def read(self, stream, resources=None): s = StreamReader(stream) self.version = s.u32() tgi = TGIList(package=resources) tgi.begin_read(stream) if self.version >= 0x00000007: self.presets = ProductBase.read_presets(stream,tgi) self.product_info = ProductInfo() self.product_info.read(stream,tgi) self.model = tgi.get_resource(s.i32()) self.diagonal_model = tgi.get_resource(s.i32()) self.post_model = tgi.get_resource(s.i32()) self.post_tile_spacing = s.i32() self.can_walk_over = s.i8() == 1 if self.version >= 0x00000008: if self.version >= 0x000000A: self.should_not_get_thick_snow = s.i8() == 1 self.snow_post_shape_is_circle = s.i8()==1 self.snow_thickness_post_scale_factor = s.f32() self.snow_thickness_rail_scale_factor = s.f32() self.snow_thickness_post_vertical_offset = s.f32() self.snow_thickness_rail_vertical_offset = s.f32() self.has_wall = s.i8() == 1 if self.version < 0x000000A or self.has_wall: self.raise_fence_geometry_above_wall = s.i8()== 1 self.wall = tgi.get_resource(s.i32()) tgi.end_read(stream)
def read(self, stream, resources=None): s = StreamReader(stream) s.version = s.u32() tgi = TGIList(package=resources) tgi.begin_read(stream) self.components = [s.hash(self.component_hashes) for i in range(s.i8())] self.component_data = {} def read_component_data(): key = s.p32() val = None t = s.i8() if t == 0x00: val = t, s.p32() elif t == 0x01: val = t, tgi.get_resource(s.i32()) elif t == 0x02: val = t, tgi.get_resource(s.i32()) elif t == 0x03: val = t, s.p32() elif t == 0x04: val = t, s.u32() self.component_data[key] = val for i in range(s.i8()): read_component_data() self.visible = s.u8() tgi.end_read(stream) pass
def read(self, stream, resources=None): s = StreamReader(stream) self.version = s.u32() use_tgi = not isinstance(resources, TGIList) tgi = resources if use_tgi: tgi = TGIList(order='IGT', use_length=False, package=resources, count_size=8) tgi.begin_read(stream) if self.version >= 7: cFabrics = s.i8() for fabric_index in range(cFabrics): key = tgi.get_resource(s.u8()) fabric = TextureCompositor(key) fabric_len = s.u32() with BytesIO() as fabric_stream: fabric_stream.write(stream.read(fabric_len)) fabric_stream.seek(0, SEEK_SET) fabric.read(fabric_stream, tgi) self.fabrics.append(fabric) self.target_size = s.u32() self.part_type = s.u32() assert s.u8() == 0 cSteps = s.i32() if self.version >= 0x08: assert s.u8() == 0 self.steps = [] for step_index in range(cSteps): self.steps.append(self.read_step(stream, tgi)) if use_tgi: tgi.end_read(stream) else: assert s.u32() == 0
def read_property(self, stream, hash, tgi): s = StreamReader(stream) id = s.u32() value = None if not id: return False if not s.u8(): t = s.u8() if t == 0x00: value = bool(s.u8()) elif t == 0x01: value = s.i8() elif t == 0x02: value = s.i16() elif t == 0x03: value = s.i32() elif t == 0x04: value = s.i64() elif t == 0x05: value = s.u8() elif t == 0x06: value = s.u16() elif t == 0x07: value = s.u32() elif t == 0x08: value = s.u64() elif t == 0x09: value = s.f32() elif t == 0x0A: value = [s.f32() for i in range(4)] elif t == 0x0B: value = [s.f32() for i in range(4)] elif t == 0x0C: value = tgi.get_resource(s.u8()) elif t == 0x0D: value = s.p16() else: raise Exception("Unknown TXTC parameter type %s" % t) hash[id] = value return True
def read_rcol(self, stream, rcol): s = StreamReader(stream) self.read_tag(stream) self.version = s.u32() tgi = TGIList() tgi.begin_read(stream) self.shader = s.u32() if self.shader: end_material = s.u32() + stream.tell() self.material = MaterialBlock() self.material.read(stream, tgi) assert stream.tell() == end_material self.merge_group = s.u32() self.sort_order = s.u32() cVertices = s.u32() self.vertex_format.read(stream) for vertex_index in range(cVertices): vertex = Vertex() for declaration in self.vertex_format.declarations: if declaration.usage == self.VertexFormat.Declaration.USAGE.POSITION: vertex.position = [s.f32(), s.f32(), s.f32()] elif declaration.usage == self.VertexFormat.Declaration.USAGE.NORMAL: vertex.normal = [s.f32(), s.f32(), s.f32()] elif declaration.usage == self.VertexFormat.Declaration.USAGE.UV: uv = [s.f32(), s.f32()] if vertex.uv == None: vertex.uv = [] vertex.uv.append(uv) elif declaration.usage == self.VertexFormat.Declaration.USAGE.BLEND_INDEX: vertex.blend_indices = [s.i8(), s.i8(), s.i8(), s.i8()] elif declaration.usage == self.VertexFormat.Declaration.USAGE.BLEND_WEIGHT: vertex.blend_weights = [s.f32(), s.f32(), s.f32(), s.f32()] elif declaration.usage == self.VertexFormat.Declaration.USAGE.TANGENT: vertex.tangent = [s.f32(), s.f32(), s.f32()] elif declaration.usage == self.VertexFormat.Declaration.USAGE.COLOUR: vertex.colour = [s.u8(), s.u8(), s.u8(), s.u8()] elif declaration.usage == self.VertexFormat.Declaration.USAGE.ID: vertex.id = s.u32() self.vertices.append(vertex) assert s.u32() == 1 bytes_per_index = s.u8() assert bytes_per_index == 2 self.indices = [[s.u16() for i in range(3)] for i in range(int(s.u32() / 3))] self.skin_controller = tgi.get_resource(s.u32()) self.bones = [s.u32() for i in range(s.u32())] tgi.end_read(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 read(self, stream, resources=None): s = StreamReader(stream) self.version = s.u32() self.name_guid = s.u64() self.desc_guid = s.u64() self.name_key = s.s7() self.desc_key = s.s7() self.price = s.f32() self.niceness_multiplier = s.f32() self.crap_score = s.f32() self.status_flags = s.u8() self.icon = s.u64() self.environment_score = s.f32() self.fire_type = s.u32() self.is_stealable = bool(s.i8()) self.is_reposessable = bool(s.i8()) self.ui_sort_index = s.u32() if self.version >= 0x0000000D: self.is_placeable_on_roof = bool(s.u8()) if self.version >= 0x0000000E: self.is_visible_in_worldbuilder = bool(s.u8()) if self.version >= 0x0000000F: self.product_name = s.u32()
def read(self, stream, resources=None): s = StreamReader(stream) self.version = s.u32() self.name_guid = s.u64() self.desc_guid = s.u64() self.name_key = s.s7(size=16,order='>') self.desc_key = s.s7(size=16,order='>') self.price = s.f32() self.niceness_multiplier = s.f32() self.crap_score = s.f32() self.status_flags = s.u8() self.icon = s.u64() assert s.u8() == 0 self.environment_score = s.f32() self.fire_type = s.u32() self.is_stealable = bool(s.i8()) self.is_reposessable = bool(s.i8()) self.ui_sort_index = s.u32() if self.version >= 0x0000000D: self.is_placeable_on_roof = bool(s.u8()) if self.version >= 0x0000000E: self.is_visible_in_worldbuilder = bool(s.u8()) if self.version >= 0x0000000F: self.product_name = s.u32()
def read(self, stream, resources=None): s = StreamReader(stream) s.seek(12, io.SEEK_SET) c = s.i32() ce = ComplateEncoder() for i in range(c): if not s.i8() == 1: s.i32() preset_len = s.u32() expected_end = s.tell() + preset_len preset = self.BuildBuyPreset() preset.complate = ce.deserialize(stream, resources) assert s.tell() == expected_end preset.id = s.u32() self.presets.append(preset)
def fix_read_offset(self, stream): s = StreamReader(stream) pos = stream.tell() fix_bytes = 0 if pos % 2 == 0: fix_bytes = pos % 4 else: fix_bytes = pos % 2 if (pos + fix_bytes) % 2 == 0: fix_bytes += 2 assert fix_bytes <= 3 for i in range(fix_bytes): b = s.i8() assert b == i
def read_presets(cls,stream,resources=None): s = StreamReader(stream) c = s.i32() ce = ComplateEncoder() presets = [] for i in range(c): preset = cls.BuildBuyPreset() preset.unk1 = s.i8() if preset.unk1 != 1: preset.unk2 = s.i32() preset_ptr = StreamPtr.begin_read(s,relative=True,offset_start=True) preset.complate = ce.deserialize(stream,resources) preset_ptr.end() preset.id = s.u32() presets.append(preset) return presets
def read(self, stream, resources=None): s = StreamReader(stream) self.version = s.u32() tgi = TGIList(package=resources) tgi.begin_read(stream) self.product_info = ProductInfo() self.product_info.read(stream,tgi) self.fireplace_width = s.i8() self.mantle = tgi.get_resource(s.i32()) self.chimney_mantle = tgi.get_resource(s.i32()) self.chimney_full_level = tgi.get_resource(s.i32()) self.chimney_ground_level = tgi.get_resource(s.i32()) self.chimney_body = tgi.get_resource(s.i32()) self.chimney_top = tgi.get_resource(s.i32()) self.chimney_cap = tgi.get_resource(s.i32()) tgi.end_read(stream)
def read_rcol(self, stream, rcol): s = StreamReader(stream) self.read_tag(stream) self.version = s.u32() self.footprint_polygons = [self.Area(stream) for i in range(s.i8())] self.routing_slot_footprint_polygons = [self.Area(stream) for i in range(s.i8())]
def read(self, stream, resource=None): s = StreamReader(stream) self.version = s.u32() tgi = TGIList(order='igt', count_size=8, package=resource, use_length=False) tgi.begin_read(stream) self.presets = [self.CasPreset(stream, tgi) for i in range(s.u32())] self.part_name = s.s7(16, '>') self.display_index = s.f32() self.has_unique_texture_space = s.u8() self.body_type = s.u32() self.part_flags = s.u32() self.age_gender_flags = s.u32() self.clothing_category = s.u32() self.naked_cas_part = tgi.get_resource(s.i8()) self.base_cas_part = tgi.get_resource(s.i8()) self.blend_fat = tgi.get_resource(s.i8()) self.blend_fit = tgi.get_resource(s.i8()) self.blend_thin = tgi.get_resource(s.i8()) self.blend_special = tgi.get_resource(s.i8()) self.draw_layer = s.u32() self.sources = [tgi.get_resource(s.i8()) for i in range(s.u8())] self.lod_infos = [CASLodInfo(stream) for i in range(s.u8())] self.diffuse_refs = [tgi.get_resource(s.i8()) for i in range(s.u8())] self.specular_refs = [tgi.get_resource(s.i8()) for i in range(s.u8())] self.secondary_diffuse_refs = [tgi.get_resource(s.i8()) for i in range(s.u8())] self.secondary_specular_refs = [tgi.get_resource(s.i8()) for i in range(s.u8())] self.slot_poses = [tgi.get_resource(s.i8()) for i in range(s.u8())] self.shoe_material = s.s7(16, '>') tgi.end_read(stream)
def read(self, stream, resource=None): s = StreamReader(stream) self.level = s.u8() self.dest_texture = s.u32() self.assets = [self.Asset(stream) for i in range(s.i8())]
class Buffer: def __init__(self): self.stream = BytesIO() self.reader = StreamReader(self.stream) self.writer = StreamWriter(self.stream) def delete_vertices(self, offset, vrtf, count): end_offset = offset + vrtf.stride * count self.stream.seek(end_offset, SEEK_SET) end_data = self.stream.read(-1) self.stream.seek(offset, SEEK_SET) self.stream.truncate() self.stream.writable(end_data) def read_vertices(self, offset, vrtf, count,uvscales): self.stream.seek(offset, SEEK_SET) return [self.read_vertex(vrtf,uvscales) for i in range(count)] def read_vertex(self, vrtf, uvscales): vertex = Vertex() start = self.stream.tell() end = start + vrtf.stride for declaration in vrtf.declarations: u = declaration.usage value = self.read_element(declaration,uvscales[declaration.usage_index]) if u == VertexFormat.USAGE.POSITION: vertex.position = value elif u == VertexFormat.USAGE.NORMAL: vertex.normal = value elif u == VertexFormat.USAGE.UV: if vertex.uv == None: vertex.uv = [] vertex.uv.append(value) elif u == VertexFormat.USAGE.BLEND_INDEX: vertex.blend_indices = value elif u == VertexFormat.USAGE.BLEND_WEIGHT: vertex.blend_weights = value elif u == VertexFormat.USAGE.COLOR: vertex.colour = value elif u == VertexFormat.USAGE.TANGENT: vertex.tangent = value else: raise Exception("Unknown usage %s", declaration.usage) actual = self.stream.tell() return vertex def write_vertices(self, vrtf, vertices, uvscales=None): self.stream.seek(0, SEEK_END) offset = self.stream.tell() for vertex in vertices: self.write_vertex(vrtf, vertex) def write_vertex(self, vrtf, v): for declaration in vrtf.declarations: u = declaration.usage if u == VertexFormat.USAGE.POSITION: data = v.position elif u == VertexFormat.USAGE.NORMAL: data = v.normal elif u == VertexFormat.USAGE.UV: data = v.uv[vrtf.usage_index] elif u == VertexFormat.USAGE.BLEND_INDEX: data = v.blend_indices elif u == VertexFormat.USAGE.BLEND_WEIGHT: data = v.blend_weights elif u == VertexFormat.USAGE.COLOR: data = v.colour elif u == VertexFormat.USAGE.TANGENT: data = v.tangents else: raise Exception('Unknown VRTF usage type %i' % u) self.write_element(declaration, data) def write_element(self, declaration, value): pass def read_element(self, declaration, uvscale): float_count = VertexFormat.FORMAT.float_count(declaration.format) value = [0.0] * float_count f = declaration.format u = declaration.usage if u == VertexFormat.USAGE.UV: if f == VertexFormat.FORMAT.SHORT2: for i in range(float_count): value[i] = self.reader.i16() * uvscale elif f == VertexFormat.FORMAT.SHORT4: shorts = [self.reader.i16() for i in range(4)] assert shorts[2] == 0 value = [shorts[0] /0x7FFF, shorts[1]/0x7FFF, shorts[3] /0x1FF] elif f in (VertexFormat.FORMAT.FLOAT, VertexFormat.FORMAT.FLOAT2, VertexFormat.FORMAT.FLOAT3, VertexFormat.FORMAT.FLOAT4): for i in range(float_count): value[i] = self.reader.f32() elif f == VertexFormat.FORMAT.UBYTE4: for i in range(float_count): value[i] = self.reader.i8() elif f == VertexFormat.FORMAT.COLOR_UBYTE4: if u == VertexFormat.USAGE.COLOR: for i in range(float_count): value[i] = self.reader.u8() / 0xFF elif u == VertexFormat.USAGE.BLEND_WEIGHT: for i in range(float_count): value[VertexFormat.FORMAT.UBYTE_MAP[i]] = self.reader.u8() / 0xFF elif u in (VertexFormat.USAGE.NORMAL, VertexFormat.USAGE.TANGENT): bytes = [self.reader.u8() for i in range(4)] for i in range(float_count - 1): value[i] = -1 if bytes[2 - i] == 0 else ( ((bytes[2 - i] + 1) / 128.0) - 1) determinant = 0.0 if not bytes[3]: determinant = -1.0 elif bytes[3] == 127.0: determinant = 0.0 elif bytes[3] == 255.0: determinant = 1.0 else: print("Unexpected handedness %i " % bytes[3]) value[float_count - 1] = determinant else: raise Exception("Unhandled usage %s for format %s" % (u, f)) elif f == VertexFormat.FORMAT.SHORT2: for i in range(float_count): value[i] = self.reader.i16() / 0xFFFF elif f == VertexFormat.FORMAT.SHORT4: shorts = [self.reader.i16() for i in range(3)] scalar = self.reader.u16() if not scalar: scalar = 0x7FFF for i in range(float_count): value[i] = float(shorts[i]) / float(scalar) elif f == VertexFormat.FORMAT.USHORT4N: shorts = [self.reader.i16() for i in range(3)] scalar = self.reader.u16() if not scalar: scalar = 511 for i in range(float_count): value[i] = shorts[i] / scalar elif f == VertexFormat.FORMAT.UBYTE4: data = [self.reader.i8() for i in range(4)] else: raise Exception("Unhandled format %s" % f) return value def __del__(self): if self.stream != None: self.stream.close()
def read(self, stream, resources=None): s = StreamReader(stream) self.version = s.u32() tgi = TGIList() tgi.begin_read(stream) self.presets = ProductBase.read_presets(stream,tgi) if self.version >= 0x00000016: self.instance_name = s.s7(size=16,order='>') self.product_info = ProductInfo() self.product_info.read(stream,tgi) self.object_component = tgi.get_resource(s.i32()) self.object_type_flags = s.u32() if self.version >= 0x00000001A: self.object_type_flags_2 = s.u32() self.wall_placement_flags = s.u32() self.movement_flags = s.u32() self.num_wall_cutout_tiles_per_level = s.i32() self.num_levels = s.i32() self.wall_masks = [self.WallMaskEntry(stream,tgi) for i in range(s.i8())] self.script_enabled = s.i8() == 1 self.diagonal_object = tgi.get_resource(s.i32()) self.ambiance_type = s.hash() self.room_flags = s.u32() self.function_category_flags = s.u32() self.sub_category_flags = s.u64() if self.version >= 0x0000001C: self.sub_category_flags_2 = s.u64() self.sub_room_flags = s.u64() self.build_category_flags = s.u32() self.wall_cutout_texture = tgi.get_resource(s.i32()) if self.version >= 0x00000017: self.floor_cutout_texture = tgi.get_resource(s.i32()) self.floor_cutout_level_offset = s.i32() self.floor_cutout_bounds_length = s.f32() if self.version >= 0x00000020: self.floor_cutout_bounds_width = s.f32() if self.version >= 0x0000021: self.floor_cutout_offset_x = s.f32() self.floor_cutout_offset_z = s.f32() if self.version >= 0x00000018: self.shell_states = [s.hash() for i in range(s.i32())] if self.version >= 0x00000019: self.shell_level_below =tgi.get_resource(s.i32()) if self.version >= 0x0000001B: self.shell_proxy =tgi.get_resource(s.i32()) if self.version >= 0x0000001D: self.blueprint_xml =tgi.get_resource(s.i32()) if self.version >= 0x0000001E: self.blueprint_icon =tgi.get_resource(s.i32()) if self.version >= 0x0000001F: self.blueprint_icon_offset_min_x = s.f32() self.blueprint_icon_offset_min_z = s.f32() self.blueprint_icon_offset_max_x = s.f32() self.blueprint_icon_offset_max_z = s.f32() self.slot_placement_flags = s.u32() self.surface_type = s.s7(size=16,order='>') self.source_material = s.s7(size=16,order='>') self.moodlet_given = s.u32() self.moodlet_score = s.u32() assert s.u32() == 5 self.ratings = [self.ProductRating(stream) for i in range(5)] self.fallback = tgi.get_resource(s.i32()) if self.version >= 0x00000022: self.modular_arch_end_east_model = tgi.get_resource(s.i32()) self.modular_arch_end_west_model = tgi.get_resource(s.i32()) self.modular_arch_connecting_model = tgi.get_resource(s.i32()) self.modular_arch_single_model = tgi.get_resource(s.i32()) tgi.end_read(stream)
class Buffer: def __init__(self): self.stream = BytesIO() self.reader = StreamReader(self.stream) self.writer = StreamWriter(self.stream) def delete_vertices(self, offset, vrtf, count): end_offset = offset + vrtf.stride * count self.stream.seek(end_offset, SEEK_SET) end_data = self.stream.read(-1) self.stream.seek(offset, SEEK_SET) self.stream.truncate() self.stream.writable(end_data) def read_vertices(self, offset, vrtf, count, uvscales): self.stream.seek(offset, SEEK_SET) return [self.read_vertex(vrtf, uvscales) for i in range(count)] def read_vertex(self, vrtf, uvscales): vertex = Vertex() start = self.stream.tell() end = start + vrtf.stride for declaration in vrtf.declarations: u = declaration.usage value = self.read_element(declaration, uvscales[declaration.usage_index]) if u == VertexFormat.USAGE.POSITION: vertex.position = value elif u == VertexFormat.USAGE.NORMAL: vertex.normal = value elif u == VertexFormat.USAGE.UV: if vertex.uv == None: vertex.uv = [] vertex.uv.append(value) elif u == VertexFormat.USAGE.BLEND_INDEX: vertex.blend_indices = value elif u == VertexFormat.USAGE.BLEND_WEIGHT: vertex.blend_weights = value elif u == VertexFormat.USAGE.COLOR: vertex.colour = value elif u == VertexFormat.USAGE.TANGENT: vertex.tangent = value else: raise Exception("Unknown usage %s", declaration.usage) actual = self.stream.tell() return vertex def write_vertices(self, vrtf, vertices, uvscales=None): self.stream.seek(0, SEEK_END) offset = self.stream.tell() for vertex in vertices: self.write_vertex(vrtf, vertex) def write_vertex(self, vrtf, v): for declaration in vrtf.declarations: u = declaration.usage if u == VertexFormat.USAGE.POSITION: data = v.position elif u == VertexFormat.USAGE.NORMAL: data = v.normal elif u == VertexFormat.USAGE.UV: data = v.uv[vrtf.usage_index] elif u == VertexFormat.USAGE.BLEND_INDEX: data = v.blend_indices elif u == VertexFormat.USAGE.BLEND_WEIGHT: data = v.blend_weights elif u == VertexFormat.USAGE.COLOR: data = v.colour elif u == VertexFormat.USAGE.TANGENT: data = v.tangents else: raise Exception('Unknown VRTF usage type %i' % u) self.write_element(declaration, data) def write_element(self, declaration, value): pass def read_element(self, declaration, uvscale): float_count = VertexFormat.FORMAT.float_count(declaration.format) value = [0.0] * float_count f = declaration.format u = declaration.usage if u == VertexFormat.USAGE.UV: if f == VertexFormat.FORMAT.SHORT2: for i in range(float_count): value[i] = self.reader.i16() * uvscale elif f == VertexFormat.FORMAT.SHORT4: shorts = [self.reader.i16() for i in range(4)] assert shorts[2] == 0 value = [ shorts[0] / 0x7FFF, shorts[1] / 0x7FFF, shorts[3] / 0x1FF ] elif f in (VertexFormat.FORMAT.FLOAT, VertexFormat.FORMAT.FLOAT2, VertexFormat.FORMAT.FLOAT3, VertexFormat.FORMAT.FLOAT4): for i in range(float_count): value[i] = self.reader.f32() elif f == VertexFormat.FORMAT.UBYTE4: for i in range(float_count): value[i] = self.reader.i8() elif f == VertexFormat.FORMAT.COLOR_UBYTE4: if u == VertexFormat.USAGE.COLOR: for i in range(float_count): value[i] = self.reader.u8() / 0xFF elif u == VertexFormat.USAGE.BLEND_WEIGHT: for i in range(float_count): value[VertexFormat.FORMAT. UBYTE_MAP[i]] = self.reader.u8() / 0xFF elif u in (VertexFormat.USAGE.NORMAL, VertexFormat.USAGE.TANGENT): bytes = [self.reader.u8() for i in range(4)] for i in range(float_count - 1): value[i] = -1 if bytes[2 - i] == 0 else (( (bytes[2 - i] + 1) / 128.0) - 1) determinant = 0.0 if not bytes[3]: determinant = -1.0 elif bytes[3] == 127.0: determinant = 0.0 elif bytes[3] == 255.0: determinant = 1.0 else: print("Unexpected handedness %i " % bytes[3]) value[float_count - 1] = determinant else: raise Exception("Unhandled usage %s for format %s" % (u, f)) elif f == VertexFormat.FORMAT.SHORT2: for i in range(float_count): value[i] = self.reader.i16() / 0xFFFF elif f == VertexFormat.FORMAT.SHORT4: shorts = [self.reader.i16() for i in range(3)] scalar = self.reader.u16() if not scalar: scalar = 0x7FFF for i in range(float_count): value[i] = float(shorts[i]) / float(scalar) elif f == VertexFormat.FORMAT.USHORT4N: shorts = [self.reader.i16() for i in range(3)] scalar = self.reader.u16() if not scalar: scalar = 511 for i in range(float_count): value[i] = shorts[i] / scalar elif f == VertexFormat.FORMAT.UBYTE4: data = [self.reader.i8() for i in range(4)] else: raise Exception("Unhandled format %s" % f) return value def __del__(self): if self.stream != None: self.stream.close()