Skip to content

Instantly share code, notes, and snippets.

@rdb
Last active June 6, 2023 18:09
Show Gist options
  • Select an option

  • Save rdb/81853af7538ebf9ba6a8281ab9a0435b to your computer and use it in GitHub Desktop.

Select an option

Save rdb/81853af7538ebf9ba6a8281ab9a0435b to your computer and use it in GitHub Desktop.
This gist demonstrates how to use the new .bam reading hooks to define custom types in Python or define a loader hook for existing types. Requires Panda 1.10.
"""
This example shows how to use the new Python factory function in the BamReader
in order to add a custom hook that is called when the BamReader encounters an
object of a certain type.
You can also use this to add a custom hook whenever the bam reader loads an
existing type, for example if you want to do some post-process task on every
GeomNode or Material loaded from the .bam file.
"""
from panda3d.core import BamReader, TypeRegistry, PandaNode, NodePath
registry = TypeRegistry.ptr()
# This shows how to register a custom factory function for any type that the
# Panda type system knows about. In this case, it's an existing type,
# PandaNode.
# The callback does nothing interesting but print a message and add something
# to the name.
def node_factory(scan, reader):
print("Reading PandaNode from .bam file with version %d.%d" % (reader.file_version))
node = PandaNode("")
node.fillin(scan, reader)
node.name += " (MODIFIED)"
#NB. Note that at this time, all the pointer values (eg. node.state,
# node.get_children(), etc.) have not been filled in yet!
return node
# Register our custom hook function, overriding the existing PandaNode loader.
BamReader.register_factory(PandaNode, node_factory)
# Now follows a more complete example that uses a custom type that inherits
# from PandaNode. Creating a class and providing these methods isn't
# necessary, as the above example shows, but this follows the Panda paradigms.
class CustomNode(PandaNode):
def fillin(self, scan, reader):
PandaNode.fillin(self, scan, reader)
# Also read out a custom field that this class adds.
self.custom_field = scan.get_uint8()
# Here's how to read a field that depends on the .bam version.
if reader.file_version >= (6, 42):
self.new_field = scan.get_uint8()
else:
self.new_field = None
@staticmethod
def make_from_bam(scan, reader):
"""Factory function that is called when the .bam reader encounters an
object of type CustomNode."""
node = CustomNode("")
node.fillin(scan, reader)
return node
# Register our custom type with Panda's type system, telling Panda that the
# class inherits from PandaNode.
class_type = registry.register_dynamic_type("CustomNode")
registry.record_derivation(class_type, PandaNode.get_class_type())
# Register the factory function with the BamReader.
BamReader.register_factory(class_type, CustomNode.make_from_bam)
# Test loading a file.
from panda3d.core import ModelPool
node = ModelPool.load_model("test.bam")
NodePath(node).ls()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment