Skip to content

Instantly share code, notes, and snippets.

@lf94
Created June 17, 2018 00:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lf94/96f22a1917b75659c74cffdaa85806cb to your computer and use it in GitHub Desktop.
Save lf94/96f22a1917b75659c74cffdaa85806cb to your computer and use it in GitHub Desktop.
zmap to ply converter
def toAddress(bytes):
return int.from_bytes(bytes, byteorder='big')
class Map:
# Map structure is tied to a file
def __init__(self, fileHandle):
self.fileHandle = fileHandle
self.header = self.Header(fileHandle)
fileHandle.seek(toAddress(self.header.commands[-1].data))
self.mesh = Mesh(fileHandle)
class Header:
def __init__(self, fileHandle):
self.fileHandle = fileHandle
self.commands = []
self.bytes = []
self.currentCommand = self.Command(0,0)
while self.currentCommand.mType != 0x0A:
self.nextCommand()
# Found 0x0A
self.parse0x0A()
# Now move onto the mesh...
def nextCommand(self):
self.bytes = self.fileHandle.read(8) # 64 bits
self.currentCommand = self.Command(self.bytes[0], self.bytes[1:])
def parse0x0A(self):
self.commands.append(self.Command(self.bytes[0], self.bytes[-3:]))
class Command:
def __init__(self, mType, data):
self.mType = mType
self.data = data
class Mesh:
def __init__(self, fileHandle):
self.fileHandle = fileHandle
self.header = self.Header(fileHandle)
fileHandle.seek(self.header.startPosition)
self.geometries = []
for mesh in range(self.header.nMeshes):
if self.header.hType == self.header.NORMAL:
# Opaque
self.geometries.append(Geometry(fileHandle))
# Translucent
self.geometries.append(Geometry(fileHandle))
if self.header.hType == self.header.LOD:
fileHandle.read(8)
# High detail
self.geometries.append(Geometry(fileHandle))
# Low detail
self.geometries.append(Geometry(fileHandle))
class Header:
NORMAL = b'\x00'
LOD = b'\x02'
def __init__(self, fileHandle):
self.hType = fileHandle.read(1)
self.nMeshes = int.from_bytes(fileHandle.read(1), byteorder="big")
fileHandle.read(3) # Skip 3 useless bytes
self.startPosition = toAddress(fileHandle.read(3))
class Geometry:
def __init__(self, fileHandle):
self.fileHandle = fileHandle
self.geometry = {'verts': [], 'faces': []}
fileHandle.read(1)
offset = toAddress(fileHandle.read(3))
if(offset != 0):
currentFilePosition = fileHandle.tell()
fileHandle.seek(offset)
interpretMicrocode(fileHandle, self.geometry)
fileHandle.seek(currentFilePosition)
vertexCounter = {'total': 0, 'current': 0}
def interpretMicrocode(fileHandle, geometry):
command = fileHandle.read(8)
while command[0] != 0xDF:
if command[0] == 0xDE:
#print("DE")
currentFilePosition = fileHandle.tell()
fileHandle.seek(toAddress(command[-3:]))
interpretMicrocode(fileHandle, geometry)
fileHandle.seek(currentFilePosition)
elif command[0] == 0x01:
#print("01")
currentFilePosition = fileHandle.tell()
fileHandle.seek(toAddress(command[-3:]))
nVerts = int.from_bytes(command[1:3], byteorder="big") >> 4
verts = readVertices(fileHandle, nVerts)
geometry['verts'].extend(verts)
vertexCounter['current'] = len(verts)
vertexCounter['total'] += vertexCounter['current']
fileHandle.seek(currentFilePosition)
elif command[0] == 0x05:
#print("05")
face = (calculateIndex(command[1]), calculateIndex(command[2]), calculateIndex(command[3]))
geometry['faces'].append(face)
elif command[0] == 0x06:
#print("06")
faces = [
(calculateIndex(command[1]), calculateIndex(command[2]), calculateIndex(command[3])),
(calculateIndex(command[5]), calculateIndex(command[6]), calculateIndex(command[7]))
]
geometry['faces'].extend(faces)
command = fileHandle.read(8)
#print("DF")
return geometry
def calculateIndex(index):
return (index/2)+(vertexCounter['total']-vertexCounter['current'])
def readVertices(fileHandle, nVerts):
verts = []
for vert in range(nVerts):
x = int.from_bytes(fileHandle.read(2), byteorder="big", signed=True)
y = int.from_bytes(fileHandle.read(2), byteorder="big", signed=True)
z = int.from_bytes(fileHandle.read(2), byteorder="big", signed=True)
fileHandle.read(6)
nx = int.from_bytes(fileHandle.read(1), byteorder="big", signed=True)
ny = int.from_bytes(fileHandle.read(1), byteorder="big", signed=True)
nz = int.from_bytes(fileHandle.read(1), byteorder="big", signed=True)
fileHandle.read(1)
verts.append((x,y,z,nx,ny,nz))
return verts
with open("miharigoya_room_0.zmap", "rb") as fh:
mapo = Map(fh)
totalVerts = 0
totalFaces = 0
for geo in mapo.mesh.geometries:
totalVerts += len(geo.geometry['verts'])
totalFaces += len(geo.geometry['faces'])
print("ply")
print("format ascii 1.0")
print("element vertex {0}".format(totalVerts))
print("property float x ")
print("property float y ")
print("property float z")
print("property float nx ")
print("property float ny ")
print("property float nz")
print("element face {0}".format(totalFaces))
print("property list uchar int vertex_index")
print("end_header")
for geo in mapo.mesh.geometries:
for vert in geo.geometry['verts']:
print("{}.0 {}.0 {}.0 {}.0 {}.0 {}.0".format(vert[0],vert[1],vert[2],vert[3],vert[4],vert[5]))
for geo in mapo.mesh.geometries:
for face in geo.geometry['faces']:
print("3 {} {} {}".format(int(face[0]),int(face[1]),int(face[2])))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment