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.
2 changed files with 68 additions and 36 deletions
Showing only changes of commit cc70b13113 - Show all commits

View File

@ -166,6 +166,7 @@ class BlendFile:
break
if block.code == b"DNA1":
# for i in range(block.count):
self.decode_structs(block)
else:
self.fileobj.seek(block.size, os.SEEK_CUR)
@ -350,25 +351,10 @@ 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
# 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."""
@ -486,6 +472,12 @@ class BlendFileBlock:
self.addr_old = blockheader[2]
self.sdna_index = blockheader[3]
self.count = blockheader[4]
# if self.count > 1:
# self.size = self.size // self.count
# if self.count > 1:
# print(self.count)
# print("size is 144")
self.file_offset = bfile.fileobj.tell()
def __repr__(self) -> str:
@ -774,6 +766,35 @@ class BlendFileBlock:
continue
yield dereferenced
def iter_array_from_pointer(
self, path: dna.FieldPath, array_size: int
) -> typing.Iterator["BlendFileBlock"]:
"""Dereference pointers from an array field.
:param path: The array-of-pointers field.
:param array_size: Number of items in the array. If None, the
on-disk size of the DNA field is divided by the pointer size to
obtain the array size.
"""
if array_size == 0:
return
array = self.get_pointer(path)
array_ptr = self.get(path)
assert array_ptr is not None
item_size = array.size // array_size
for i in range(array_size):
print(i)
address = array_ptr + (item_size * i)
print(address)
if address == 0:
continue
dereferenced = self.bfile.dereference_pointer(address)
yield dereferenced
def iter_fixed_array_of_pointers(
self, path: dna.FieldPath
) -> typing.Iterator["BlendFileBlock"]:

View File

@ -27,7 +27,7 @@ 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.blendfile.dna import Struct, Field, Name
from blender_asset_tracer import blendfile, bpathlib, cdefs
from . import result
@ -325,13 +325,18 @@ def modifier_cloth(
)
def split_bytes_array(raw_data: bytes, item_size: int) -> typing.Iterator[bytes]:
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):
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 = {}
@ -340,9 +345,16 @@ def bytes_to_struct(data_bytes: bytes, struct_type: Struct):
end = start + field.size
field_data = data_bytes[start:end]
value = field_data.hex()
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
struct_instance[field.name.name_only] = value
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
@ -352,22 +364,21 @@ 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")
bake_directory = bake_directory.as_string()
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)
bakes_split = split_bytes_array(bakes)
for bake_bytes in bakes_split:
bake_struct = bytes_to_struct(bake_bytes, dna_type)
print(bake_struct)
bake_struct = bytes_to_struct(bake_bytes, dna_type, modifier)
JonasDichelle marked this conversation as resolved

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:

use_custom_path = bool(flag & cdefs.NODES_MODIFIER_BAKE_CUSTOM_PATH)
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) ```
if bake_struct["use_custom_directory"] == "1":
directory = bake_struct["directory"]
else:
directory = bake_directory
# yield bake_struct
print(directory)
quit()
# yield from _walk_point_cache(
# ctx, block_name, modifier.bfile, pointcache, cdefs.PTCACHE_EXT
# )