Wednesday, 1 July 2015

Metasequoia Script - Read uklogo.pak

uklogo.pak is the file which stores the title graphic for classic Tomb Raider games (TR1 to TR5).

uklogo.pak

In this post I will write a script that reads the uklogo.pak file.

The first four bytes of the uklogo.pak file are an integer while the rest of the file is the red, green and blue pixel data.

The pixel data is zlib compressed and the integer at the start of the file gives the size of the pixel data when it is decompressed.

The pixel data is stored as 24 bit colour which means one byte for each colour.

The uklogo.pak graphic has dimensions (width x height) 512px  x 256px and black pixels (r=0,g=0,b=0) are transparent when the title is displayed in game.

With this information we can read the uklogo.pak and visualise it in Metasequoia.

Firstly use the Primitive command to create a plane in Metasequoia with the following properties.

plane properties
Change the colour of the material used for the plane to black.

plane

Enter the following Python script into Metasequoia’s Script Editor. The Script Editor is only available from the Panel menu in registered copies of Metasequoia.

# Metasequoia 4 Python script
# Title
'''
Reads uklogo.pak from Tomb Raider games.
'''
# imports
# import Python's os.path module so can extract filename
# and filename extension from full path
import os.path
#import zlib to decompress pixel data
import zlib
#import module to read binary structures
import struct
#import io to use file methods on data in memory
import io
# global variables
doc = MQSystem.getDocument()
# function definitions
def mqprint(message):
try:
print(message)
except:
MQSystem.println(repr(message))
return
def readFile(filepath):
with open(filepath, "rb") as f:
d = f.read(4)
size, = struct.unpack('I',d)
mqprint(size)
comp_data = f.read()
uncomp_data = zlib.decompress(comp_data)
return uncomp_data
# main script function
def main():
# create the OpenFile dialog as a child control of Metasequoia
od = MQWidget.OpenFileDialog(MQWidget.getMainWindow())
od.addFilter("TR4 pak files (*.pak)|*.pak")
# apparently good practise to always have All Files option
od.addFilter("All Files (*.*)|*.*")
# show the dialog
if od.execute():
# user selected a file and clicked ok
# store path string in variable named f
f = od.filename
# extract file's extension using an os.path function
path,ext = os.path.splitext(f)
if ext.lower() in [".pak"]:
# correct extension so extract filename and store in name
path,name = os.path.split(f)
# print path to file
mqprint(f)
# read the file
data = readFile(f)
g=io.BytesIO(data)
matlist=[]
k=0
msg="Have you created a 512 x 256 segmented plane?"
if doc.numObject==0:
mqprint("No object. "+msg)
return
ob=doc.object[doc.currentObjectIndex]
if ob.numFace<(512*256):
mqprint("Too few faces. "+msg)
return
for i in range(256):
for j in range(512):
mat = MQSystem.newMaterial()
s= "mat%i"%(k) #give each material a unique name
k += 1
mat.name=s
rd=struct.unpack('B',g.read(1))[0]
gr=struct.unpack('B',g.read(1))[0]
bl=struct.unpack('B',g.read(1))[0]
if (rd !=0) and (gr !=0) and (bl !=0):
mat.color=MQSystem.newColor(rd/255.0,gr/255.0 ,bl/255.0)
idx = doc.addMaterial(mat) #add material to document
ob.face[512*i+j].material=idx #set material to face
ob.face[512*i+j].select=1 #select the face
else:
# user select incorrect file type
mqprint("Not a *.pak file")
else:
# user clicked "Cancel"
mqprint("No file selected")
return
if __name__ == "__main__":
# clear output window
MQSystem.clearLog()
# run main function
main()
# let user know script finished
mqprint("Script finished")
view raw OpenPak.py hosted with ❤ by GitHub


Make sure the plane object is the current object by selecting it in the Object Panel and that nothing of the mesh is selected before running the script using Script>Run in the Script Editor.

Note that because of the high number iterations through the loop the script takes a few minutes to finish.

You may have to set Metasequoia to show only faces and not lines or points to see the logo properly.

result

After running the script the non black pixels should be selected so you can use extrude to make the title 3D.

Extrude selected faces

3D Logo

No comments:

Post a Comment