def __init__(self, key=None, stream=None): self.version = self.VERSION.DEFAULT self.bounds = BoundingBox() self.flags = 0x00000000 self.routing_footprint = ExternalResource(ResourceKey()) self.entries = [] RCOL.__init__(self, key, stream)
def __init__(self, key, stream=None, rcol=None): self.version = self.VERSION.STANDARD self.bounds = BoundingBox() self.extra_bounds = [] self.fade_type = 0 self.custom_fade_distance = 0.0 self.lods = [] RCOL.__init__(self, key, stream)
def __init__(self, ftpt, stream=None): self.ftpt = ftpt self.name = None self.priority = 0 self.footprint_type_flags = 0 self.points = [] self.allow_intersection_flags = 0 self.surface_type_flags = 0 self.surface_attribute_flags = 0 self.level_offset = 0 self.elevation_offset = 0 self.bounds = BoundingBox(dimensions=2) Serializable.__init__(self, stream)
def read_rcol(self, stream, rcol): s = StreamReader(stream) self.read_tag(stream) self.version = s.u32() cLods = s.i32() self.bounds.read(stream) if self.version >= self.VERSION.EXTENDED: self.extra_bounds = [ BoundingBox(stream=stream) for i in range(s.i32()) ] self.fade_type = s.u32() self.custom_fade_distance = s.f32() self.lods = [self.LOD(stream, rcol) for i in range(cLods)]
def __init__(self, stream=None, resources=None, parent=None): self.name = None self.material = None self.vertex_format = None self.vertex_buffer = None self.index_buffer = None self.flags = self.Flags.PICKABLE self.primitive_type = self.PrimitiveType.TRIANGLE_LIST self.stream_offset = 0 self.start_vertex = 0 self.start_index = 0 self.min_vertex_index = 0 self.vertex_count = 0 self.primitive_count = 0 self.bounds = BoundingBox() self.skin_controller = None self.bone_references = [] self.scale_offsets = None self.states = [] self.parent_name = 0 self.mirror_plane_normal = [0.0, 0.0, 0.0] self.mirror_plane_offset = 0.0 ChildElement.__init__(self, parent) Serializable.__init__(self, stream, resources)
class Area(Serializable): def __init__(self, ftpt, stream=None): self.ftpt = ftpt self.name = None self.priority = 0 self.footprint_type_flags = 0 self.points = [] self.allow_intersection_flags = 0 self.surface_type_flags = 0 self.surface_attribute_flags = 0 self.level_offset = 0 self.elevation_offset = 0 self.bounds = BoundingBox(dimensions=2) Serializable.__init__(self, stream) def read(self, stream, resource=None): s = StreamReader(stream) self.name = s.u32() self.priority = s.i8() self.footprint_type_flags = s.u32() self.points = [(s.f32(), s.f32()) for i in range(s.i32())] self.allow_intersection_flags = s.u32() self.surface_type_flags = s.u32() self.surface_attribute_flags = s.u32() self.level_offset = s.i32() if self.ftpt.version >= Footprint.VERSION.EXTENDED: self.elevation_offset = s.f32() self.bounds.read(stream) def write(self, stream, resource=None): s = StreamWriter(stream) self.bounds.clear() s.hash(self.name) s.i8(self.priority) s.u32(self.footprint_type_flags) s.i32(len(self.points)) for point in self.points: self.bounds.add(point) s.f32(point[0]) s.f32(point[1]) s.u32(self.allow_intersection_flags) s.u32(self.surface_type_flags) s.u32(self.surface_attribute_flags) s.i8(self.level_offset) if self.ftpt.version >= Footprint.VERSION.EXTENDED: s.f32(self.elevation_offset) self.bounds.write(stream)
def __init__(self, stream=None, resources=None, parent=None): self.name = None self.material = None self.vertex_format = None self.vertex_buffer = None self.index_buffer = None self.flags = self.Flags.PICKABLE self.primitive_type = self.PrimitiveType.TRIANGLE_LIST self.stream_offset = 0 self.start_vertex = 0 self.start_index = 0 self.min_vertex_index = 0 self.vertex_count = 0 self.primitive_count = 0 self.bounds = BoundingBox() self.skin_controller = None self.bone_references = [] self.scale_offsets = None self.states = [] self.parent_name = 0 self.mirror_plane_normal = [0.0, 0.0, 0.0] self.mirror_plane_offset = 0.0 ChildElement.__init__(self,parent) Serializable.__init__(self, stream, resources)
class VisualProxy(RCOL): ID = 0x736884F1 TAG = 'VPXY' class VERSION: DEFAULT = 0x00000004 def __init__(self, key=None, stream=None): self.version = self.VERSION.DEFAULT self.bounds = BoundingBox() self.flags = 0x00000000 self.routing_footprint = ExternalResource(ResourceKey()) self.entries = [] RCOL.__init__(self, key, stream) def read_rcol(self, stream, rcol): self.read_tag(stream) s = StreamReader(stream) tgi = TGIList() self.version = s.u32() tgi.begin_read(stream) cEntries = s.u8() for entry_index in range(cEntries): t = s.u8() entry = self.Entry.create_instance(t) entry.read(stream, tgi) self.entries.append(entry) assert s.u8() == 0x02 self.bounds.read(stream) self.flags = s.u32() if s.u8(): self.routing_footprint = tgi.get_resource(s.u32()) tgi.end_read(stream) def write_rcol(self, stream, rcol): self.write_tag(stream) s = StreamWriter(stream) s.u32(self.version) tgi = TGIList() tgi.begin_write(stream) s.u8(len(self.entries)) for entry in self.entries: s.u8(entry.TYPE) entry.write(stream, tgi) s.u8(2) self.bounds.write(stream) s.u32(self.flags) if self.routing_footprint.key != ResourceKey(): s.u8(1) s.tgi(self.routing_footprint.key, 'TGI') else: s.u8(0) tgi.end_write(stream) class Entry(Serializable): def __init__(self, stream=None, resources=None): Serializable.__init__(self, stream, resources) @staticmethod def create_instance(type): if type == VisualProxy.MiscEntry.TYPE: return VisualProxy.MiscEntry() elif type == VisualProxy.LodEntry.TYPE: return VisualProxy.LodEntry() def read(self, stream, resources=None): pass def write(self, stream, resources=None): pass class MiscEntry(Entry): TYPE = 0x00000001 def __init__(self, stream=None, resources=None, parent=None): self.index = 0 self.resource = ExternalResource(ResourceKey()) VisualProxy.Entry.__init__(self, stream, resources) def read(self, stream, tgi=None): s = StreamReader(stream) self.index = s.u32() self.resource = tgi.get_resource(self.index) def write(self, stream, tgi=None): s = StreamWriter(stream) s.u32(self.index) s.u32(tgi.get_resource_index(self.resource)) def __str__(self): return "%s" % self.resource class LodEntry(Entry): TYPE = 0x00000000 def __init__(self, stream=None, resources=None): self.index = 0 self.resources = [] VisualProxy.Entry.__init__(self, stream, resources) def read(self, stream, resources=None): s = StreamReader(stream) self.index = s.u8() self.resources = [resources.get_resource(s.u32()) for i in range(s.u8())] def write(self, stream, resources=None): s = StreamWriter(stream) s.u8(self.index) s.u8(len(self.resources)) for resource in self.resources: s.u32(resources.get_resource_index(resource)) def __str__(self): return "%s" % self.resources
class ObjectMesh(Serializable, ChildElement, Mesh): class Flags: BASIN_INTERIOR = 0x00000001 HD_EXTERIOR_LIT = 0x00000002 PORTAL_SIDE = 0x00000004 DROP_SHADOW = 0x00000008 SHADOW_CASTER = 0x00000010 FOUNDATION = 0x00000020 PICKABLE = 0x00000040 class PrimitiveType: POINT_LIST = 0x00000000 LINE_LIST = 0x00000001 LINE_STRIP = 0x00000002 TRIANGLE_LIST = 0x00000003 TRIANGLE_FAN = 0x00000004 TRIANGLE_STRIP = 0x00000005 QUAD_LIST = 0x00000006 DISPLAY_LIST = 0x00000007 class State(Serializable): def __init__(self, stream=None): self.name = 0 self.start_index = 0 self.start_vertex = 0 self.vertex_count = 0 self.index_count = 0 Serializable.__init__(self, stream) def read(self, stream, resource=None): s = StreamReader(stream) self.name = s.u32() self.start_index = s.i32() self.start_vertex = s.i32() self.vertex_count = s.i32() self.index_count = s.i32() def write(self, stream, resource=None): s = StreamWriter(stream) s.hash(self.name) s.i32(self.start_index) s.i32(self.start_vertex) s.i32(self.vertex_count) s.i32(self.index_count) def is_dropshadow(self): return isinstance(self.material,MaterialDefinition) and int(self.material.shader_name) == 0xC09C7582 def __init__(self, stream=None, resources=None, parent=None): self.name = None self.material = None self.vertex_format = None self.vertex_buffer = None self.index_buffer = None self.flags = self.Flags.PICKABLE self.primitive_type = self.PrimitiveType.TRIANGLE_LIST self.stream_offset = 0 self.start_vertex = 0 self.start_index = 0 self.min_vertex_index = 0 self.vertex_count = 0 self.primitive_count = 0 self.bounds = BoundingBox() self.skin_controller = None self.bone_references = [] self.scale_offsets = None self.states = [] self.parent_name = 0 self.mirror_plane_normal = [0.0, 0.0, 0.0] self.mirror_plane_offset = 0.0 ChildElement.__init__(self,parent) Serializable.__init__(self, stream, resources) def get_vertex_format(self): return self.vertex_format if self.vertex_format != None else VertexFormat.default_sunshadow() if Flag.is_set(self.flags,self.Flags.SHADOW_CASTER) else VertexFormat.default_drop_shadow() def read(self, stream, rcol): s = StreamReader(stream) data_len = s.u32() end = stream.tell() + data_len self.name = s.u32() self.material = rcol.get_block(s.u32(), (MaterialDefinition, MaterialSet)) self.vertex_format = rcol.get_block(s.u32(), VertexFormat) self.vertex_buffer = rcol.get_block(s.u32(), (VertexBuffer, VertexBufferShadow)) self.index_buffer = rcol.get_block(s.u32(), (IndexBuffer, IndexBufferShadow)) flags = s.u32() self.flags = flags >> 8 self.primitive_type = flags & 0x000000FF self.stream_offset = s.u32() self.start_vertex = s.i32() self.start_index = s.i32() self.min_vertex_index = s.i32() self.vertex_count = s.i32() self.primitive_count = s.i32() self.bounds.read(stream) self.skin_controller = rcol.get_block(s.u32(), ObjectSkinController) self.bone_references = [s.u32() for i in range(s.i32())] self.scale_offsets = rcol.get_block(s.u32(), MaterialDefinition) self.states = [self.State(stream) for i in range(s.i32())] if self.parent.version > ModelLod.VERSION.DEFAULT: self.parent_name = s.u32() self.mirror_plane_normal = [s.f32() for i in range(3)] self.mirror_plane_offset = s.f32() if not stream.tell() == end: raise Exception( "Invalid MLOD.Mesh data length: expected 0x%X, but got 0x%08X" % (end, stream.tell())) def write(self, stream, rcol): s = StreamWriter(stream) len_offset = stream.tell() s.u32(0) start = stream.tell() s.hash(self.name) s.u32(rcol.get_block_index(self.material)) s.u32(rcol.get_block_index(self.vertex_format)) s.u32(rcol.get_block_index(self.vertex_buffer)) s.u32(rcol.get_block_index(self.index_buffer)) flags = self.primitive_type flags |= (self.flags << 8) s.u32(flags) s.u32(self.stream_offset) s.i32(self.start_vertex) s.i32(self.start_index) s.i32(self.min_vertex_index) s.i32(self.vertex_count) s.i32(self.primitive_count) self.bounds.write(stream) s.u32(rcol.get_block_index(self.skin_controller)) s.i32(len(self.bone_references)) for bone in self.bone_references: s.u32(bone) s.u32(rcol.get_block_index(self.scale_offsets)) s.i32(len(self.states)) for state in self.states: state.write_rcol(self, rcol) if self.parent.version > ModelLod.VERSION.DEFAULT: s.hash(self.parent_name) for i in range(3): s.f32(self.mirror_plane_normal[i]) s.f32(self.mirror_plane_offset) end = stream.tell() stream.seek(len_offset, SEEK_SET) s.u32(end - start) stream.seek(end, SEEK_SET) def get_uv_scales(self): uvscales = [1/0x7FFF] * 3 key = 'uvscales' material = self.material if material == None: return None while not isinstance(material, MaterialDefinition): if isinstance(material, MaterialSet): material = material.default_material.material else: raise Exception("Expected a MaterialDefinition or MaterialSet") if key in material.material_block: uvscales = material.material_block[key] return uvscales def get_vertices(self): uvscales = self.get_uv_scales() vrtf = self.get_vertex_format() verts = self.vertex_buffer.buffer.read_vertices(self.stream_offset, vrtf, self.vertex_count, uvscales) return verts def get_triangles(self): primitive_size = 0 if self.primitive_type == self.PrimitiveType.TRIANGLE_LIST: primitive_size = 3 else: raise NotImplementedError() return [[self.index_buffer.buffer[self.start_index + (primitive_index * primitive_size) + i] for i in range(primitive_size)] for primitive_index in range(self.primitive_count)]
class Model(RCOL): TAG = 'MODL' ID = 0x01661233 class VERSION(): STANDARD = 0x00000100 EXTENDED = 0x00000102 class LOD(Serializable): class FLAGS: NONE = 0x00000000 PORTAL = 0x00000001 DOOR = 0x00000002 def __init__(self, stream=None, rcol=None): self.model = None self.flags = Model.LOD.FLAGS.NONE self.id = LOD_ID.MEDIUM_DETAIL self.min_z = 0.0 self.max_z = 0.0 Serializable.__init__(self, stream, rcol) def read(self, stream, resources): s = StreamReader(stream) self.model = resources.get_block(s.u32(), ModelLod) self.flags = s.u32() self.id = s.u16() self.is_sunshadow = bool(s.u16()) self.min_z = s.f32() self.max_z = s.f32() def write(self, stream, resources): s = StreamWriter(stream) s.u32(resources.get_block_index(self.model, RCOL.Reference.PUBLIC)) s.u32(self.flags) s.u16(self.id) s.u16(int(self.is_sunshadow)) s.f32(self.min_z) s.f32(self.max_z) def __init__(self, key, stream=None, rcol=None): self.version = self.VERSION.STANDARD self.bounds = BoundingBox() self.extra_bounds = [] self.fade_type = 0 self.custom_fade_distance = 0.0 self.lods = [] RCOL.__init__(self, key, stream) def read_rcol(self, stream, rcol): s = StreamReader(stream) self.read_tag(stream) self.version = s.u32() cLods = s.i32() self.bounds.read(stream) if self.version >= self.VERSION.EXTENDED: self.extra_bounds = [BoundingBox(stream=stream) for i in range(s.i32())] self.fade_type = s.u32() self.custom_fade_distance = s.f32() self.lods = [self.LOD(stream, rcol) for i in range(cLods)] def write_rcol(self, stream, rcol): s = StreamWriter(stream) self.write_tag(stream) s.u32(self.version) s.i32(len(self.lods)) self.bounds.write(stream) if self.version >= self.VERSION.EXTENDED: s.i32(len(self.extra_bounds)) for extra in self.extra_bounds: extra.write(stream) s.u32(self.fade_type) s.f32(self.custom_fade_distance) for lod in self.lods: lod.write_rcol(stream, rcol)
class Model(RCOL): TAG = 'MODL' ID = 0x01661233 class VERSION(): STANDARD = 0x00000100 EXTENDED = 0x00000102 class LOD(Serializable): class FLAGS: NONE = 0x00000000 PORTAL = 0x00000001 DOOR = 0x00000002 def __init__(self, stream=None, rcol=None): self.model = None self.flags = Model.LOD.FLAGS.NONE self.id = LOD_ID.MEDIUM_DETAIL self.min_z = 0.0 self.max_z = 0.0 Serializable.__init__(self, stream, rcol) def read(self, stream, resources): s = StreamReader(stream) self.model = resources.get_block(s.u32(), ModelLod) self.flags = s.u32() self.id = s.u16() self.is_sunshadow = bool(s.u16()) self.min_z = s.f32() self.max_z = s.f32() def write(self, stream, resources): s = StreamWriter(stream) s.u32(resources.get_block_index(self.model, RCOL.Reference.PUBLIC)) s.u32(self.flags) s.u16(self.id) s.u16(int(self.is_sunshadow)) s.f32(self.min_z) s.f32(self.max_z) def __init__(self, key, stream=None, rcol=None): self.version = self.VERSION.STANDARD self.bounds = BoundingBox() self.extra_bounds = [] self.fade_type = 0 self.custom_fade_distance = 0.0 self.lods = [] RCOL.__init__(self, key, stream) def read_rcol(self, stream, rcol): s = StreamReader(stream) self.read_tag(stream) self.version = s.u32() cLods = s.i32() self.bounds.read(stream) if self.version >= self.VERSION.EXTENDED: self.extra_bounds = [ BoundingBox(stream=stream) for i in range(s.i32()) ] self.fade_type = s.u32() self.custom_fade_distance = s.f32() self.lods = [self.LOD(stream, rcol) for i in range(cLods)] def write_rcol(self, stream, rcol): s = StreamWriter(stream) self.write_tag(stream) s.u32(self.version) s.i32(len(self.lods)) self.bounds.write(stream) if self.version >= self.VERSION.EXTENDED: s.i32(len(self.extra_bounds)) for extra in self.extra_bounds: extra.write(stream) s.u32(self.fade_type) s.f32(self.custom_fade_distance) for lod in self.lods: lod.write_rcol(stream, rcol)
class VisualProxy(RCOL): ID = 0x736884F1 TAG = 'VPXY' class VERSION: DEFAULT = 0x00000004 def __init__(self, key=None, stream=None): self.version = self.VERSION.DEFAULT self.bounds = BoundingBox() self.flags = 0x00000000 self.routing_footprint = ExternalResource(ResourceKey()) self.entries = [] RCOL.__init__(self, key, stream) def read_rcol(self, stream, rcol): self.read_tag(stream) s = StreamReader(stream) tgi = TGIList() self.version = s.u32() tgi.begin_read(stream) cEntries = s.u8() for entry_index in range(cEntries): type = s.u8() entry = self.Entry.create_instance(type) entry.read(stream, tgi) self.entries.append(entry) assert s.u8() == 0x02 self.bounds.read(stream) self.flags = s.u32() if s.u8(): self.routing_footprint = tgi.get_resource(s.u32()) tgi.end_read(stream) def write_rcol(self, stream, rcol): self.write_tag(stream) s = StreamWriter(stream) s.u32(self.version) tgi = TGIList() tgi.begin_write(stream) s.u8(len(self.entries)) for entry in self.entries: s.u8(entry.TYPE) entry.write(stream, tgi) s.u8(2) self.bounds.write(stream) s.u32(self.flags) if self.routing_footprint.key != ResourceKey(): s.u8(1) s.tgi(self.routing_footprint.key, 'TGI') else: s.u8(0) tgi.end_write(stream) class Entry(Serializable): def __init__(self, stream=None, resources=None): Serializable.__init__(self, stream, resources) @staticmethod def create_instance(type): if type == VisualProxy.MiscEntry.TYPE: return VisualProxy.MiscEntry() elif type == VisualProxy.LodEntry.TYPE: return VisualProxy.LodEntry() class MiscEntry(Entry): TYPE = 0x00000001 def __init__(self, stream=None, resources=None, parent=None): self.index = 0 self.resource = ExternalResource(ResourceKey()) VisualProxy.Entry.__init__(self, stream, resources) def read(self, stream, tgi): s = StreamReader(stream) self.index = s.u32() self.resource = tgi.get_resource(self.index) def write(self, stream, tgi): s = StreamWriter(stream) s.u32(self.index) s.u32(tgi.get_resource_index(self.resource)) def __str__(self): return "%s" % self.resource class LodEntry(Entry): TYPE = 0x00000000 def __init__(self, stream=None, resources=None): self.index = 0 self.resources = [] VisualProxy.Entry.__init__(self, stream, resources) def read(self, stream, resources): s = StreamReader(stream) self.index = s.u8() self.resources = [resources.get_resource(s.u32()) for i in range(s.u8())] def write(self, stream, resources): s = StreamWriter(stream) s.u8(self.index) s.u8(len(self.resources)) for resource in self.resources: s.u32(resources.get_resource_index(resource)) def __str__(self): return "%s" % self.resources
class ObjectMesh(Serializable, ChildElement, Mesh): class Flags: BASIN_INTERIOR = 0x00000001 HD_EXTERIOR_LIT = 0x00000002 PORTAL_SIDE = 0x00000004 DROP_SHADOW = 0x00000008 SHADOW_CASTER = 0x00000010 FOUNDATION = 0x00000020 PICKABLE = 0x00000040 class PrimitiveType: POINT_LIST = 0x00000000 LINE_LIST = 0x00000001 LINE_STRIP = 0x00000002 TRIANGLE_LIST = 0x00000003 TRIANGLE_FAN = 0x00000004 TRIANGLE_STRIP = 0x00000005 QUAD_LIST = 0x00000006 DISPLAY_LIST = 0x00000007 class State(Serializable): def __init__(self, stream=None): self.name = 0 self.start_index = 0 self.start_vertex = 0 self.vertex_count = 0 self.index_count = 0 Serializable.__init__(self, stream) def read(self, stream, resource=None): s = StreamReader(stream) self.name = s.u32() self.start_index = s.i32() self.start_vertex = s.i32() self.vertex_count = s.i32() self.index_count = s.i32() def write(self, stream, resource=None): s = StreamWriter(stream) s.hash(self.name) s.i32(self.start_index) s.i32(self.start_vertex) s.i32(self.vertex_count) s.i32(self.index_count) def is_dropshadow(self): return isinstance(self.material, MaterialDefinition) and int( self.material.shader_name) == 0xC09C7582 def __init__(self, stream=None, resources=None, parent=None): self.name = None self.material = None self.vertex_format = None self.vertex_buffer = None self.index_buffer = None self.flags = self.Flags.PICKABLE self.primitive_type = self.PrimitiveType.TRIANGLE_LIST self.stream_offset = 0 self.start_vertex = 0 self.start_index = 0 self.min_vertex_index = 0 self.vertex_count = 0 self.primitive_count = 0 self.bounds = BoundingBox() self.skin_controller = None self.bone_references = [] self.scale_offsets = None self.states = [] self.parent_name = 0 self.mirror_plane_normal = [0.0, 0.0, 0.0] self.mirror_plane_offset = 0.0 ChildElement.__init__(self, parent) Serializable.__init__(self, stream, resources) def get_vertex_format(self): return self.vertex_format if self.vertex_format != None else VertexFormat.default_sunshadow( ) if Flag.is_set(self.flags, self.Flags.SHADOW_CASTER ) else VertexFormat.default_drop_shadow() def read(self, stream, rcol): s = StreamReader(stream) data_len = s.u32() end = stream.tell() + data_len self.name = s.u32() self.material = rcol.get_block(s.u32(), (MaterialDefinition, MaterialSet)) self.vertex_format = rcol.get_block(s.u32(), VertexFormat) self.vertex_buffer = rcol.get_block(s.u32(), (VertexBuffer, VertexBufferShadow)) self.index_buffer = rcol.get_block(s.u32(), (IndexBuffer, IndexBufferShadow)) flags = s.u32() self.flags = flags >> 8 self.primitive_type = flags & 0x000000FF self.stream_offset = s.u32() self.start_vertex = s.i32() self.start_index = s.i32() self.min_vertex_index = s.i32() self.vertex_count = s.i32() self.primitive_count = s.i32() self.bounds.read(stream) self.skin_controller = rcol.get_block(s.u32(), ObjectSkinController) self.bone_references = [s.u32() for i in range(s.i32())] self.scale_offsets = rcol.get_block(s.u32(), MaterialDefinition) self.states = [self.State(stream) for i in range(s.i32())] if self.parent.version > ModelLod.VERSION.DEFAULT: self.parent_name = s.u32() self.mirror_plane_normal = [s.f32() for i in range(3)] self.mirror_plane_offset = s.f32() if not stream.tell() == end: raise Exception( "Invalid MLOD.Mesh data length: expected 0x%X, but got 0x%08X" % (end, stream.tell())) def write(self, stream, rcol): s = StreamWriter(stream) len_offset = stream.tell() s.u32(0) start = stream.tell() s.hash(self.name) s.u32(rcol.get_block_index(self.material)) s.u32(rcol.get_block_index(self.vertex_format)) s.u32(rcol.get_block_index(self.vertex_buffer)) s.u32(rcol.get_block_index(self.index_buffer)) flags = self.primitive_type flags |= (self.flags << 8) s.u32(flags) s.u32(self.stream_offset) s.i32(self.start_vertex) s.i32(self.start_index) s.i32(self.min_vertex_index) s.i32(self.vertex_count) s.i32(self.primitive_count) self.bounds.write(stream) s.u32(rcol.get_block_index(self.skin_controller)) s.i32(len(self.bone_references)) for bone in self.bone_references: s.u32(bone) s.u32(rcol.get_block_index(self.scale_offsets)) s.i32(len(self.states)) for state in self.states: state.write_rcol(self, rcol) if self.parent.version > ModelLod.VERSION.DEFAULT: s.hash(self.parent_name) for i in range(3): s.f32(self.mirror_plane_normal[i]) s.f32(self.mirror_plane_offset) end = stream.tell() stream.seek(len_offset, SEEK_SET) s.u32(end - start) stream.seek(end, SEEK_SET) def get_uv_scales(self): uvscales = [1 / 0x7FFF] * 3 key = 'uvscales' material = self.material if material == None: return None while not isinstance(material, MaterialDefinition): if isinstance(material, MaterialSet): material = material.default_material.material else: raise Exception("Expected a MaterialDefinition or MaterialSet") if key in material.material_block: uvscales = material.material_block[key] return uvscales def get_vertices(self): uvscales = self.get_uv_scales() vrtf = self.get_vertex_format() verts = self.vertex_buffer.buffer.read_vertices( self.stream_offset, vrtf, self.vertex_count, uvscales) return verts def get_triangles(self): primitive_size = 0 if self.primitive_type == self.PrimitiveType.TRIANGLE_LIST: primitive_size = 3 else: raise NotImplementedError() return [[ self.index_buffer.buffer[self.start_index + (primitive_index * primitive_size) + i] for i in range(primitive_size) ] for primitive_index in range(self.primitive_count)]