Merge branch 'feature/pythonbinding' of scuti/lib3ddevil1 into master

This commit is contained in:
suhrke 2018-05-19 17:42:53 -07:00 committed by Gitea
commit ee9644b5d1
14 changed files with 937 additions and 20 deletions

4
.gitignore vendored
View File

@ -1,9 +1,11 @@
# Files from compilation and tests
*.o
*.so
*.gch
*.exe
*.stackdump
*.log
devil1test
__pycache__
demo-extractpld
demo-extracttexture
demo-extractmesh

View File

@ -1,21 +1,30 @@
CC=gcc
CFLAGS=-I"include" -Wall -fPIC #-g
LDFLAGS=-shared
TARGET=lib3ddevil1.so
PEX=demo-extractpld
TEX=demo-extracttexture
MEX=demo-extractmesh
OBJ=devil1pld.o devil1tex.o devil1geo.o
CC=gcc
CFLAGS= -I"include" -Wall
all: $(TARGET) demos
$(TARGET): $(OBJ)
$(LINK.cc) $(LDFLAGS) $^ -o $@
all: pld texture mesh
pld: devil1pld.o devil1tex.o devil1geo.o
demos: pld texture mesh
pld: $(OBJ)
$(CC) $^ demo/extractpld.c $(CFLAGS) -o $(PEX)
texture: devil1pld.o devil1tex.o devil1geo.o
texture: $(OBJ)
$(CC) $^ demo/extracttexture.c $(CFLAGS) -o $(TEX)
mesh: devil1pld.o devil1tex.o devil1geo.o
mesh: $(OBJ)
$(CC) $^ demo/extractmesh.c $(CFLAGS) -o $(MEX)
devil1pld.o: src/devil1pld.c
$(CC) -c $^ $(CFLAGS)
@ -26,4 +35,4 @@ devil1geo.o: src/devil1geo.c
$(CC) -c $^ $(CFLAGS)
clean:
rm *.o $(EX) $(PEX) $(TEX) $(MEX)
rm *.o $(TARGET) $(PEX) $(TEX) $(MEX)

23
bindings/__init__.py Normal file
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()

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

View File

@ -59,10 +59,10 @@ void writemesh(const struct MeshHeader *mh,
void extractmeshes(const char *filedata,
const char *filename,
unsigned int filesize) {
if (filedata == NULL || filesize <= 0) {
struct Header *h = NULL;
if (!(DEVIL1GEO.getheader(&h, filedata))|| filesize <= 0) {
return;
}
struct Header *h = (struct Header*)filedata;
struct MeshHeader *mh = NULL;
struct Mesh m;
m.b = NULL;

View File

@ -8,10 +8,9 @@ void extracttextures(const char *filedata,
struct Texture *t = NULL;
struct TextureBatchDescriptor *d = NULL;
char * fmt = NULL;
if (filedata == NULL || filesize == 0) {
if (!(DEVIL1TEX.getheader(&p, filedata)) || filesize == 0) {
return;
}
p = (struct TexturePack*)filedata;
fmt = (char*)malloc(strlen(filename) + 3 + 4);
unsigned int i;
unsigned int j;

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.

View File

@ -85,6 +85,9 @@ typedef struct {
// input: pointer to struct
void (* const printcoordinate)(struct Coordinate*, unsigned int);
// input: pointer to struct, file data
bool (* const getheader) (struct Header**, const char*);
// input: pointer of pointer to struct, order, file data
// ** = 'pass by reference' of a pointer to struct
bool (* const getmeshheader) (struct MeshHeader**,
@ -96,11 +99,11 @@ typedef struct {
unsigned int offset,
const char * const);
// input: pointer to struct, order, file data
// input: pointer to struct, order, file data, file size
bool (* const getmesh) (struct Mesh*,
unsigned int i,
const char*,
unsigned int filesize);
unsigned int);
} fn_devil1geo;
extern fn_devil1geo const DEVIL1GEO;

View File

@ -45,6 +45,9 @@ typedef struct {
// input: pointer to struct
void (* const printbatchdesc)(struct TextureBatchDescriptor*);
// input: pointer to struct, file data
bool (* const getheader) (struct TexturePack**, const char*);
// input: pointer of pointer to struct, order, file data, file size
// ** = 'pass by reference' of a pointer to struct
bool (* const getbatchdesc) (struct TextureBatchDescriptor**,

View File

@ -9,6 +9,7 @@ static void printmeshbatch(struct Batch*);
static void printcoordinate(struct Coordinate*, unsigned int);
static bool getgheader(struct Header**, const char*);
static bool getmeshheader(struct MeshHeader**, unsigned int i, const char * const);
@ -20,6 +21,7 @@ fn_devil1geo const DEVIL1GEO = {printgheader,
printmeshheader,
printmeshbatch,
printcoordinate,
getgheader,
getmeshheader,
getmeshbatch,
getmesh};
@ -74,14 +76,22 @@ static void printcoordinate(struct Coordinate *p, unsigned int count) {
}
}
static bool getgheader(struct Header** h, const char* filedata) {
if (filedata == NULL) {
return false;
}
(*h) = (struct Header*)filedata;
return true;
}
static bool getmeshheader(struct MeshHeader **hs,
unsigned int i,
const char * const filedata) {
bool done = false;
if (hs == NULL || filedata == NULL) {
bool done = false;
struct Header *h = NULL;
if (hs == NULL || !(getgheader(&h, filedata))) {
return done;
}
struct Header *h = (struct Header*)filedata;
if (h -> numMesh < i) {
return done;
}

View File

@ -8,8 +8,10 @@ static void printtph(struct TexturePack*);
// Print Texture Batch Descriptor.
static void printtbd(struct TextureBatchDescriptor*);
// Get Texture Batch Descriptor.
// Get Texture Pack Header
static inline bool getpackheader(struct TexturePack**, const char*);
// Get Texture Batch Descriptor.
static bool gettexdescriptor(struct TextureBatchDescriptor**,
unsigned int,
const char *,
@ -30,6 +32,7 @@ static bool unpacktexbatch(struct Texture*,
fn_devil1tex const DEVIL1TEX = {printtph,
printtbd,
getpackheader,
gettexdescriptor,
gettexbatch,
unpacktexbatch};
@ -55,6 +58,14 @@ static void printtbd(struct TextureBatchDescriptor *bd) {
}
}
inline static bool getpackheader(struct TexturePack** p, const char *filedata) {
if (filedata == NULL) {
return false;
}
(*p) = (struct TexturePack*)filedata;
return true;
}
static bool gettexdescriptor(struct TextureBatchDescriptor **descriptor,
unsigned int i,
const char *filedata,
@ -75,10 +86,9 @@ static bool gettexbatch(struct TextureBatch **batch,
const char *filedata,
unsigned int filesize) {
struct TexturePack *p = NULL;
if (filedata == NULL) { // no data to get batch from.
if (!(getpackheader(&p, filedata))) {
return false;
}
p = (struct TexturePack*)filedata;
if (i > p -> batchNumber) { // no such batch in texture pack
return false;
}