diff --git a/bindings/main.py b/bindings/main.py new file mode 100644 index 0000000..c88aa65 --- /dev/null +++ b/bindings/main.py @@ -0,0 +1,121 @@ +from py3devil1pld import * +from py3devil1tex import * +from py3devil1geo import * + +#--------------------------------------+ +# Regular Python +#--------------------------------------+ + +if __name__ == "__main__": + def pldtest(devil1pld, pldheader): + with open("pl01.pld", "rb") as f: + data = f.read() + devil1pld.getheader(ctypes.byref(pldheader), data) + devil1pld.printheader(ctypes.byref(pldheader)) + # for offset in pldheader.getoffsets(): + # print(hex(offset)) + + def textest(devil1tex, texheader): + print("texture test") + with open("pl01.pld_1.txp", "rb") as f: + data = f.read() +# texheader = ctypes.cast(data, ctypes.POINTER(TexturePack)) + th = ctypes.pointer(texheader) + devil1tex.getheader(ctypes.byref(th), data) + devil1tex.printheader(th) + batchdesc = TextureBatchDescriptor() + bd = ctypes.pointer(batchdesc) + print("\nbatch descriptor:") + devil1tex.getbatchdesc(ctypes.byref(bd), 1, data, len(data)) + devil1tex.printbatchdesc(bd) + print(bd.contents.textureSize) + + def geotest(devil1geo, geoheader): + print("geo test") + with open("pl00.pld_0", "rb") as f: + data = f.read() +# geoheader = ctypes.cast(data, ctypes.POINTER(Header)) + gh = ctypes.pointer(geoheader) + devil1geo.getheader(ctypes.byref(gh), data) + devil1geo.printheader(gh) + meshheader = MeshHeader() + mh = ctypes.pointer(meshheader) + devil1geo.getmeshheader(ctypes.byref(mh), 1, data) + devil1geo.printmeshheader(mh) + + def main(): + sharedlib='./lib3ddevil1.so' + libc = ctypes.cdll.LoadLibrary(sharedlib) + if (not libc): + print("Couldn't load %s" % sharedlib) + return 1 + print("OK") + + pldfn = Devil1PLD_FN.in_dll(libc, "DEVIL1PLD") + pldh = PldHeader() + pldtest(pldfn, pldh) + + texfn = Devil1TEX_FN.in_dll(libc, "DEVIL1TEX") + texh = TexturePack() + textest(texfn, texh) + + geofn = Devil1GEO_FN.in_dll(libc, "DEVIL1GEO") + geoh = Header() + geotest(geofn, geoh) + + def mainx(): + with open("pl01.pld", "rb") as f: + data = f.read() + pld = PLDHeader(data) + pld.show() + pld2 = PLDHeader() + pld2.show() + + with open("pl01.pld_1.txp", "rb") as f: + data = f.read() + txp = TEXturePack(data) + txp.show() + print(txp.getbatchno()) + print(txp.getfirstbatchoffset()) + tbd = TEXtureBatchDescriptor(1, data) + tbd.show() + print(tbd.gettexturesize()) + #tx = TEXtures(0, tbd.gettexno(), data) + tx = TEXtureBatch(0, data) + ts = tx.gettextures() + for i in range(0, 10): + print(ts[0].data[i]) + + with open("pl00.pld_0", "rb") as f: + data = f.read() + gh = GEOHeader(data) + gh.show() + print("-------------") + print(gh.getmeshno()) + print(gh.getunknownb()) + print(gh.getunknownc()) + print(gh.getunknownd()) + print(gh.getpadding()) + print(gh.getunknownoffset()) + mh = MEShHeader(3, data) + mh.show() + m = MEsh(0, data) + m.show() + # p = m.getpositions() + # print("positions:") + # for point in p: + # print(point) + # n = m.getnormals() + # print("normals:") + # for point in n: + # print(point) + # u = m.getuvs() + # print("uvs:") + # for point in u: + # print(point) + dbatch = m.getbatchdata() + print(hex(dbatch.numVertex)) + print(hex(dbatch.padding)) +#---------------------------------------+ + # main() + mainx() diff --git a/bindings/py3devil1.py b/bindings/py3devil1.py deleted file mode 100755 index d63c10b..0000000 --- a/bindings/py3devil1.py +++ /dev/null @@ -1,546 +0,0 @@ -#!/usr/bin/python3 -import ctypes, sys - -#--------------------------------------+ -# Devil 1: PLD Base -#--------------------------------------+ - -class PldHeader(ctypes.Structure): - _pack_ = 1 - _fields_ = [ - ("numOffset", ctypes.c_int), - ("offsets", ctypes.POINTER(ctypes.c_int)) - ] - -class Devil1PLD_FN(ctypes.Structure): - _fields_ = [ - ("getheader" , ctypes.CFUNCTYPE( - ctypes.c_bool, - ctypes.POINTER(PldHeader), - ctypes.c_char_p)), - ("sizeofsector", ctypes.CFUNCTYPE( - ctypes.c_int, - ctypes.POINTER(PldHeader), - ctypes.c_int)), - ("printheader" , ctypes.CFUNCTYPE(None, - ctypes.POINTER(PldHeader))) - ] - -#--------------------------------------+ -# Devil 1: TEX Base -#--------------------------------------+ - -class TexturePack(ctypes.Structure): - _pack_ = 1 - _fields_ = [ - ("id", ctypes.c_char * 4), # fixed length 4, reverse order - ("batchNumber", ctypes.c_int), - ("firstBatchOffset", ctypes.c_int), - ("unknownA", ctypes.c_int) - ] - -class TextureBatchDescriptor(ctypes.Structure): - _pack_ = 1 - _fields_ = [ - ("batchIdx", ctypes.c_int), - ("hash", ctypes.c_int), - ("texNumber", ctypes.c_int), - ("unknownA", ctypes.c_int * 8), - ("textureSize", ctypes.c_int), - ("unknownB", ctypes.c_int * 30) - ] - -class Texture(ctypes.Structure): - _pack_ = 1 - _fields_ = [ - ("data", ctypes.POINTER(ctypes.c_ubyte)) - ] - -class TextureBatch(ctypes.Structure): - _pack_ = 1 - _fields_ = [ - ("batch", ctypes.POINTER(Texture)) - ] - -class Devil1TEX_FN(ctypes.Structure): - _fields_ = [ - ("printheader", ctypes.CFUNCTYPE( - None, - ctypes.POINTER(TexturePack))), - ("printbatchdesc", ctypes.CFUNCTYPE( - None, - ctypes.POINTER(TextureBatchDescriptor))), - ("getheader", ctypes.CFUNCTYPE( - ctypes.c_bool, - ctypes.POINTER( - ctypes.POINTER(TexturePack)), - ctypes.c_char_p)), - ("getbatchdesc", ctypes.CFUNCTYPE( - ctypes.c_bool, - ctypes.POINTER( - ctypes.POINTER(TextureBatchDescriptor)), - ctypes.c_uint, - ctypes.c_char_p, - ctypes.c_uint)), - ("getbatch", ctypes.CFUNCTYPE( - ctypes.c_bool, - ctypes.POINTER( - ctypes.POINTER(TextureBatch)), - ctypes.c_uint, - ctypes.c_char_p, - ctypes.c_uint)), - ("gettextures", ctypes.CFUNCTYPE( - ctypes.c_bool, - ctypes.POINTER(Texture), - ctypes.c_uint, - ctypes.c_char_p, - ctypes.c_uint)) - ] - -#--------------------------------------+ -# Devil 1: GEO Base -#--------------------------------------+ - -class Header(ctypes.Structure): - _pack_ = 1 - _fields_ = [ - ("numMesh", ctypes.c_ubyte), - ("unknownNumberB", ctypes.c_ubyte), - ("unknownNumberC", ctypes.c_ubyte), - ("unknownNumberD", ctypes.c_ubyte), - ("padding", ctypes.c_int), - ("unknownOffset", ctypes.c_ulonglong) - ] - -class MeshHeader(ctypes.Structure): - _pack_ = 1 - _fields_ = [ - ("numBatch", ctypes.c_short), - ("numVertex", ctypes.c_short), - ("u", ctypes.c_uint), - ("offsetBatches", ctypes.c_ulonglong), - ("flags", ctypes.c_ulonglong) - ] - -class Coordinate(ctypes.Structure): - _pack_ = 1 - _fields_ = [ - ("x", ctypes.c_float), - ("y", ctypes.c_float), - ("z", ctypes.c_float) - ] - - def __str__(self): - return "(%s, %s, %s)" % (str(self.x), str(self.y), str(self.z)) - -class UVs(ctypes.Structure): - _pack_ = 1 - _fields_ = [ - ("u", ctypes.c_short), - ("v", ctypes.c_short) - ] - - def __str__(self): - return "(%s, %s)" % (str(self.u), str(self.v)) - -class BoneIndexes(ctypes.Structure): - _pack_ = 1 - _fields_ = [ - ("indexes", ctypes.c_ubyte * 4), - ] - -class BoneWeights(ctypes.Structure): - _pack_ = 1 - _fields_ = [ - ("weights", ctypes.c_short) - ] - - -class BatchData(ctypes.Structure): - _pack_ = 1 - _fields_ = [ - ("numVertex", ctypes.c_short), - ("uB", ctypes.c_short), - ("padding", ctypes.c_uint), - ("offsetPositions", ctypes.c_ulonglong), - ("offsetNormals", ctypes.c_ulonglong), - ("offsetUVs", ctypes.c_ulonglong), - ("offsetBoneIndexes", ctypes.c_ulonglong), - ("offsetBoneWeights", ctypes.c_ulonglong), - ("offsets", ctypes.c_ulonglong) - ] - -class VertexData(ctypes.Structure): - _pack_ = 1 - _fields_ = [ - ("positions", ctypes.POINTER(Coordinate)), - ("normals", ctypes.POINTER(Coordinate)), - ("u", ctypes.POINTER(UVs)), - ("bi", ctypes.POINTER(BoneIndexes)), - ("bw", ctypes.POINTER(BoneWeights)) - ] - -class Batch(ctypes.Structure): - _pack_ = 1 - _fields_ = [ - ("bd", ctypes.POINTER(BatchData)), - ("vd", VertexData) - ] - -class Mesh(ctypes.Structure): - _pack_ = 1 - _fields_ = [ - ("b", ctypes.POINTER(Batch)) - ] - -class Devil1GEO_FN(ctypes.Structure): - _fields_ = [ - ("printheader", ctypes.CFUNCTYPE( - None, - ctypes.POINTER(Header))), - ("printmeshheader", ctypes.CFUNCTYPE( - None, - ctypes.POINTER(MeshHeader))), - ("printbatch", ctypes.CFUNCTYPE( - None, - ctypes.POINTER(Batch))), - ("printcoordinate", ctypes.CFUNCTYPE( - None, - ctypes.POINTER(Coordinate))), - ("getheader", ctypes.CFUNCTYPE( - None, - ctypes.POINTER(ctypes.POINTER(Header)), - ctypes.c_char_p)), - ("getmeshheader", ctypes.CFUNCTYPE( - ctypes.c_bool, - ctypes.POINTER(ctypes.POINTER(MeshHeader)), - ctypes.c_uint, - ctypes.c_char_p)), - ("getbatch", ctypes.CFUNCTYPE( - ctypes.c_bool, - ctypes.POINTER(Batch), - ctypes.c_uint, - ctypes.c_char_p)), - ("getmesh", ctypes.CFUNCTYPE( - ctypes.c_bool, - ctypes.POINTER(Mesh), - ctypes.c_uint, - ctypes.c_char_p, - ctypes.c_uint)) - ] - -#--------------------------------------+ -# Python Objs -#--------------------------------------+ - -sharedlib = './lib3ddevil1.so' -libc = ctypes.cdll.LoadLibrary(sharedlib) -if not libc: - print("Couldn't load %s" % sharedlib) - sys.exit() -del sys -print("\nlib3ddevil1 loaded.") -devil1pld = Devil1PLD_FN.in_dll(libc, "DEVIL1PLD") -devil1tex = Devil1TEX_FN.in_dll(libc, "DEVIL1TEX") -devil1geo = Devil1GEO_FN.in_dll(libc, "DEVIL1GEO") - -class PLDHeader: - def __init__(self, filedata = None): - # Store C Struct in order to call C functions - self.cstruct = PldHeader() - if filedata: - devil1pld.getheader(ctypes.byref(self.cstruct), filedata) - self.eof = len(filedata) - - def show(self): - devil1pld.printheader(ctypes.byref(self.cstruct)) - return - - def getnumoffsets(self): - return self.cstruct.numOffsets - - # return pythonic list of offsets - def getoffsets(self): - return self.cstruct.offsets[:self.cstruct.numOffset] - - def sizeofsector(self, i): - ptr = ctypes.byref(self.cstruct) - return devil1pld.sizeofsector(ptr, i, self.eof) - -class TEXturePack: - def __init__(self, filedata): - self.cstruct = ctypes.pointer(TexturePack()) - devil1tex.getheader(ctypes.byref(self.cstruct), filedata) - return - - def show(self): - devil1tex.printheader(self.cstruct) - - def getbatchno(self): - return self.cstruct.contents.batchNumber - - def getfirstbatchoffset(self): - return self.cstruct.contents.firstBatchOffset - -class TEXtureBatchDescriptor: - def __init__(self, i, filedata): - self.cstruct = ctypes.pointer(TextureBatchDescriptor()) - ptrofptr = ctypes.byref(self.cstruct) - if filedata: - devil1tex.getbatchdesc(ptrofptr, i, filedata, len(filedata)) - return - - def show(self): - devil1tex.printbatchdesc(self.cstruct) - - def getbatchidx(self): - return self.cstruct.contents.batchIdx - - def gethash(self): - return self.cstruct.contents.hash - - def gettexno(self): - return self.cstruct.contents.texNumber - - def gettexturesize(self): - return self.cstruct.contents.textureSize - -class TEXtureBatch: - def __init__(self, i, filedata): - self.cstruct = TextureBatch() - if filedata: - self.cstruct.batch = None - tbd = TEXtureBatchDescriptor(i, filedata) - self.amount = tbd.gettexno() - memsize = self.amount * tbd.gettexturesize() - self.cstruct.batch = ctypes.cast( - ctypes.create_string_buffer(memsize), - ctypes.POINTER(Texture)) - devil1tex.gettextures(self.cstruct.batch, i, filedata, len(filedata)) - return - - def gettextures(self): - return self.cstruct.batch[:self.amount] - -class GEOHeader: - def __init__(self, filedata): - self.cstruct = ctypes.pointer(Header()) - ptrofptr = ctypes.byref(self.cstruct) - if filedata: - devil1geo.getheader(ptrofptr, filedata) - return - - def show(self): - devil1geo.printheader(self.cstruct) - - def getmeshno(self): - return self.cstruct.contents.numMesh - - def getunknownb(self): - return self.cstruct.contents.unknownNumberB - - def getunknownc(self): - return self.cstruct.contents.unknownNumberC - - def getunknownd(self): - return self.cstruct.contents.unknownNumberD - - def getpadding(self): - return hex(self.cstruct.contents.padding) - - def getunknownoffset(self): - return hex(self.cstruct.contents.unknownOffset) - - -class MEShHeader: - def __init__(self, i, filedata): - self.cstruct = ctypes.pointer(MeshHeader()) - ptrofptr = ctypes.byref(self.cstruct) - if filedata: - devil1geo.getmeshheader(ptrofptr, i, filedata) - return - pass - - def show(self): - devil1geo.printmeshheader(self.cstruct) - - def getbatchno(self): - return self.cstruct.contents.numBatch - - def getnumvertex(self): - return self.cstruct.contents.numVertex - - def getunknown(self): - return hex(self.cstruct.contents.u) - - def getoffsetbatches(self): - return self.cstruct.contents.offsetBatches - - def getflags(self): - return self.cstruct.contents.flags - -class MEsh: - def __init__(self, i, filedata): - self.cstruct = Mesh() - if filedata: - mh = MEShHeader(i, filedata) - # allocate memory for the size of batch * number of batches - memsize = ctypes.sizeof(Batch) * mh.getbatchno() - self.cstruct.b = ctypes.cast( - ctypes.create_string_buffer(memsize), - ctypes.POINTER(Batch)) - if not devil1geo.getmesh( - ctypes.byref(self.cstruct), - i, - filedata, - len(filedata)): - print("failed to get mesh") - del mh, memsize - return - - def show(self): - if self.cstruct.b: - devil1geo.printbatch(self.cstruct.b) - else: - print("nothing to show") - - def getbatchdata(self): - return self.cstruct.b.contents.bd.contents - - def getpositions(self): - length = self.cstruct.b.contents.bd.contents.numVertex - return self.cstruct.b.contents.vd.positions[:length] - - def getnormals(self): - length = self.cstruct.b.contents.bd.contents.numVertex - return self.cstruct.b.contents.vd.normals[:length] - - def getuvs(self): - length = self.cstruct.b.contents.bd.contents.numVertex - return self.cstruct.b.contents.vd.u[:length] - - def getboneindexes(self): - length = self.cstruct.b.contents.bd.contents.numVertex - return self.cstruct.b.contents.vd.bi[:length] - - def getboneweights(self): - length = self.cstruct.b.contents.bd.contents.numVertex - return self.cstruct.b.contents.vd.bw[:length] - -#--------------------------------------+ -# Regular Python -#--------------------------------------+ -if __name__ == "__main__": - def pldtest(devil1pld, pldheader): - with open("pl01.pld", "rb") as f: - data = f.read() - devil1pld.getheader(ctypes.byref(pldheader), data) - devil1pld.printheader(ctypes.byref(pldheader)) - # for offset in pldheader.getoffsets(): - # print(hex(offset)) - - def textest(devil1tex, texheader): - print("texture test") - with open("pl01.pld_1.txp", "rb") as f: - data = f.read() -# texheader = ctypes.cast(data, ctypes.POINTER(TexturePack)) - th = ctypes.pointer(texheader) - devil1tex.getheader(ctypes.byref(th), data) - devil1tex.printheader(th) - batchdesc = TextureBatchDescriptor() - bd = ctypes.pointer(batchdesc) - print("\nbatch descriptor:") - devil1tex.getbatchdesc(ctypes.byref(bd), 1, data, len(data)) - devil1tex.printbatchdesc(bd) - print(bd.contents.textureSize) - - def geotest(devil1geo, geoheader): - print("geo test") - with open("pl00.pld_0", "rb") as f: - data = f.read() -# geoheader = ctypes.cast(data, ctypes.POINTER(Header)) - gh = ctypes.pointer(geoheader) - devil1geo.getheader(ctypes.byref(gh), data) - devil1geo.printheader(gh) - meshheader = MeshHeader() - mh = ctypes.pointer(meshheader) - devil1geo.getmeshheader(ctypes.byref(mh), 1, data) - devil1geo.printmeshheader(mh) - - def main(): - sharedlib='./lib3ddevil1.so' - libc = ctypes.cdll.LoadLibrary(sharedlib) - if (not libc): - print("Couldn't load %s" % sharedlib) - return 1 - print("OK") - - pldfn = Devil1PLD_FN.in_dll(libc, "DEVIL1PLD") - pldh = PldHeader() - pldtest(pldfn, pldh) - - texfn = Devil1TEX_FN.in_dll(libc, "DEVIL1TEX") - texh = TexturePack() - textest(texfn, texh) - - geofn = Devil1GEO_FN.in_dll(libc, "DEVIL1GEO") - geoh = Header() - geotest(geofn, geoh) - - def mainx(): - with open("pl01.pld", "rb") as f: - data = f.read() - pld = PLDHeader(data) - pld.show() - pld2 = PLDHeader() - pld2.show() - - with open("pl01.pld_1.txp", "rb") as f: - data = f.read() - txp = TEXturePack(data) - txp.show() - print(txp.getbatchno()) - print(txp.getfirstbatchoffset()) - tbd = TEXtureBatchDescriptor(1, data) - tbd.show() - print(tbd.gettexturesize()) - #tx = TEXtures(0, tbd.gettexno(), data) - tx = TEXtureBatch(0, data) - ts = tx.gettextures() - for i in range(0, 10): - print(ts[0].data[i]) - - with open("pl00.pld_0", "rb") as f: - data = f.read() - gh = GEOHeader(data) - gh.show() - print("-------------") - print(gh.getmeshno()) - print(gh.getunknownb()) - print(gh.getunknownc()) - print(gh.getunknownd()) - print(gh.getpadding()) - print(gh.getunknownoffset()) - mh = MEShHeader(3, data) - mh.show() - m = MEsh(0, data) - m.show() - # p = m.getpositions() - # print("positions:") - # for point in p: - # print(point) - # n = m.getnormals() - # print("normals:") - # for point in n: - # print(point) - # u = m.getuvs() - # print("uvs:") - # for point in u: - # print(point) - dbatch = m.getbatchdata() - print(hex(dbatch.numVertex)) - print(hex(dbatch.padding)) -#---------------------------------------+ - # main() - mainx() - diff --git a/bindings/py3devil1geo.py b/bindings/py3devil1geo.py new file mode 100644 index 0000000..939c282 --- /dev/null +++ b/bindings/py3devil1geo.py @@ -0,0 +1,254 @@ +#!/usr/bin/python3 +import ctypes, sys + +sharedlib = './lib3ddevil1.so' +libc = ctypes.cdll.LoadLibrary(sharedlib) +if not libc: + print("Couldn't load %s" % sharedlib) + sys.exit() +del sys + +print("\nlib3ddevil1 loaded.") + +#--------------------------------------+ +# Basic Struct +#--------------------------------------+ + +class Header(ctypes.Structure): + _pack_ = 1 + _fields_ = [ + ("numMesh", ctypes.c_ubyte), + ("unknownNumberB", ctypes.c_ubyte), + ("unknownNumberC", ctypes.c_ubyte), + ("unknownNumberD", ctypes.c_ubyte), + ("padding", ctypes.c_int), + ("unknownOffset", ctypes.c_ulonglong) + ] + +class MeshHeader(ctypes.Structure): + _pack_ = 1 + _fields_ = [ + ("numBatch", ctypes.c_short), + ("numVertex", ctypes.c_short), + ("u", ctypes.c_uint), + ("offsetBatches", ctypes.c_ulonglong), + ("flags", ctypes.c_ulonglong) + ] + +class Coordinate(ctypes.Structure): + _pack_ = 1 + _fields_ = [ + ("x", ctypes.c_float), + ("y", ctypes.c_float), + ("z", ctypes.c_float) + ] + + def __str__(self): + return "(%s, %s, %s)" % (str(self.x), str(self.y), str(self.z)) + +class UVs(ctypes.Structure): + _pack_ = 1 + _fields_ = [ + ("u", ctypes.c_short), + ("v", ctypes.c_short) + ] + + def __str__(self): + return "(%s, %s)" % (str(self.u), str(self.v)) + +class BoneIndexes(ctypes.Structure): + _pack_ = 1 + _fields_ = [ + ("indexes", ctypes.c_ubyte * 4), + ] + +class BoneWeights(ctypes.Structure): + _pack_ = 1 + _fields_ = [ + ("weights", ctypes.c_short) + ] + + +class BatchData(ctypes.Structure): + _pack_ = 1 + _fields_ = [ + ("numVertex", ctypes.c_short), + ("uB", ctypes.c_short), + ("padding", ctypes.c_uint), + ("offsetPositions", ctypes.c_ulonglong), + ("offsetNormals", ctypes.c_ulonglong), + ("offsetUVs", ctypes.c_ulonglong), + ("offsetBoneIndexes", ctypes.c_ulonglong), + ("offsetBoneWeights", ctypes.c_ulonglong), + ("offsets", ctypes.c_ulonglong) + ] + +class VertexData(ctypes.Structure): + _pack_ = 1 + _fields_ = [ + ("positions", ctypes.POINTER(Coordinate)), + ("normals", ctypes.POINTER(Coordinate)), + ("u", ctypes.POINTER(UVs)), + ("bi", ctypes.POINTER(BoneIndexes)), + ("bw", ctypes.POINTER(BoneWeights)) + ] + +class Batch(ctypes.Structure): + _pack_ = 1 + _fields_ = [ + ("bd", ctypes.POINTER(BatchData)), + ("vd", VertexData) + ] + +class Mesh(ctypes.Structure): + _pack_ = 1 + _fields_ = [ + ("b", ctypes.POINTER(Batch)) + ] + +class Devil1GEO_FN(ctypes.Structure): + _fields_ = [ + ("printheader", ctypes.CFUNCTYPE( + None, + ctypes.POINTER(Header))), + ("printmeshheader", ctypes.CFUNCTYPE( + None, + ctypes.POINTER(MeshHeader))), + ("printbatch", ctypes.CFUNCTYPE( + None, + ctypes.POINTER(Batch))), + ("printcoordinate", ctypes.CFUNCTYPE( + None, + ctypes.POINTER(Coordinate))), + ("getheader", ctypes.CFUNCTYPE( + None, + ctypes.POINTER(ctypes.POINTER(Header)), + ctypes.c_char_p)), + ("getmeshheader", ctypes.CFUNCTYPE( + ctypes.c_bool, + ctypes.POINTER(ctypes.POINTER(MeshHeader)), + ctypes.c_uint, + ctypes.c_char_p)), + ("getbatch", ctypes.CFUNCTYPE( + ctypes.c_bool, + ctypes.POINTER(Batch), + ctypes.c_uint, + ctypes.c_char_p)), + ("getmesh", ctypes.CFUNCTYPE( + ctypes.c_bool, + ctypes.POINTER(Mesh), + ctypes.c_uint, + ctypes.c_char_p, + ctypes.c_uint)) + ] + +devil1geo = Devil1GEO_FN.in_dll(libc, "DEVIL1GEO") + +#--------------------------------------+ +# Pythonic Object +#--------------------------------------+ + +class GEOHeader: + def __init__(self, filedata): + self.cstruct = ctypes.pointer(Header()) + ptrofptr = ctypes.byref(self.cstruct) + if filedata: + devil1geo.getheader(ptrofptr, filedata) + return + + def show(self): + devil1geo.printheader(self.cstruct) + + def getmeshno(self): + return self.cstruct.contents.numMesh + + def getunknownb(self): + return self.cstruct.contents.unknownNumberB + + def getunknownc(self): + return self.cstruct.contents.unknownNumberC + + def getunknownd(self): + return self.cstruct.contents.unknownNumberD + + def getpadding(self): + return hex(self.cstruct.contents.padding) + + def getunknownoffset(self): + return hex(self.cstruct.contents.unknownOffset) + + +class MEShHeader: + def __init__(self, i, filedata): + self.cstruct = ctypes.pointer(MeshHeader()) + ptrofptr = ctypes.byref(self.cstruct) + if filedata: + devil1geo.getmeshheader(ptrofptr, i, filedata) + return + pass + + def show(self): + devil1geo.printmeshheader(self.cstruct) + + def getbatchno(self): + return self.cstruct.contents.numBatch + + def getnumvertex(self): + return self.cstruct.contents.numVertex + + def getunknown(self): + return hex(self.cstruct.contents.u) + + def getoffsetbatches(self): + return self.cstruct.contents.offsetBatches + + def getflags(self): + return self.cstruct.contents.flags + +class MEsh: + def __init__(self, i, filedata): + self.cstruct = Mesh() + if filedata: + mh = MEShHeader(i, filedata) + # allocate memory for the size of batch * number of batches + memsize = ctypes.sizeof(Batch) * mh.getbatchno() + self.cstruct.b = ctypes.cast( + ctypes.create_string_buffer(memsize), + ctypes.POINTER(Batch)) + if not devil1geo.getmesh( + ctypes.byref(self.cstruct), + i, + filedata, + len(filedata)): + print("failed to get mesh") + del mh, memsize + return + + def show(self): + if self.cstruct.b: + devil1geo.printbatch(self.cstruct.b) + else: + print("nothing to show") + + def getbatchdata(self): + return self.cstruct.b.contents.bd.contents + + def getpositions(self): + length = self.cstruct.b.contents.bd.contents.numVertex + return self.cstruct.b.contents.vd.positions[:length] + + def getnormals(self): + length = self.cstruct.b.contents.bd.contents.numVertex + return self.cstruct.b.contents.vd.normals[:length] + + def getuvs(self): + length = self.cstruct.b.contents.bd.contents.numVertex + return self.cstruct.b.contents.vd.u[:length] + + def getboneindexes(self): + length = self.cstruct.b.contents.bd.contents.numVertex + return self.cstruct.b.contents.vd.bi[:length] + + def getboneweights(self): + length = self.cstruct.b.contents.bd.contents.numVertex + return self.cstruct.b.contents.vd.bw[:length] diff --git a/bindings/py3devil1pld.py b/bindings/py3devil1pld.py new file mode 100644 index 0000000..ad66826 --- /dev/null +++ b/bindings/py3devil1pld.py @@ -0,0 +1,65 @@ +#!/usr/bin/python3 +import ctypes, sys + +sharedlib = './lib3ddevil1.so' +libc = ctypes.cdll.LoadLibrary(sharedlib) +if not libc: + print("Couldn't load %s" % sharedlib) + sys.exit() +del sys +print("\nlib3ddevil1 loaded.") + +#--------------------------------------+ +# Basic Struct +#--------------------------------------+ + +class PldHeader(ctypes.Structure): + _pack_ = 1 + _fields_ = [ + ("numOffset", ctypes.c_int), + ("offsets", ctypes.POINTER(ctypes.c_int)) + ] + +class Devil1PLD_FN(ctypes.Structure): + _fields_ = [ + ("getheader" , ctypes.CFUNCTYPE( + ctypes.c_bool, + ctypes.POINTER(PldHeader), + ctypes.c_char_p)), + ("sizeofsector", ctypes.CFUNCTYPE( + ctypes.c_int, + ctypes.POINTER(PldHeader), + ctypes.c_int)), + ("printheader" , ctypes.CFUNCTYPE(None, + ctypes.POINTER(PldHeader))) + ] + +devil1pld = Devil1PLD_FN.in_dll(libc, "DEVIL1PLD") + +#--------------------------------------+ +# Pythonic Object +#--------------------------------------+ + +class PLDHeader: + def __init__(self, filedata = None): + # Store C Struct in order to call C functions + self.cstruct = PldHeader() + if filedata: + devil1pld.getheader(ctypes.byref(self.cstruct), filedata) + self.eof = len(filedata) + + def show(self): + devil1pld.printheader(ctypes.byref(self.cstruct)) + return + + def getnumoffsets(self): + return self.cstruct.numOffsets + + # return pythonic list of offsets + def getoffsets(self): + return self.cstruct.offsets[:self.cstruct.numOffset] + + def sizeofsector(self, i): + ptr = ctypes.byref(self.cstruct) + return devil1pld.sizeofsector(ptr, i, self.eof) + diff --git a/bindings/py3devil1tex.py b/bindings/py3devil1tex.py new file mode 100644 index 0000000..0fa32a9 --- /dev/null +++ b/bindings/py3devil1tex.py @@ -0,0 +1,144 @@ +#!/usr/bin/python3 +import ctypes, sys + +sharedlib = './lib3ddevil1.so' +libc = ctypes.cdll.LoadLibrary(sharedlib) +if not libc: + print("Couldn't load %s" % sharedlib) + sys.exit() +del sys + +print("\nlib3ddevil1 loaded.") + +#--------------------------------------+ +# Basic Struct +#--------------------------------------+ + +class TexturePack(ctypes.Structure): + _pack_ = 1 + _fields_ = [ + ("id", ctypes.c_char * 4), # fixed length 4, reverse order + ("batchNumber", ctypes.c_int), + ("firstBatchOffset", ctypes.c_int), + ("unknownA", ctypes.c_int) + ] + +class TextureBatchDescriptor(ctypes.Structure): + _pack_ = 1 + _fields_ = [ + ("batchIdx", ctypes.c_int), + ("hash", ctypes.c_int), + ("texNumber", ctypes.c_int), + ("unknownA", ctypes.c_int * 8), + ("textureSize", ctypes.c_int), + ("unknownB", ctypes.c_int * 30) + ] + +class Texture(ctypes.Structure): + _pack_ = 1 + _fields_ = [ + ("data", ctypes.POINTER(ctypes.c_ubyte)) + ] + +class TextureBatch(ctypes.Structure): + _pack_ = 1 + _fields_ = [ + ("batch", ctypes.POINTER(Texture)) + ] + +class Devil1TEX_FN(ctypes.Structure): + _fields_ = [ + ("printheader", ctypes.CFUNCTYPE( + None, + ctypes.POINTER(TexturePack))), + ("printbatchdesc", ctypes.CFUNCTYPE( + None, + ctypes.POINTER(TextureBatchDescriptor))), + ("getheader", ctypes.CFUNCTYPE( + ctypes.c_bool, + ctypes.POINTER( + ctypes.POINTER(TexturePack)), + ctypes.c_char_p)), + ("getbatchdesc", ctypes.CFUNCTYPE( + ctypes.c_bool, + ctypes.POINTER( + ctypes.POINTER(TextureBatchDescriptor)), + ctypes.c_uint, + ctypes.c_char_p, + ctypes.c_uint)), + ("getbatch", ctypes.CFUNCTYPE( + ctypes.c_bool, + ctypes.POINTER( + ctypes.POINTER(TextureBatch)), + ctypes.c_uint, + ctypes.c_char_p, + ctypes.c_uint)), + ("gettextures", ctypes.CFUNCTYPE( + ctypes.c_bool, + ctypes.POINTER(Texture), + ctypes.c_uint, + ctypes.c_char_p, + ctypes.c_uint)) + ] + +devil1tex = Devil1TEX_FN.in_dll(libc, "DEVIL1TEX") + +#--------------------------------------+ +# Pythonic Object +#--------------------------------------+ + +class TEXturePack: + def __init__(self, filedata): + self.cstruct = ctypes.pointer(TexturePack()) + devil1tex.getheader(ctypes.byref(self.cstruct), filedata) + return + + def show(self): + devil1tex.printheader(self.cstruct) + + def getbatchno(self): + return self.cstruct.contents.batchNumber + + def getfirstbatchoffset(self): + return self.cstruct.contents.firstBatchOffset + +class TEXtureBatchDescriptor: + def __init__(self, i, filedata): + self.cstruct = ctypes.pointer(TextureBatchDescriptor()) + ptrofptr = ctypes.byref(self.cstruct) + if filedata: + devil1tex.getbatchdesc(ptrofptr, i, filedata, len(filedata)) + return + + def show(self): + devil1tex.printbatchdesc(self.cstruct) + + def getbatchidx(self): + return self.cstruct.contents.batchIdx + + def gethash(self): + return self.cstruct.contents.hash + + def gettexno(self): + return self.cstruct.contents.texNumber + + def gettexturesize(self): + return self.cstruct.contents.textureSize + +class TEXtureBatch: + def __init__(self, i, filedata): + self.cstruct = TextureBatch() + if filedata: + self.cstruct.batch = None + tbd = TEXtureBatchDescriptor(i, filedata) + self.amount = tbd.gettexno() + memsize = self.amount * tbd.gettexturesize() + self.cstruct.batch = ctypes.cast( + ctypes.create_string_buffer(memsize), + ctypes.POINTER(Texture)) + devil1tex.gettextures(self.cstruct.batch, i, filedata, len(filedata)) + return + + def gettextures(self): + return self.cstruct.batch[:self.amount] +