Merge branch 'python/finalize' of scuti/lib3ddevil1 into feature/pythonbinding

This commit is contained in:
suhrke 2018-05-19 17:36:52 -07:00 committed by Gitea
commit 182567a634
13 changed files with 1231 additions and 549 deletions

View File

@ -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)

View File

@ -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

View File

@ -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
View 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()

View File

@ -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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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);
}
}