def read(self, stream, resource=None): s = StreamReader(stream) assert s.chars(4) == self.TAG self.version = s.u32() cBlends = s.i32() cLods = s.i32() cPointers = s.i32() cVectors = s.i32() assert s.i32() == 0x00000008 assert s.i32() == 0x0000000C blend_ptr = StreamPtr.begin_read(s) vertex_ptr = StreamPtr.begin_read(s) vector_ptr = StreamPtr.begin_read(s) blend_ptr.end() lod_ptrs = [] for blend_index in range(cBlends): blend = Blend() blend.age_gender_flags = s.u32() blend.blend_region = s.u32() self.blends.append(blend) blend.lods = [Blend.LOD() for lod_index in range(cLods)] lod_ptrs.append([self.LodPtr(s.u32(), s.u32(), s.u32()) for lod_index in range(cLods)]) vertex_ptr.end() pointers = [self.VertexPtr(s.i16()) for pointer_index in range(cPointers)] vector_ptr.end() vectors = [[self.unpack(s.i16()) for i in range(3)] for vector_index in range(cVectors)] for blend_index, blend in enumerate(self.blends): start_vector_ptr = 0 current_vector_offset = 0 blend_ptr = lod_ptrs[blend_index] for lod_index, lod in enumerate(blend.lods): lod_blend_index = blend_index + lod_index if lod_blend_index >= len(blend_ptr): print('Skipping missing LOD %s - %s'%(lod_blend_index,len(blend_ptr))) continue lod_ptr = blend_ptr[blend_index + lod_index] current_vertex_id = lod_ptr.start_vertex_id for vector_ptr_index in range(lod_ptr.vertex_count): vertex = Blend.Vertex() vector_ptr = pointers[vector_ptr_index + start_vector_ptr] current_vector_offset += vector_ptr.offset vertex.id = current_vertex_id vertex_vector_offset = 0 if vector_ptr.has_position: vertex.position = vectors[current_vector_offset + vertex_vector_offset] vertex_vector_offset += 1 if vector_ptr.has_normal: vertex.normal = vectors[current_vector_offset + vertex_vector_offset] vertex_vector_offset += 1 current_vertex_id += 1 lod.vertices.append(vertex) start_vector_ptr += lod_ptr.vertex_count current_vector_offset += lod_ptr.vector_count
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): self.read_tag(stream) s = StreamReader(stream) self.version = s.u32() self.flags = s.u32() self.unknown = s.u32() start = stream.tell() stream.seek(0, SEEK_END) end = stream.tell() stream.seek(start, SEEK_SET) self.buffer = [] last = 0 while stream.tell() < end: cur = s.i32() if Flag.is_set(self.flags, self.FLAGS.INDEX_32) else s.i16() if Flag.is_set(self.flags, self.FLAGS.DIFFERENCED_INDICES): cur += last last = cur self.buffer.append(cur)
def deserialize(self, stream, parent_tgi): def read_element(s, tgi_list): def read_complate_string(s): a = s.i8() if not a: return None if a & 0x80: return s.chars(s.i8() if a & 0x40 else a & 0x3F) if a & 0x40: a = (a & 0x3F) + s.i8() return self.complate_string_lookup[a] def read_typecode(s, tgi_list): tc = s.u8() if tc == 1: return read_complate_string(s) elif tc == 0x02: return [s.u8() for i in range(4)] elif tc == 0x03: return tgi_list.get_resource(s.i8()) elif tc == 0x04: return s.f32() elif tc == 0x05: return [s.f32() for i in range(2)] elif tc == 0x06: return [s.f32() for i in range(3)] elif tc == 0x07: return bool(s.i8()) else: raise Exception("Unknown typecode %02X" % tc) element = Preset.Element() element.resource = tgi_list.get_resource(s.u8()) element.name = read_complate_string(s) element.variable = read_complate_string(s) for i in range(s.i32()): name = read_complate_string(s) value = read_typecode(s, tgi_list) element.values[name] = value element.patterns = [ read_element(s, tgi_list) for i in range(s.i32()) ] return element s = StreamReader(stream) unk = s.i16() preset_tgi = TGIList(use_length=True) preset_tgi.begin_read(stream) element = read_element(s, preset_tgi) preset_tgi.end_read(stream) return element
def deserialize(self,stream,parent_tgi): def read_element(s,tgi_list): def read_complate_string(s): a = s.i8() if not a: return None if a & 0x80: return s.chars(s.i8() if a & 0x40 else a &0x3F) if a & 0x40: a = (a & 0x3F) + s.i8() return self.complate_string_lookup[a] def read_typecode(s,tgi_list): tc = s.u8() if tc == 1: return read_complate_string(s) elif tc == 0x02: return [s.u8() for i in range(4)] elif tc == 0x03: return tgi_list.get_resource(s.i8()) elif tc == 0x04: return s.f32() elif tc == 0x05: return [s.f32() for i in range(2)] elif tc == 0x06: return [s.f32() for i in range(3)] elif tc == 0x07: return bool(s.i8()) else: raise Exception("Unknown typecode %02X"%tc) element = Preset.Element() element.resource = tgi_list.get_resource(s.u8()) element.name = read_complate_string(s) element.variable = read_complate_string(s) for i in range(s.i32()): name = read_complate_string(s) value = read_typecode(s,tgi_list) element.values[name] =value element.patterns = [read_element(s,tgi_list) for i in range(s.i32())] return element s = StreamReader(stream) unk = s.i16() preset_tgi = TGIList(use_length=True) preset_tgi.begin_read(stream) element = read_element(s,preset_tgi) preset_tgi.end_read(stream) complate = ComplateElement() complate.preset = element complate.priority = unk return complate
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()
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, resource=None): s = StreamReader(stream) assert s.chars(4) == self.TAG self.version = s.u32() cBlends = s.i32() cLods = s.i32() cPointers = s.i32() cVectors = s.i32() assert s.i32() == 0x00000008 assert s.i32() == 0x0000000C blend_ptr = StreamPtr.begin_read(s) vertex_ptr = StreamPtr.begin_read(s) vector_ptr = StreamPtr.begin_read(s) blend_ptr.end() lod_ptrs = [] for blend_index in range(cBlends): blend = Blend() blend.age_gender_flags = s.u32() blend.blend_region = s.u32() self.blends.append(blend) blend.lods = [Blend.LOD() for lod_index in range(cLods)] lod_ptrs.append([ self.LodPtr(s.u32(), s.u32(), s.u32()) for lod_index in range(cLods) ]) vertex_ptr.end() pointers = [ self.VertexPtr(s.i16()) for pointer_index in range(cPointers) ] vector_ptr.end() vectors = [[self.unpack(s.i16()) for i in range(3)] for vector_index in range(cVectors)] for blend_index, blend in enumerate(self.blends): start_vector_ptr = 0 current_vector_offset = 0 blend_ptr = lod_ptrs[blend_index] for lod_index, lod in enumerate(blend.lods): lod_blend_index = blend_index + lod_index if lod_blend_index >= len(blend_ptr): print('Skipping missing LOD %s - %s' % (lod_blend_index, len(blend_ptr))) continue lod_ptr = blend_ptr[blend_index + lod_index] current_vertex_id = lod_ptr.start_vertex_id for vector_ptr_index in range(lod_ptr.vertex_count): vertex = Blend.Vertex() vector_ptr = pointers[vector_ptr_index + start_vector_ptr] current_vector_offset += vector_ptr.offset vertex.id = current_vertex_id vertex_vector_offset = 0 if vector_ptr.has_position: vertex.position = vectors[current_vector_offset + vertex_vector_offset] vertex_vector_offset += 1 if vector_ptr.has_normal: vertex.normal = vectors[current_vector_offset + vertex_vector_offset] vertex_vector_offset += 1 current_vertex_id += 1 lod.vertices.append(vertex) start_vector_ptr += lod_ptr.vertex_count current_vector_offset += lod_ptr.vector_count