home *** CD-ROM | disk | FTP | other *** search
- """
-
- Binary mesh file.
-
- Possibly relevant strings from the executable:
- REB_Mesh VEC_Mesh VEC_Material VEC_Map
- Bitmap, UserData, Map_Diffuse, OneSided, DepthBuffered
- unknown render mode
- (various strings, possibly flags, 9088d0)
- Map_Bump
- invalid tag for a userdata (%d)
-
- """
-
- import io
- import struct
-
- from PyQt5.QtGui import QVector2D, QVector3D
-
- import utils
-
-
- def read_vector2d(ins):
- x, y = struct.unpack('<2f', ins.read(8))
- return QVector2D(x, y)
-
-
- def read_vector3d(ins):
- x, y, z = struct.unpack('<3f', ins.read(12))
- return QVector3D(x, y, z)
-
-
- class Vertex:
- RAW_SIZE = 40
- POS_OFFSET = 0
- TEXCOORD_OFFSET = 28
-
- def __init__(self, ins):
- self.pos = read_vector3d(ins)
- self.normal = read_vector3d(ins)
- # Perhaps ARGB, only ffffffff observed
- self.u0, = struct.unpack('<L', ins.read(4))
- self.texcoord = read_vector2d(ins)
- self.bone, = struct.unpack('<L', ins.read(4))
-
-
- class Triangle:
- RAW_SIZE = 8
-
- def __init__(self, ins):
- # d and e unknown, seem to be very low values. Full sample needed.
- self.a, self.b, self.c, self.d, self.e = \
- struct.unpack('<3H2B', ins.read(8))
-
-
- class BoundingBox:
- def __init__(self, ins):
- minx, miny, minz, maxx, maxy, maxz = struct.unpack('<6f', ins.read(24))
- self.min = QVector3D(minx, miny, minz)
- self.max = QVector3D(maxx, maxy, maxz)
-
- def center(self):
- return QVector3D((self.min.x() + self.max.x()) / 2,
- (self.min.y() + self.max.y()) / 2,
- (self.min.z() + self.max.z()) / 2)
-
- def radius(self):
- return (self.center() - self.min).length()
-
-
- class Material:
- def __init__(self, ins):
- # a is always -1
- # b and c are interesting, see Mesh.u2
- # it looks like b is UserData (needs more testing)
- # c could be flags like MappingType = "Explicit"
- self.a, self.b, self.c, self.TilingU = struct.unpack('<l2Lf', ins.read(16))
- # See sf1.pak, for Order of Dawn at least.
- name = ins.read(64)
- self.name = utils.read_cstr(name)
-
-
- def process_verts(raw_verts):
- ins = io.BytesIO(raw_verts)
- verts = []
- while ins.tell() < len(raw_verts):
- verts.append(Vertex(ins))
- return verts
-
-
- class Mesh:
- def __init__(self, ins):
- always512, num_verts, num_tris = struct.unpack('<h2L', ins.read(10))
- self.raw_verts = ins.read(Vertex.RAW_SIZE * num_verts)
- self.verts = process_verts(self.raw_verts)
- self.triangles = [Triangle(ins) for _ in range(num_tris)]
- # Process into raw indices, which involves removing the d e fields:
- self.raw_indices = bytearray()
- tri_ins = io.BytesIO(self.raw_indices)
- for tri in self.triangles:
- # Note winding order:
- self.raw_indices.extend(struct.pack('<3H', tri.c, tri.b, tri.a))
- always512, = struct.unpack('<h', ins.read(2))
- # Suggested names from here on are based on .msh content:
- self.diffuse_material = Material(ins)
- self.bump_material = Material(ins)
- # u0 shine? always 0.0
- self.argb0, self.argb1, self.u0 = struct.unpack('<2Lf', ins.read(12))
- self.bb = BoundingBox(ins)
- # u1 always 1.0 - could be opacity
- # A large range for u2. Sometimes, clearly floats. Other times, they
- # look like low sequential indices. Other times still, they look like
- # the b and c values seen in the Maps. UserData?
- self.u1, self.u2 = struct.unpack('<fL', ins.read(8))
-
-
- class MeshBuffer:
- def __init__(self, data):
- ins = io.BytesIO(data)
- always512, num_meshes = struct.unpack('<HL', ins.read(6))
- self.meshes = [Mesh(ins) for _ in range(num_meshes)]
- self.bb = BoundingBox(ins)
-
-