mirror of
https://notabug.org/scuti/lib3ddevil1
synced 2024-11-25 16:28:57 +05:30
Merge branch 'python/finalize' of scuti/lib3ddevil1 into feature/pythonbinding
This commit is contained in:
commit
182567a634
2
Makefile
2
Makefile
@ -35,4 +35,4 @@ devil1geo.o: src/devil1geo.c
|
|||||||
$(CC) -c $^ $(CFLAGS)
|
$(CC) -c $^ $(CFLAGS)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm *.o *.gch $(TARGET) $(PEX) $(TEX) $(MEX)
|
rm *.o $(TARGET) $(PEX) $(TEX) $(MEX)
|
||||||
|
@ -2,12 +2,16 @@
|
|||||||
A C library for handling Devil May Cry 1 HD Collection PC file formats.
|
A C library for handling Devil May Cry 1 HD Collection PC file formats.
|
||||||
|
|
||||||
|
|
||||||
#### Build Demos
|
#### Build
|
||||||
Run `make`
|
Run `make` to build demos.
|
||||||
|
|
||||||
|
Include the appropriate files in your build system. Reference the Makefile for an example of building with GCC.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#### Compiler(s)
|
#### Compiler(s)
|
||||||
Developed and tested with the following compilers.
|
Developed and tested with the following compilers.
|
||||||
|
|
||||||
* mingw-w64, GCC 6.4.0
|
* mingw-w64, GCC 6.4.0
|
||||||
* gcc version 7.1.1 20170528
|
* gcc version 7.1.1 20170528
|
||||||
|
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
import ctypes, os, sys
|
||||||
|
|
||||||
|
def loadlibc():
|
||||||
|
libc = None
|
||||||
|
# os.environ['PATH'] = os.path.abspath(
|
||||||
|
# os.path.join(
|
||||||
|
# os.path.dirname(__file__), "../")) \
|
||||||
|
# + ';' \
|
||||||
|
# + os.environ['PATH']
|
||||||
|
# __file__ is this __init__.py
|
||||||
|
# This assumes that the repo's directory has not been modified
|
||||||
|
# and that
|
||||||
|
so = '/lib3ddevil1.so'
|
||||||
|
libdir = os.path.abspath(os.path.join(os.path.dirname(__file__), "../"))
|
||||||
|
sharedlib = libdir + so
|
||||||
|
try:
|
||||||
|
libc = ctypes.cdll.LoadLibrary(sharedlib)
|
||||||
|
except OSError as e:
|
||||||
|
print("Error loading dynamically linked library.\nOSError: " + str(e))
|
||||||
|
raise RuntimeError("Couldn't load %s" % sharedlib)
|
||||||
|
return libc
|
||||||
|
|
||||||
|
libc = loadlibc()
|
134
bindings/__test__.py
Executable file
134
bindings/__test__.py
Executable file
@ -0,0 +1,134 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
from py3devil1pld import pyPldHeader
|
||||||
|
from py3devil1tex import pyTexturePack, pyTextureBatchDescriptor, pyTextureBatch
|
||||||
|
from py3devil1geo import pyGeoHeader, pyMeshHeader, pyMesh
|
||||||
|
|
||||||
|
#print(libc)
|
||||||
|
|
||||||
|
#--------------------------------------+
|
||||||
|
# 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 = pyPldHeader()
|
||||||
|
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 = pyPldHeader(data)
|
||||||
|
pld.show()
|
||||||
|
pld2 = pyPldHeader()
|
||||||
|
pld2.show()
|
||||||
|
|
||||||
|
with open("pl01.pld_1.txp", "rb") as f:
|
||||||
|
data = f.read()
|
||||||
|
txp = pyTexturePack(data)
|
||||||
|
txp.show()
|
||||||
|
print(txp.getbatchnumber())
|
||||||
|
print(txp.getfirstbatchoffset())
|
||||||
|
tbd = pyTextureBatchDescriptor(1, data)
|
||||||
|
tbd.show()
|
||||||
|
print(tbd.gettexturesize())
|
||||||
|
#tx = pyTextures(0, tbd.gettexno(), data)
|
||||||
|
tx = pyTextureBatch(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 = pyGeoHeader(data)
|
||||||
|
gh.show()
|
||||||
|
print("-------------")
|
||||||
|
print(gh.getnummesh())
|
||||||
|
print(gh.getunknownb())
|
||||||
|
print(gh.getunknownc())
|
||||||
|
print(gh.getunknownd())
|
||||||
|
print(gh.getpadding())
|
||||||
|
print(gh.getunknownoffset())
|
||||||
|
mh = pyMeshHeader(3, data)
|
||||||
|
print("-------------")
|
||||||
|
try:
|
||||||
|
mh = pyMeshHeader(87, data)
|
||||||
|
except RuntimeError as e:
|
||||||
|
print(str(e))
|
||||||
|
try:
|
||||||
|
mh = pyMesh(87, data)
|
||||||
|
except RuntimeError as e:
|
||||||
|
print(str(e))
|
||||||
|
print("-------------")
|
||||||
|
mh.show()
|
||||||
|
m = pyMesh(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()
|
@ -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()
|
|
||||||
|
|
254
bindings/py3devil1geo.py
Normal file
254
bindings/py3devil1geo.py
Normal file
@ -0,0 +1,254 @@
|
|||||||
|
import ctypes
|
||||||
|
import os, sys
|
||||||
|
sys.path.append(
|
||||||
|
os.path.abspath(
|
||||||
|
os.path.join(
|
||||||
|
os.path.dirname(__file__), "../../")))
|
||||||
|
from lib3ddevil1.bindings import libc
|
||||||
|
del os, sys
|
||||||
|
|
||||||
|
#--------------------------------------+
|
||||||
|
# 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(
|
||||||
|
ctypes.c_bool,
|
||||||
|
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")
|
||||||
|
del libc
|
||||||
|
|
||||||
|
#--------------------------------------+
|
||||||
|
# Pythonic Object
|
||||||
|
#--------------------------------------+
|
||||||
|
|
||||||
|
class pyGeoHeader:
|
||||||
|
def __init__(self, filedata):
|
||||||
|
self.cstruct = ctypes.pointer(Header())
|
||||||
|
ptrofptr = ctypes.byref(self.cstruct)
|
||||||
|
if filedata:
|
||||||
|
if not devil1geo.getheader(ptrofptr, filedata):
|
||||||
|
raise RuntimeError("failed to get geometry file header")
|
||||||
|
return
|
||||||
|
|
||||||
|
def show(self):
|
||||||
|
devil1geo.printheader(self.cstruct)
|
||||||
|
|
||||||
|
def getnummesh(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 pyMeshHeader:
|
||||||
|
def __init__(self, i, filedata):
|
||||||
|
self.cstruct = ctypes.pointer(MeshHeader())
|
||||||
|
ptrofptr = ctypes.byref(self.cstruct)
|
||||||
|
if filedata:
|
||||||
|
if not devil1geo.getmeshheader(ptrofptr, i, filedata):
|
||||||
|
raise RuntimeError("failed to get mesh header #" + str(i))
|
||||||
|
return
|
||||||
|
pass
|
||||||
|
|
||||||
|
def show(self):
|
||||||
|
devil1geo.printmeshheader(self.cstruct)
|
||||||
|
|
||||||
|
def getnumbatch(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 pyMesh:
|
||||||
|
def __init__(self, i, filedata):
|
||||||
|
self.cstruct = Mesh()
|
||||||
|
if filedata:
|
||||||
|
mh = pyMeshHeader(i, filedata)
|
||||||
|
# allocate memory for the size of batch * number of batches
|
||||||
|
memsize = ctypes.sizeof(Batch) * mh.getnumbatch()
|
||||||
|
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)):
|
||||||
|
raise RuntimeError("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]
|
66
bindings/py3devil1pld.py
Normal file
66
bindings/py3devil1pld.py
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
import ctypes
|
||||||
|
import os, sys
|
||||||
|
# This is the folder containing the whole library.
|
||||||
|
sys.path.append(
|
||||||
|
os.path.abspath(
|
||||||
|
os.path.join(
|
||||||
|
os.path.dirname(__file__), "../../")))
|
||||||
|
from lib3ddevil1.bindings import libc
|
||||||
|
del os, sys
|
||||||
|
|
||||||
|
#--------------------------------------+
|
||||||
|
# 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")
|
||||||
|
del libc
|
||||||
|
|
||||||
|
#--------------------------------------+
|
||||||
|
# Pythonic Object
|
||||||
|
#--------------------------------------+
|
||||||
|
|
||||||
|
class pyPldHeader:
|
||||||
|
def __init__(self, filedata = None):
|
||||||
|
# Store C Struct in order to call C functions
|
||||||
|
self.cstruct = PldHeader()
|
||||||
|
if filedata:
|
||||||
|
if not devil1pld.getheader(ctypes.byref(self.cstruct), filedata):
|
||||||
|
raise RuntimeError("failed to get .pld header")
|
||||||
|
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)
|
||||||
|
|
161
bindings/py3devil1tex.py
Normal file
161
bindings/py3devil1tex.py
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
import ctypes
|
||||||
|
import os, sys
|
||||||
|
sys.path.append(
|
||||||
|
os.path.abspath(
|
||||||
|
os.path.join(
|
||||||
|
os.path.dirname(__file__), "../../")))
|
||||||
|
from lib3ddevil1.bindings import libc
|
||||||
|
del os, sys
|
||||||
|
|
||||||
|
#--------------------------------------+
|
||||||
|
# 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")
|
||||||
|
del libc
|
||||||
|
|
||||||
|
#--------------------------------------+
|
||||||
|
# Pythonic Object
|
||||||
|
#--------------------------------------+
|
||||||
|
|
||||||
|
class pyTexturePack:
|
||||||
|
def __init__(self, filedata):
|
||||||
|
self.cstruct = ctypes.pointer(TexturePack())
|
||||||
|
if not devil1tex.getheader(ctypes.byref(self.cstruct), filedata):
|
||||||
|
raise RuntimeError("failed to get texture pack header")
|
||||||
|
return
|
||||||
|
|
||||||
|
def show(self):
|
||||||
|
devil1tex.printheader(self.cstruct)
|
||||||
|
|
||||||
|
def getbatchnumber(self):
|
||||||
|
return self.cstruct.contents.batchNumber
|
||||||
|
|
||||||
|
def getfirstbatchoffset(self):
|
||||||
|
return self.cstruct.contents.firstBatchOffset
|
||||||
|
|
||||||
|
class pyTextureBatchDescriptor:
|
||||||
|
def __init__(self, i, filedata):
|
||||||
|
self.cstruct = ctypes.pointer(TextureBatchDescriptor())
|
||||||
|
ptrofptr = ctypes.byref(self.cstruct)
|
||||||
|
if filedata:
|
||||||
|
if not devil1tex.getbatchdesc(
|
||||||
|
ptrofptr,
|
||||||
|
i,
|
||||||
|
filedata,
|
||||||
|
len(filedata)):
|
||||||
|
raise RuntimeError("failed to get texturebatchdescriptor #" + str(i))
|
||||||
|
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 gettexnumber(self):
|
||||||
|
return self.cstruct.contents.texNumber
|
||||||
|
|
||||||
|
def gettexturesize(self):
|
||||||
|
return self.cstruct.contents.textureSize
|
||||||
|
|
||||||
|
class pyTextureBatch:
|
||||||
|
def __init__(self, i, filedata):
|
||||||
|
self.cstruct = TextureBatch()
|
||||||
|
if filedata:
|
||||||
|
self.cstruct.batch = None
|
||||||
|
tbd = pyTextureBatchDescriptor(i, filedata)
|
||||||
|
self.amount = tbd.gettexnumber()
|
||||||
|
self.size = tbd.gettexturesize()
|
||||||
|
memsize = self.amount * self.size
|
||||||
|
self.cstruct.batch = ctypes.cast(
|
||||||
|
ctypes.create_string_buffer(memsize),
|
||||||
|
ctypes.POINTER(Texture))
|
||||||
|
if not devil1tex.gettextures(
|
||||||
|
self.cstruct.batch,
|
||||||
|
i,
|
||||||
|
filedata,
|
||||||
|
len(filedata)):
|
||||||
|
raise RuntimeError("failed to get textures of batch #" + str(i))
|
||||||
|
return
|
||||||
|
|
||||||
|
def gettextures(self):
|
||||||
|
ptrs = self.cstruct.batch[:self.amount]
|
||||||
|
textures = []
|
||||||
|
for ptr in ptrs:
|
||||||
|
texture = ctypes.cast(ptr.data,
|
||||||
|
ctypes.POINTER(
|
||||||
|
ctypes.c_ubyte * self.size))[0]
|
||||||
|
textures.append(texture)
|
||||||
|
return textures
|
||||||
|
|
132
docs/doc-geo.txt
Normal file
132
docs/doc-geo.txt
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
|
||||||
|
devil1geo.h / devil1geo.c
|
||||||
|
Handles files containing geometry.
|
||||||
|
|
||||||
|
Functions
|
||||||
|
All functions are static but exposed by a function pointer in a constant
|
||||||
|
struct called DEVIL1GEO. For example, clients call functions using
|
||||||
|
DEVIL1GEO.printheader(...);
|
||||||
|
|
||||||
|
void printheader(struct Header*);
|
||||||
|
Show attributes and values of a Header for the package.
|
||||||
|
|
||||||
|
input: pointer to Header, pass by reference of a struct.
|
||||||
|
Can not be NULL.
|
||||||
|
|
||||||
|
void printmeshheader(struct MeshHeader*);
|
||||||
|
Show attributes and values of a MeshHeader.
|
||||||
|
|
||||||
|
input: pointer to MeshHeader, pass by reference of a struct.
|
||||||
|
Can not be NULL.
|
||||||
|
|
||||||
|
void printbatch(struct Batch*);
|
||||||
|
Show attribute and values of a Batch and three sample position
|
||||||
|
coordinates.
|
||||||
|
|
||||||
|
input: pointer to Batch, pass by reference of a struct.
|
||||||
|
Can not be NULL.
|
||||||
|
|
||||||
|
void printcoordinate(struct Coordinate*, unsigned int);
|
||||||
|
Show a specified quantity of Coordinates.
|
||||||
|
|
||||||
|
input:
|
||||||
|
pointer to array of Coordinates.
|
||||||
|
Can not be NULL.
|
||||||
|
|
||||||
|
unsigned int, for quantity of coordinates to be printed.
|
||||||
|
|
||||||
|
|
||||||
|
bool getmeshheader(struct MeshHeader**,
|
||||||
|
unsigned int,
|
||||||
|
const char * const);
|
||||||
|
Retrives the i-th MeshHeader in a buffer.
|
||||||
|
|
||||||
|
input:
|
||||||
|
Pointer of a pointer to MeshHeader.
|
||||||
|
Pass by reference of a pointer to the function.
|
||||||
|
The pointer of MeshHeader can be NULL and will be set to point to
|
||||||
|
a region in the buffer.
|
||||||
|
|
||||||
|
unsigned int, the i-th instance of MeshHeader in the buffer.
|
||||||
|
|
||||||
|
const char*, the buffer containing the whole mesh package.
|
||||||
|
|
||||||
|
output:
|
||||||
|
true on success.
|
||||||
|
|
||||||
|
false when failing checks against segmentation faults.
|
||||||
|
If parameter 'struct MeshHeader**' is NULL.
|
||||||
|
If parameter 'const char*' is NULL.
|
||||||
|
|
||||||
|
bool getbatch(struct Batch*,
|
||||||
|
unsigned int offset,
|
||||||
|
const char * const);
|
||||||
|
Retrives the i-th Batch in a buffer.
|
||||||
|
|
||||||
|
input:
|
||||||
|
Pointer to a Batch.
|
||||||
|
Pass by reference of a struct to the function.
|
||||||
|
Can not be NULL.
|
||||||
|
|
||||||
|
unsigned int, the i-th instance of Batch in the buffer.
|
||||||
|
|
||||||
|
const char*, the buffer containing the whole mesh package.
|
||||||
|
|
||||||
|
output:
|
||||||
|
true on success.
|
||||||
|
|
||||||
|
false when failing checks against segmentation faults.
|
||||||
|
If parameter 'struct Batch*' is NULL.
|
||||||
|
If parameter 'const char*' is NULL.
|
||||||
|
|
||||||
|
bool getmesh(struct Mesh*,
|
||||||
|
unsigned int,
|
||||||
|
const char*,
|
||||||
|
unsigned int);
|
||||||
|
Retrives the i-th Mesh in a buffer.
|
||||||
|
|
||||||
|
input:
|
||||||
|
Pointer to mesh.
|
||||||
|
Pass by reference of a struct to the function.
|
||||||
|
|
||||||
|
unsigned int, the i-th instance of Mesh in the buffer.
|
||||||
|
|
||||||
|
const char*, the buffer containing the whole mesh package.
|
||||||
|
|
||||||
|
output:
|
||||||
|
true on success.
|
||||||
|
|
||||||
|
false when failing checks against segmentation faults.
|
||||||
|
If parameter 'struct Mesh*' is NULL.
|
||||||
|
If attribute 'b' of parameter 'struct Mesh' is NULL.
|
||||||
|
if parameter 'const char*' is NULL.
|
||||||
|
When file size is detected to be too small for a given i-th
|
||||||
|
Mesh.
|
||||||
|
|
||||||
|
Example logic to interact with all meshes:
|
||||||
|
{
|
||||||
|
// After the file has been read in.
|
||||||
|
|
||||||
|
// Need to know how many meshes are in the file.
|
||||||
|
struct Header *h = (struct Header*)filedata;
|
||||||
|
|
||||||
|
// Need to know about a specific mesh (how many batches).
|
||||||
|
struct MeshHeader *mh = NULL;
|
||||||
|
|
||||||
|
// Need to hold information about mesh.
|
||||||
|
struct Mesh m;
|
||||||
|
// As a precaution - empty for now.
|
||||||
|
m.b = NULL;
|
||||||
|
|
||||||
|
unsigned int i;
|
||||||
|
for (i = 0; i < h -> numMesh; i++) {
|
||||||
|
DEVIL1GEO.getmeshheader(&mh, i, filedata);
|
||||||
|
// Allocate space to hold batch data.
|
||||||
|
m.b = (struct Batch*)malloc(sizeof(struct Batch) * (mh -> numBatch));
|
||||||
|
if (m.b != NULL) {
|
||||||
|
DEVIL1GEO.getmesh(&m, i, filedata, filesize);
|
||||||
|
// Do whatever you want with the mesh.
|
||||||
|
free(m.b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
23
docs/doc-overview.txt
Normal file
23
docs/doc-overview.txt
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
|
||||||
|
lib3ddevil1
|
||||||
|
A C library for handling Devil May Cry 1 HD Collection PC file formats.
|
||||||
|
These formats are little endian.
|
||||||
|
|
||||||
|
Design/Restrictions
|
||||||
|
Library functions do not:
|
||||||
|
- allocate memory on the heap
|
||||||
|
- operate on files
|
||||||
|
- convert endianness
|
||||||
|
|
||||||
|
Pseudo-Namespaces
|
||||||
|
Library functions are callable through a struct of function pointers.
|
||||||
|
For example:
|
||||||
|
// Print header of a .pld file.
|
||||||
|
DEVIL1PLD.printheader(...);
|
||||||
|
|
||||||
|
// Print header of a texture pack.
|
||||||
|
DEVIL1TEX.printheader(...);
|
||||||
|
|
||||||
|
// Print header of a mesh pack.
|
||||||
|
DEVIL1GEO.printheader(...);
|
||||||
|
|
56
docs/doc-pld.txt
Normal file
56
docs/doc-pld.txt
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
|
||||||
|
devil1pld.h / devil1pld.c
|
||||||
|
Handles .pld files.
|
||||||
|
|
||||||
|
File Format
|
||||||
|
PLDs are simple packages of different files, and do not contain a table
|
||||||
|
of contents. The header consists only of the number of files packaged
|
||||||
|
and the offsets from the beginning of the .pld that marks the starting
|
||||||
|
location of the file.
|
||||||
|
|
||||||
|
Functions
|
||||||
|
All functions are static but exposed by a function pointer in a constant
|
||||||
|
struct called DEVIL1PLD. For example, clients call functions using
|
||||||
|
DEVIL1PLD.getheader(..., ...);
|
||||||
|
|
||||||
|
bool getheader(struct PldHeader*, const char*);
|
||||||
|
Places file header into the struct pointed at by the first parameter
|
||||||
|
from the information given in by the second parameter.
|
||||||
|
|
||||||
|
inputs: pointer to a struct, pointer to file data
|
||||||
|
Neither parameter should be NULL.
|
||||||
|
|
||||||
|
output: true or false, whether or not operation succeeds or fails.
|
||||||
|
Will return false if one or both of the parameters are NULL
|
||||||
|
pointers.
|
||||||
|
Will return false if the attribute numOffset is less than 0-
|
||||||
|
i.e file is not valid.
|
||||||
|
|
||||||
|
int sizeofsector(struct PldHeader*, unsigned int i, unsigned int max);
|
||||||
|
Returns the size of the i-th file packed in the pld.
|
||||||
|
|
||||||
|
inputs: pointer to a struct, i-th element in pld, file size
|
||||||
|
|
||||||
|
output: (-1), [0, maximum value of int)
|
||||||
|
-1 indicates an invalid input.
|
||||||
|
|
||||||
|
void printheader(struct PldHeader*);
|
||||||
|
Shows contents of a PLD header in standard output.
|
||||||
|
|
||||||
|
inputs: pointer of a struct
|
||||||
|
|
||||||
|
Example logic to iterate through a .pld
|
||||||
|
{
|
||||||
|
...
|
||||||
|
// Get information about the file
|
||||||
|
struct PldHeader h;
|
||||||
|
DEVIL1PLD.getheader(&h, data);
|
||||||
|
|
||||||
|
unsigned int i;
|
||||||
|
for (i = 0; i < h.numOffset; i++) {
|
||||||
|
const char *currentfile = filedata + h.offset[i];
|
||||||
|
...
|
||||||
|
}
|
||||||
|
...
|
||||||
|
|
||||||
|
}
|
243
docs/doc-python.txt
Normal file
243
docs/doc-python.txt
Normal file
@ -0,0 +1,243 @@
|
|||||||
|
|
||||||
|
lib3ddevil1/bindings
|
||||||
|
Python interface to C library functions of lib3ddevil1.
|
||||||
|
|
||||||
|
This component uses ctypes thus it must access a compiled .so file (internally
|
||||||
|
a .dll for Windows). The .so may be located in the top level of the library
|
||||||
|
directory or any directory in the environment variable's path.
|
||||||
|
|
||||||
|
Note that there are two categories of objects in each python interface. One is
|
||||||
|
derived from ctypes.Structure, and the other is a pythonic object. The former
|
||||||
|
is for internal use and requires knowledge of both python, C, and ctypes. The
|
||||||
|
latter is to be used by python users.
|
||||||
|
|
||||||
|
Functions and Objects
|
||||||
|
class pyPldHeader
|
||||||
|
def __init__(self, filedata = None):
|
||||||
|
parameters: file data, is a single line list of data.
|
||||||
|
|
||||||
|
This function may raise RuntimeError when it fails to initialize
|
||||||
|
based on file data.
|
||||||
|
|
||||||
|
def show(self):
|
||||||
|
This prints the contents of the object.
|
||||||
|
|
||||||
|
def getnumoffsets(self):
|
||||||
|
This returns the attribute numOffsets of a PldHeader.
|
||||||
|
See details of the C struct in doc-pld.txt.
|
||||||
|
|
||||||
|
def getoffsets(self):
|
||||||
|
This returns a pythonic list of offsets.
|
||||||
|
The offsets can be accessed via list comprehensions.
|
||||||
|
|
||||||
|
def sizeofsector(self, i):
|
||||||
|
parameter: i, an integer.
|
||||||
|
This returns the size of the i-th sector in the .pld.
|
||||||
|
|
||||||
|
If the result is -1, then specified i is out of range.
|
||||||
|
|
||||||
|
class PyTexturePack
|
||||||
|
def __init__(self, filedata):
|
||||||
|
parameters: file data, a single line list of data.
|
||||||
|
|
||||||
|
This function may raise RuntimeError when it fails to initialize
|
||||||
|
based on file data.
|
||||||
|
|
||||||
|
See details of the C struct in doc-tex.txt.
|
||||||
|
|
||||||
|
def show(self):
|
||||||
|
This prints the contents of the object.
|
||||||
|
|
||||||
|
def getbatchnumber(self):
|
||||||
|
This returns the attribute 'batchNumber'.
|
||||||
|
|
||||||
|
def getfirstbatchoffset(self):
|
||||||
|
This returns the attribute 'firstBatchOffset'.
|
||||||
|
|
||||||
|
class pyTextureBatchDescriptor:
|
||||||
|
def __init__(self, i, filedata):
|
||||||
|
parameters: i, for i-th instance of TextureBatchDescriptor.
|
||||||
|
filedata, a single line list of data.
|
||||||
|
|
||||||
|
This function may raise RuntimeError when it fails to initialize
|
||||||
|
based on file data.
|
||||||
|
|
||||||
|
See details of the C struct in doc-tex.txt.
|
||||||
|
|
||||||
|
def show(self):
|
||||||
|
This prints the contents of the object.
|
||||||
|
|
||||||
|
def getbatchidx(self):
|
||||||
|
This returns the attribute 'batchidx'.
|
||||||
|
|
||||||
|
def gethash(self):
|
||||||
|
This returns the attribute 'hash'.
|
||||||
|
|
||||||
|
def gettexnumber(self):
|
||||||
|
This returns the attribute 'texNumber'.
|
||||||
|
|
||||||
|
def gettexturesize(self):
|
||||||
|
This returns the attribute 'textureSize'.
|
||||||
|
|
||||||
|
class pyTextureBatch:
|
||||||
|
def __init__(self, i, filedata):
|
||||||
|
parameters: i, for i-th instance of TextureBatch.
|
||||||
|
file data, a single line list of data.
|
||||||
|
|
||||||
|
This function may raise RuntimeError when it fails to initialize
|
||||||
|
based on file data.
|
||||||
|
|
||||||
|
See details of the C struct in doc-tex.txt.
|
||||||
|
|
||||||
|
def gettextures(self):
|
||||||
|
This returns a pythonic list of texture data.
|
||||||
|
The textures can be accessed via list comprehensions.
|
||||||
|
|
||||||
|
class pyGeoHeader:
|
||||||
|
def __init__(self, filedata):
|
||||||
|
parameters: file data, a single line list of data.
|
||||||
|
|
||||||
|
This function may raise RuntimeError when it fails to initialize
|
||||||
|
based on file data.
|
||||||
|
|
||||||
|
See details of the C struct in doc-geo.txt.
|
||||||
|
|
||||||
|
def show(self):
|
||||||
|
This prints the contents of the object.
|
||||||
|
|
||||||
|
def getnummesh(self):
|
||||||
|
This returns the attribute 'numMesh'.
|
||||||
|
|
||||||
|
def getunknownb(self):
|
||||||
|
This returns the attribute 'unknownNumberB'.
|
||||||
|
|
||||||
|
def getunknownc(self):
|
||||||
|
This returns the attribute 'unknownNumberC'.
|
||||||
|
|
||||||
|
def getunknownd(self):
|
||||||
|
This returns the attribute 'unknownNumberD'.
|
||||||
|
|
||||||
|
def getpadding(self):
|
||||||
|
This returns the attribute 'padding'.
|
||||||
|
|
||||||
|
def getunknownoffset(self):
|
||||||
|
This returns the attribute 'unknownOffset'.
|
||||||
|
|
||||||
|
class pyMeshHeader:
|
||||||
|
def __init__(self, i, filedata):
|
||||||
|
|
||||||
|
def show(self):
|
||||||
|
This prints the contents of the object.
|
||||||
|
|
||||||
|
def getnumbatch(self):
|
||||||
|
This returns the attribute 'numBatch'.
|
||||||
|
|
||||||
|
def getnumvertex(self):
|
||||||
|
This returns the attribute 'numVertex'.
|
||||||
|
|
||||||
|
def getunknown(self):
|
||||||
|
This returns the attribute 'u'.
|
||||||
|
|
||||||
|
def getoffsetbatches(self):
|
||||||
|
This returns the attribute 'offsetBatches'.
|
||||||
|
|
||||||
|
def getflags(self):
|
||||||
|
This returns the attribute 'flags'.
|
||||||
|
|
||||||
|
class pyMesh:
|
||||||
|
def __init__(self, i, filedata):
|
||||||
|
parameters: i, for i-th instance of Mesh.
|
||||||
|
filedata, a single line list of data.
|
||||||
|
|
||||||
|
This function may raise RuntimeError when it fails to initialize
|
||||||
|
based on file data.
|
||||||
|
|
||||||
|
See details of the C struct in doc-geo.txt.
|
||||||
|
|
||||||
|
def show(self):
|
||||||
|
This prints the contents of the object.
|
||||||
|
|
||||||
|
def getbatchdata(self):
|
||||||
|
This returns the attribute 'bd'.
|
||||||
|
It is a object without methods, and it's attributes are
|
||||||
|
conventionally accessed with the '.' operator.
|
||||||
|
|
||||||
|
def getpositions(self):
|
||||||
|
This returns a pythonic list of 'positions'.
|
||||||
|
The positions can be accessed with list comprehensions.
|
||||||
|
|
||||||
|
A position is a object 'Coordinate' without methods.
|
||||||
|
The attributes are x, y, and z to be accessed with the
|
||||||
|
'.' operator.
|
||||||
|
|
||||||
|
def getnormals(self):
|
||||||
|
This returns a pythonic list of 'normals'.
|
||||||
|
The normals can be accessed with list comprehensions.
|
||||||
|
|
||||||
|
A normal is a object 'Coordinate' without methods.
|
||||||
|
The attributes are x, y, and z to be accessed with the
|
||||||
|
'.' operator.
|
||||||
|
|
||||||
|
def getuvs(self):
|
||||||
|
This returns a pythonic list of 'u'.
|
||||||
|
The UVs can be accessed with list comprehensions.
|
||||||
|
|
||||||
|
A UV has two attributes, 'u' and 'v'.
|
||||||
|
|
||||||
|
def getboneindexes(self):
|
||||||
|
This returns a pythonic list of 'bi'.
|
||||||
|
The bone indices can be accessed with list comprehensions.
|
||||||
|
|
||||||
|
A bone index is a fixed length array of 4 elements, unsigned byte.
|
||||||
|
|
||||||
|
def getboneweights(self):
|
||||||
|
This returns a pythonic list of 'bw'.
|
||||||
|
The bone weights can be accessed with list comprehensions.
|
||||||
|
|
||||||
|
A bone weight is effectively an integer in python.
|
||||||
|
|
||||||
|
Example Logic: Extract Pld's
|
||||||
|
with open("pl01.pld", "rb") as f:
|
||||||
|
data = f.read()
|
||||||
|
pld = pyPldHeader(data)
|
||||||
|
filename = "demonstrate"
|
||||||
|
i = 0
|
||||||
|
for offset in pld.getoffsets():
|
||||||
|
with open(filename + str(i), "wb") as fw:
|
||||||
|
end = offset + pld.sizeofsector(i)
|
||||||
|
chunk = data[offset:end]
|
||||||
|
fw.write(chunk)
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
Example Logic: Extract Textures from a Single Batch
|
||||||
|
with open("pl01.pld_1.txp", "rb") as f:
|
||||||
|
data = f.read()
|
||||||
|
tp = pyTexturePack(data)
|
||||||
|
filename = "texture" # part 1 of output file name
|
||||||
|
id = 0 # part 2 of output file name
|
||||||
|
# Iterate through all of the batches in the package.
|
||||||
|
for i in range(0, tp.getbatchnumber()):
|
||||||
|
# Get a batch.
|
||||||
|
tx = pyTextureBatch(i, data)
|
||||||
|
# Iterate through all textures in batch.
|
||||||
|
for texture in tx.gettextures():
|
||||||
|
with open(filename + str(id) + ".dds", "wb") as fw:
|
||||||
|
fw.write(texture)
|
||||||
|
id += 1
|
||||||
|
|
||||||
|
Example Logic: Iterate through all MeshHeaders and Meshes:
|
||||||
|
with open("pl00.pld_0", "rb") as f:
|
||||||
|
# Get data to extract from.
|
||||||
|
data = f.read()
|
||||||
|
# We want to know how many meshes are in the file.
|
||||||
|
gh = pyGeoHeader(data)
|
||||||
|
# Show each MeshHeader
|
||||||
|
for i in range(0, gh.getnummesh()):
|
||||||
|
mh = pyMeshHeader(i, data)
|
||||||
|
mh.show()
|
||||||
|
# Get each Mesh
|
||||||
|
for i in range(0, gh.getnummesh()):
|
||||||
|
m = pyMesh(i, data)
|
||||||
|
m.show()
|
||||||
|
# Whatever you do with each of them is up to you.
|
||||||
|
|
132
docs/doc-tex.txt
Normal file
132
docs/doc-tex.txt
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
|
||||||
|
devil1tex.h / devil1tex.c
|
||||||
|
Handles texture packages.
|
||||||
|
|
||||||
|
File Format
|
||||||
|
Texture packags can be identified with a string "\0 2 3 T" as a starting
|
||||||
|
tag.
|
||||||
|
|
||||||
|
Functions
|
||||||
|
All functions are static but exposed by a function pointer in a constant
|
||||||
|
struct called DEVIL1TEX. For example, clients call functions using
|
||||||
|
DEVIL1TEX.printheader(...);
|
||||||
|
|
||||||
|
|
||||||
|
void printheader(struct TexturePack*);
|
||||||
|
Prints the attributes and values of a header to standard output.
|
||||||
|
|
||||||
|
input: pointer to a TexturePack struct.
|
||||||
|
|
||||||
|
void printbatchdesc(struct TextureBatchDescriptor*);
|
||||||
|
Prints the attributes and values if a TextureBatchDescriptor to
|
||||||
|
standard output.
|
||||||
|
|
||||||
|
bool getbatchdesc(struct TextureBatchDescriptor**,
|
||||||
|
unsigned int,
|
||||||
|
const char *,
|
||||||
|
unsigned int);
|
||||||
|
Retrieves the i-th TextureBatchDescriptor from a buffer.
|
||||||
|
|
||||||
|
input:
|
||||||
|
Pointer to a pointer of TextureBatchDescriptor.
|
||||||
|
This is pass by reference of a pointer to the function.
|
||||||
|
The pointer to TextureBatchDescriptor can be NULL and will be
|
||||||
|
set to point to a region in the const char*.
|
||||||
|
|
||||||
|
unsigned int, the i-th instance of a TextureBatchDescriptor in
|
||||||
|
the const char*.
|
||||||
|
|
||||||
|
const char*, the buffer containing the whole texture pack file.
|
||||||
|
|
||||||
|
unsigned int, the size of the buffer.
|
||||||
|
|
||||||
|
output:
|
||||||
|
true when successfully retrieving a pointer to
|
||||||
|
TextureBatchDescriptor.
|
||||||
|
|
||||||
|
false when unsuccesful in retrieving a pointer to
|
||||||
|
TextureBatchDescriptor; failed checks against segmentation
|
||||||
|
faults.
|
||||||
|
When const char* (buffer) is NULL.
|
||||||
|
|
||||||
|
When the location of the TextureBatchDescriptor will exceed
|
||||||
|
the size of a buffer.
|
||||||
|
|
||||||
|
bool getbatch(struct TextureBatch**,
|
||||||
|
unsigned int,
|
||||||
|
const char*
|
||||||
|
unsigned int);
|
||||||
|
Retrieves i-th instance of a TextureBatch from a buffer.
|
||||||
|
|
||||||
|
input:
|
||||||
|
Pointer to a pointer of TextureBatch.
|
||||||
|
This is pass by reference of a pointer to the function.
|
||||||
|
The pointer to a TextureBatch can be NULL and will be set to
|
||||||
|
point to a region in the const char*.
|
||||||
|
|
||||||
|
unsigned int, the i-th instance of a TextureBatch in the
|
||||||
|
const char*.
|
||||||
|
|
||||||
|
const char*, the buffer containing the whole texture pack file.
|
||||||
|
|
||||||
|
unsigned int, the size of the buffer.
|
||||||
|
|
||||||
|
output:
|
||||||
|
true on success.
|
||||||
|
|
||||||
|
false when failing checks against segmentation faults.
|
||||||
|
When const char* is NULL.
|
||||||
|
|
||||||
|
When the location of the Texture Batch will exceed the size
|
||||||
|
of the buffer.
|
||||||
|
|
||||||
|
bool gettextures(struct Texture*,
|
||||||
|
unsigned int,
|
||||||
|
const char*,
|
||||||
|
unsigned int);
|
||||||
|
Retrieves textures of the i-th batch from a buffer.
|
||||||
|
|
||||||
|
input:
|
||||||
|
Pointer to Texture. This can be an array of Textures.
|
||||||
|
This parameter can not be NULL.
|
||||||
|
|
||||||
|
unsigned int, the i-th instance the TextureBatch containing
|
||||||
|
the files.
|
||||||
|
|
||||||
|
const char*, the buffer containing the whole texture pack file.
|
||||||
|
|
||||||
|
unsigned int, size of the buffer.
|
||||||
|
|
||||||
|
output:
|
||||||
|
true on success.
|
||||||
|
|
||||||
|
false when failing checks against segmentation faults.
|
||||||
|
|
||||||
|
Example logic to interact with all textures:
|
||||||
|
{
|
||||||
|
// After reading the file in...
|
||||||
|
// Need to know how many batches are in the package.
|
||||||
|
struct TexturePack *p = (struct TexturePack*)filedata;
|
||||||
|
|
||||||
|
// Need to know about each batch in the package.
|
||||||
|
struct TextureBatchDescriptor *d = NULL;
|
||||||
|
|
||||||
|
struct Texture *t = NULL;
|
||||||
|
|
||||||
|
unsigned int i;
|
||||||
|
for (i = 0; i < p -> batchNumber; i++) {
|
||||||
|
DEVIL1TEX.getbatchdesc(&d, i, filedata, filesize);
|
||||||
|
|
||||||
|
// Batch descriptor tells how many textures are in the batch.
|
||||||
|
t = (struct Texture*)
|
||||||
|
malloc(sizeof(struct Texture) * (d -> texNumber));
|
||||||
|
DEVIL1TEX.gettextures(t, i, filedata, filesize);
|
||||||
|
|
||||||
|
// There are now textures in 't'.
|
||||||
|
for (j = 0; j < d -> texNumber; j++) {
|
||||||
|
// Do whatever you want with however many textures there are.
|
||||||
|
}
|
||||||
|
free(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user