add BlendStruct

The BlendStruct class handles the representation of a blender structure, which may be loaded or unloaded, and which may contain nested blend structs. This allows for loading specific structures in the tree to save memory.
This commit is contained in:
Josiah 2021-07-24 11:03:44 -05:00
parent a1d8ba6b8e
commit 6739b9d471
No known key found for this signature in database
GPG Key ID: C7BB8573A4ABC4B9
2 changed files with 72 additions and 6 deletions

View File

@ -2,6 +2,48 @@
import io import io
class BlendStruct:
"""
Read-only dict-like datatype representing a structure in a .blend file.
"""
def __init__(self, load_cb, type):
"""
Initialize the BlendStruct.
:param load_cb: A callback to load the structure.
:param type: The type of the structure.
"""
self._load_cb = load_cb
self._type = type
self._structure = None
def load(self):
"""
Force the structure to be loaded.
:return The loaded blend struct (self)
"""
if self._structure is None:
self._structure = self._load_cb()
return self
def __str__(self):
if self._structure is None:
return f"<Blender Structure {self._type} (unloaded)>"
else:
return str(self._structure)
def __getitem__(self, item):
if self._structure is None:
self._structure = self._load_cb()
return self._structure[item]
def __iter__(self):
if self._structure is None:
self._structure = self._load_cb()
return self._structure
# A class for opening and reading data from .blend files # A class for opening and reading data from .blend files
class Blendfile(io.FileIO): class Blendfile(io.FileIO):
def __init__(self, filename): def __init__(self, filename):
@ -135,12 +177,15 @@ class Blendfile(io.FileIO):
return sdna return sdna
def _load_struct(self, struct_name): def _load_struct(self, struct_name, offset):
""" """
Load a struct according to the SDNA. Load a struct according to the SDNA.
:param struct_name: The name of the structure type.
:param offset: The byte offset at which to begin loading.
:return The loaded structure.
""" """
fields = self._sdna["structs"][struct_name] fields = self._sdna["structs"][struct_name]
print(fields)
return {} return {}
def read_header(self): def read_header(self):
@ -198,9 +243,13 @@ class Blendfile(io.FileIO):
sdna_index = int.from_bytes(self.read(4), self.endianness) sdna_index = int.from_bytes(self.read(4), self.endianness)
count = int.from_bytes(self.read(4), self.endianness) count = int.from_bytes(self.read(4), self.endianness)
struct_name = list(self._sdna["structs"])[sdna_index] # Helper for creating a callback to load a given structure.
def create_loader(name, at_offset):
def load_struct():
return self._load_struct(name, at_offset)
return load_struct
# TODO load structs according to SDNA. # The type of the structure.
name = list(self._sdna["structs"])[sdna_index]
for _ in range(count): for _ in range(count):
translated = self._load_struct(struct_name) yield BlendStruct(create_loader(name, self.tell()), name)
yield translated

17
test.py Executable file
View File

@ -0,0 +1,17 @@
#!/usr/bin/env python3
import blendparse
import sys
try:
blendfile = sys.argv[1]
except IndexError:
print("Usage: ./test.py <path to .blend>")
sys.exit()
with blendparse.Blendfile(blendfile) as blend:
results = [block() for block in blend.get_blocks("SC").values()]
for structure in results[0]:
print(structure)
print(structure.load())