Important information: this site is currently scheduled to go offline indefinitely by end of the year.

IDOLM@STER One For All .pmd

Post questions about game models here, or help out others!
User avatar
shakotay2
MEGAVETERAN
MEGAVETERAN
Posts: 4291
Joined: Fri Apr 20, 2012 9:24 am
Location: Nexus, searching for Jim Kirk
Has thanked: 1150 times
Been thanked: 2243 times

Re: IDOLM@STER One For All .pmd

Post by shakotay2 »

MarieRose1301 wrote: Tue Sep 10, 2019 2:52 pm I have just gotten to try the program, it actually does work on other models as well, but with the same issue as the AMR, it won't convert meshes with few faces like eyes for example.
yeah, the byte indices don't really fit, even when I switched to backface culling in a test.
Do you think you could link me the source so I can study it? C is the only programming language I actually understand on more than surface/basic level
Pmed you.
Tuts: a) Bigchillghost, viewtopic.php?f=29&t=17889
b) Extracting simple models: http://forum.xentax.com/viewtopic.php?f=29&t=10894
"Quoting the whole thing. Would u ever stop this nonsense?"
User avatar
shakotay2
MEGAVETERAN
MEGAVETERAN
Posts: 4291
Joined: Fri Apr 20, 2012 9:24 am
Location: Nexus, searching for Jim Kirk
Has thanked: 1150 times
Been thanked: 2243 times

Re: IDOLM@STER One For All .pmd

Post by shakotay2 »

MarieRose1301 wrote: Tue Sep 10, 2019 5:42 pm I feel completely stupid right now but I have no idea how to read a number stored in 4 bytes...
dunno.PNG
bs = NoeBitStream(data, NOE_BIGENDIAN)
bs.readUInt()
Last edited by shakotay2 on Tue Sep 10, 2019 6:20 pm, edited 3 times in total.
Tuts: a) Bigchillghost, viewtopic.php?f=29&t=17889
b) Extracting simple models: http://forum.xentax.com/viewtopic.php?f=29&t=10894
"Quoting the whole thing. Would u ever stop this nonsense?"
MarieRose1301
veteran
Posts: 97
Joined: Sat Oct 11, 2014 10:29 pm
Has thanked: 17 times
Been thanked: 7 times

Re: IDOLM@STER One For All .pmd

Post by MarieRose1301 »

shakotay2 wrote: Tue Sep 10, 2019 5:52 pmsdfsdfsdf
000001B7 should be 439 right? It outputs 2 for me ;_;
User avatar
shakotay2
MEGAVETERAN
MEGAVETERAN
Posts: 4291
Joined: Fri Apr 20, 2012 9:24 am
Location: Nexus, searching for Jim Kirk
Has thanked: 1150 times
Been thanked: 2243 times

Re: IDOLM@STER One For All .pmd

Post by shakotay2 »

see my update above - works as expected
Tuts: a) Bigchillghost, viewtopic.php?f=29&t=17889
b) Extracting simple models: http://forum.xentax.com/viewtopic.php?f=29&t=10894
"Quoting the whole thing. Would u ever stop this nonsense?"
MarieRose1301
veteran
Posts: 97
Joined: Sat Oct 11, 2014 10:29 pm
Has thanked: 17 times
Been thanked: 7 times

Re: IDOLM@STER One For All .pmd

Post by MarieRose1301 »

shakotay2 wrote: Tue Sep 10, 2019 6:21 pm see my update above - works as expected
Now it gives me 3070230528 im so stupid haha xd
User avatar
Bigchillghost
double-veteran
double-veteran
Posts: 1028
Joined: Tue Jul 05, 2016 9:37 am
Has thanked: 32 times
Been thanked: 1213 times

Re: IDOLM@STER One For All .pmd

Post by Bigchillghost »

MarieRose1301 wrote: Tue Sep 10, 2019 3:47 pmI cannot load anything in noesis yet in fact as I haven't been able to code anything yet ^^"
Here's a Noesis Python script for the format.
fmt_IDOLMASTER_pmd.zip

Loading all meshes into Noesis:
Image
You do not have the required permissions to view the files attached to this post.
May you find peace in this puzzle-solving game. Say it with action: click the Image when you get helped.:)
MarieRose1301
veteran
Posts: 97
Joined: Sat Oct 11, 2014 10:29 pm
Has thanked: 17 times
Been thanked: 7 times

Re: IDOLM@STER One For All .pmd

Post by MarieRose1301 »

So I have rewritten my plugin based on the one provided by Bigchillghost, however I am having issues reading certain textures. Some work fine, but some, like normal maps and several ao and sphere maps do not, due to different pixel data sizes and compressions, for example this one(chr_comn_ran_face2.gtf from chr_head_rank_104_krn_a.pta). Could anyone take a look?
Image
You do not have the required permissions to view the files attached to this post.
MarieRose1301
veteran
Posts: 97
Joined: Sat Oct 11, 2014 10:29 pm
Has thanked: 17 times
Been thanked: 7 times

Re: IDOLM@STER One For All .pmd

Post by MarieRose1301 »

Trying to read bones, but Noesis just freezes when opening files, lol :oops:
Image
MarieRose1301
veteran
Posts: 97
Joined: Sat Oct 11, 2014 10:29 pm
Has thanked: 17 times
Been thanked: 7 times

Re: IDOLM@STER One For All .pmd

Post by MarieRose1301 »

Could anyone help?
I suspect my bone rotation and scale data isn't right, but i dont really know how to fix that
User avatar
shakotay2
MEGAVETERAN
MEGAVETERAN
Posts: 4291
Joined: Fri Apr 20, 2012 9:24 am
Location: Nexus, searching for Jim Kirk
Has thanked: 1150 times
Been thanked: 2243 times

Re: IDOLM@STER One For All .pmd

Post by shakotay2 »

very few people only can judge from a picture :D

Still freezing? See a suspisious NoeBone () line, where you shortened the params list.
(I know that's possible in C, in python, too? Just in case...)

params
noeBone = NoeBone(len(noeBones), boneName, boneMatrix, boneParentName, -1)
Tuts: a) Bigchillghost, viewtopic.php?f=29&t=17889
b) Extracting simple models: http://forum.xentax.com/viewtopic.php?f=29&t=10894
"Quoting the whole thing. Would u ever stop this nonsense?"
MarieRose1301
veteran
Posts: 97
Joined: Sat Oct 11, 2014 10:29 pm
Has thanked: 17 times
Been thanked: 7 times

Re: IDOLM@STER One For All .pmd

Post by MarieRose1301 »

shakotay2 wrote: Sun Oct 06, 2019 11:24 am very few people only can judge from a picture :D

Still freezing? See a suspisious NoeBone () line, where you shortened the params list.
(I know that's possible in C, in python, too? Just in case...)

params
noeBone = NoeBone(len(noeBones), boneName, boneMatrix, boneParentName, -1)
Tried, still the same. I shortened the param list because that's the root bone, with no parent(it doesn't even have a name), I saw some plugins with shortened param lists so i thought it might work this way xd

Code: Select all

from inc_noesis import *

import noesis
import rapi

def registerNoesisTypes():
	handle = noesis.register("The iDOLM@STER One For All Model", ".pmd")
	noesis.setHandlerTypeCheck(handle, pmdCheckType)
	noesis.setHandlerLoadModel(handle, pmdLoadModel)
    
	handle = noesis.register("The iDOLM@STER One For All Texture", ".pta")
	noesis.setHandlerTypeCheck(handle, ptaCheckType)
	noesis.setHandlerLoadRGBA(handle, ptaLoadRGBA)

	noesis.logPopup()
	return 1

NOEPY_HEADER = "PMD"

def ptaCheckType(data):
	bs = NoeBitStream(data)
	return 1

def pmdCheckType(data):

	bs = NoeBitStream(data)
	if len(data) < 3:
		return 0
	if bs.readBytes(3).decode("ASCII") != NOEPY_HEADER:
		return 0
	return 1

def ptaLoadRGBA(data, texList):
	bs = NoeBitStream(data, NOE_BIGENDIAN)
	Header = bs.readBytes(3).decode("ASCII")
	print(Header)
	bs.seek(0x5, NOESEEK_REL)
	FileCount=bs.readInt()
	print(FileCount)
	bs.seek(0x4, NOESEEK_REL)
	TextureOffsets = []
	for i in range(0, FileCount):
		TextureOffsets.append (bs.readInt())
	print(TextureOffsets)
	print(FileCount % 4)
	if(FileCount % 4 != 0):
		bs.seek((4 - FileCount % 4)*4, NOESEEK_REL)
	TextureNames = []
	Files = []
	for i in range(0, FileCount):
		TextureNames.append(bs.readBytes(128).decode("UTF-8").rstrip("\0"))
	bs = NoeBitStream(data)
	bs.setEndian(NOE_BIGENDIAN)
	bs.seek(TextureOffsets[0], NOESEEK_ABS)

	for i in range(0, FileCount):
		bs.seek(TextureOffsets[i], NOESEEK_ABS)
		bs.seek(0x6, NOESEEK_REL)
		FMT = bs.readBytes(1)
		bs.seek(0x11, NOESEEK_REL)
		NRML = bs.readBytes(1)
		print(FMT)
		print(NRML)
		bs.seek(0x7, NOESEEK_REL)
		imgWidth = bs.readShort()
		imgHeight = bs.readShort()
		print(imgWidth, "x", imgHeight)
		bs.seek(0x5C, NOESEEK_REL)
		if FMT == b'\x80':
			data = bs.readBytes(imgWidth*imgHeight)
			texFmt = noesis.NOESISTEX_DXT1
			texList.append(NoeTexture(TextureNames[i], imgWidth, imgHeight, data, texFmt))
		if FMT == b'\x40':
			data = bs.readBytes(imgWidth*imgHeight)
			texFmt = noesis.NOESISTEX_DXT3
			texList.append(NoeTexture(TextureNames[i], imgWidth, imgHeight, data, texFmt))
		if FMT == b'\00':
			data = bs.readBytes(imgWidth*imgHeight)
			texFmt = noesis.NOESISTEX_DXT5
			texList.append(NoeTexture(TextureNames[i], imgWidth, imgHeight, data, texFmt))
		if FMT == b'\00' and NRML == b'\85':
			data = bs.readBytes(imgWidth*imgHeight*4)
			data = rapi.imageDecodeRaw(data, imgWidth[0], imgHeight[0], "a8r8g8b8")
			texFmt = noesis.NOESISTEX_RGB16
			texList.append(NoeTexture(TextureNames[i], imgWidth, imgHeight, data, texFmt))
		if FMT == b'\04':
			data = bs.readBytes(imgWidth*imgHeight*4)
			texFmt = noesis.NOESISTEX_DXT5
			texList.append(NoeTexture(TextureNames[i], imgWidth, imgHeight, data, texFmt))
		if FMT == b'\x10':
			data = bs.readBytes(imgWidth*imgHeight)
			texFmt = noesis.NOESISTEX_DXT5
			texList.append(NoeTexture(TextureNames[i], imgWidth, imgHeight, data, texFmt))

	print(TextureNames)
	return 1

def pmdLoadModel(data, mdlList):

	global boneList, texList, texNameList
	boneList = []
	texList = []
	texNameList = []

	baseName = rapi.getExtensionlessName(rapi.getLocalFileName(rapi.getLastCheckedName()))
	texName = baseName
	if baseName.endswith("glamour"):
		texName = baseName[:-8]
	elif baseName.endswith("slender"):
		texName = baseName[:-8]

	bs = NoeBitStream(data, NOE_BIGENDIAN)
	bs.seek(0x10, NOESEEK_ABS) #PTR - Bone block
	BoneBlock=bs.readBytes(3).decode("UTF-8")
	print(BoneBlock)
	bs.seek(0x05, NOESEEK_REL)
	BoneCountOffset=bs.readInt()
	print(BoneCountOffset)
	BoneBlockSize = bs.readInt()
	print(BoneBlockSize)
	bs.seek(BoneCountOffset, NOESEEK_ABS)
	BoneCount=bs.readInt()
	print(BoneCount)
	bs.seek(0xE, NOESEEK_REL)
	bs.seek(8*BoneCount+42, NOESEEK_REL)
	BoneNames = []
	for i in range(0, BoneCount):
		if(i == 0):
			BoneNames.append ("ROOT")
			bs.seek(0x20, NOESEEK_REL)
			BoneParent=bs.readInt()
			BoneChild=bs.readInt()
			BoneUNK=bs.readInt()
			BoneNULL=bs.readInt()
			POS = NoeVec3.fromBytes(bs.readBytes(0xC))
			bs.seek(0x4, NOESEEK_REL)
			ROT = NoeAngles.fromBytes(bs.readBytes(0xC))
			bs.seek(0x4, NOESEEK_REL)
			SCL = NoeVec3.fromBytes(bs.readBytes(0xC))
			bs.seek(0x4, NOESEEK_REL)
			MTRX = ROT.toMat43()
			MTRX[3] = POS;
			MTRX[0][0] = SCL[0]
			MTRX[1][1] = SCL[1]
			MTRX[2][2] = SCL[2]
			Bone = NoeBone(i, BoneNames[i], MTRX, BoneParent, -1)
			boneList.append(Bone)
			bs.seek(0x9C, NOESEEK_REL)
		else:
			BoneNames.append (bs.readBytes(32).decode("UTF-8").rstrip("\0"))
			BoneParent=bs.readInt()
			BoneChild=bs.readInt()
			BoneUNK=bs.readInt()
			BoneNULL=bs.readInt()
			POS = NoeVec3.fromBytes(bs.readBytes(0xC))
			bs.seek(0x4, NOESEEK_REL)
			ROT = NoeAngles.fromBytes(bs.readBytes(0xC))
			bs.seek(0x4, NOESEEK_REL)
			SCL = NoeVec3.fromBytes(bs.readBytes(0xC))
			bs.seek(0x4, NOESEEK_REL)
			MTRX = ROT.toMat43()
			MTRX[3] = POS;
			MTRX[0][0] = SCL[0]
			MTRX[1][1] = SCL[1]
			MTRX[2][2] = SCL[2]
			Bone = NoeBone(i, BoneNames[i], MTRX, BoneParent, -1)
			boneList.append(Bone)
			if(i == BoneCount-1): #last bone is C bytes shorter
				bs.seek(0xB0, NOESEEK_REL)
			else:
				bs.seek(0xBC, NOESEEK_REL)
		
	print(BoneNames)
	MeshBlock=bs.readBytes(3).decode("UTF-8")
	print(MeshBlock)
	bs.seek(0xD, NOESEEK_REL)
	MeshCount=bs.readInt()
	print(MeshCount)
	bs.seek(MeshCount*8+8, NOESEEK_REL)
	ctx = rapi.rpgCreateContext()
	rapi.rpgSetOption(noesis.RPGOPT_BIGENDIAN, 1)
	MeshNames = []
	MaterialInfo = []
	for i in range(0, MeshCount):
		bs.seek(0x10, NOESEEK_REL)
		MeshNames.append (noeStrFromBytes(bs.readBytes(0x20), "UTF8"))

		bs.seek(0x18, NOESEEK_REL)
		VertCount = bs.readInt()

		bs.seek(4, NOESEEK_REL)
		VertSize = bs.readInt()
		FaceSize = VertSize // VertCount

		FaceIndexCount = bs.readInt()

		bs.seek(4, NOESEEK_REL)
		FaceIndexSize = bs.readInt()
		IndexSize = FaceIndexSize // FaceIndexCount

		bs.seek(0x58, NOESEEK_REL)
		MeshOffset = bs.readInt()

		bs.seek(0x84, NOESEEK_REL)
		MeshOffset += bs.tell()

		VData = bs.readBytes(VertSize)
		IndexData = bs.readBytes(FaceIndexSize)

		rapi.rpgSetName(MeshNames[i])
		rapi.rpgBindPositionBuffer(VData, noesis.RPGEODATA_FLOAT, FaceSize)
		rapi.rpgBindNormalBufferOfs(VData, noesis.RPGEODATA_SHORT, FaceSize, 0x10)
		rapi.rpgBindUV1BufferOfs(VData, noesis.RPGEODATA_HALFFLOAT, FaceSize, 0x18)
		if IndexSize == 1:
			idxType = noesis.RPGEODATA_UBYTE
		elif IndexSize == 2:
			idxType = noesis.RPGEODATA_USHORT
		else:
			idxType = noesis.RPGEODATA_INT

		rapi.rpgCommitTriangles(IndexData, idxType, FaceIndexCount, noesis.RPGEO_TRIANGLE_STRIP, 1)
		rapi.rpgClearBufferBinds()
		
		bs.seek(MeshOffset, NOESEEK_ABS)

	print(MeshNames)

	bs.seek(0x04, NOESEEK_REL)
	MaterialBlock=noeStrFromBytes(bs.readBytes(3), "UTF8")
	print(MaterialBlock)
	bs.seek(0x09, NOESEEK_REL)
	MaterialOffset=bs.readInt()
	print(MaterialOffset)
	MaterialCount=bs.readInt()
	print(MaterialCount)
	bs.seek(0xF, NOESEEK_REL)
	bs.seek(MaterialCount*8+10, NOESEEK_REL)

	bs.seek(MaterialOffset-13, NOESEEK_REL)
	TextureBlock=noeStrFromBytes(bs.readBytes(3), "UTF8")
	print(TextureBlock)
	bs.seek(0xD, NOESEEK_REL)
	TextureCount=bs.readInt()
	print(TextureCount)
	bs.seek(0xF, NOESEEK_REL)
	bs.seek(TextureCount*8+41, NOESEEK_REL)
	#textures are .gtf in a .pta file container with the same name as the model minus _glamour or _slender, no idea how to have Noesis open that file together with the model
	TextureNames = []
	for i in range(0, TextureCount):
		TextureNames.append (noeStrFromBytes(bs.readBytes(40), "UTF8") + ".gtf")
		bs.seek(0x148, NOESEEK_REL)
	print(TextureNames)

	if( rapi.checkFileExists( rapi.getDirForFilePath( rapi.getLastCheckedName() ) + texName + ".pta" ) ):
		data = rapi.loadIntoByteArray( rapi.getDirForFilePath( rapi.getLastCheckedName() ) + texName + ".pta" )
		ptaLoadRGBA(data, texList)

	mdl = rapi.rpgConstructModel()
	mdlList.append(mdl)
	return 1
User avatar
shakotay2
MEGAVETERAN
MEGAVETERAN
Posts: 4291
Joined: Fri Apr 20, 2012 9:24 am
Location: Nexus, searching for Jim Kirk
Has thanked: 1150 times
Been thanked: 2243 times

Re: IDOLM@STER One For All .pmd

Post by shakotay2 »

yeah, this line in the else: path of your bone loop makes it crash:
MTRX = ROT.toMat43()

Some ROT values are too big, I think:

Code: Select all

Detected file type: The iDOLM@STER One For All Model
PTR
32
60776
214
1 (0.0, 0.0, 0.0)
2 (0.0, 0.0, 0.0)
3 (0.0, 0.0, 0.0)
4 (0.0, 0.0, 0.0)
5 (0.0, -632378032652288.0, 0.0)
...
(Might be a matter of endianness?)

These are the bytes at 0xCB8 in the pmd, 3f c9 0f d8, that's big endian notation of a 32 bit float value.
Your script seems to switch Noesis to BigENDIAN but the output is -632378032652288.0?
(You usually get that value in case you read it as a little endian one.

(little endian (d8 0f c9 3f) would result in 1.570796, which seems to be a correct ROT value i.e. an angle in radians (180°).
But in the pmd it's big endian. :? )

Maybe better you read your matrices using POS = NoeVec3( (bs.readFloat(), bs.readFloat(), bs.readFloat()) )
for example.
Bones look funny, so you might need to recheck that:
.
bones_or_not_bones.png
You do not have the required permissions to view the files attached to this post.
Last edited by shakotay2 on Sun Oct 06, 2019 5:36 pm, edited 1 time in total.
Tuts: a) Bigchillghost, viewtopic.php?f=29&t=17889
b) Extracting simple models: http://forum.xentax.com/viewtopic.php?f=29&t=10894
"Quoting the whole thing. Would u ever stop this nonsense?"
MarieRose1301
veteran
Posts: 97
Joined: Sat Oct 11, 2014 10:29 pm
Has thanked: 17 times
Been thanked: 7 times

Re: IDOLM@STER One For All .pmd

Post by MarieRose1301 »

shakotay2 wrote: Sun Oct 06, 2019 3:50 pm yeah, this line in the else: path of your bone loop makes it crash:
MTRX = ROT.toMat43()

Some ROT values are too big, I think:

Code: Select all

Detected file type: The iDOLM@STER One For All Model
PTR
32
60776
214
1 (0.0, 0.0, 0.0)
2 (0.0, 0.0, 0.0)
3 (0.0, 0.0, 0.0)
4 (0.0, 0.0, 0.0)
5 (0.0, -632378032652288.0, 0.0)
...
(Might be a matter of endianness?)

These are the bytes at 0xCB8 in the pmd, 3f c9 0f d8, that's big endian notation of a 32 bit float value.
Your script seems to switch Noesis to BigENDIAN but the output is -632378032652288.0?
(You usually get that value in case you read it as a little endian one.

(little endian (d8 0f c9 3f) would result in 1.570796, which seems to be a correct ROT value i.e. an angle in radians (180°).
But in the pmd it's big endian. :? )

Maybe better you read your matrices using POS = NoeVec3( (bs.readFloat(), bs.readFloat(), bs.readFloat()) )
for example.
PS3 games don't usually use LittleEndian, do they?
I've tried using floats, and it does not freeze anymore, no bones pop out either though :D

Seems like at very least scales are displayed correctly now, not so sure about positions and rotations(might as well be wrong order)
Here's an extract from my log:

Code: Select all

Detected file type: The iDOLM@STER One For All Model
PTR
32
60776
214
Postition:
(1.0, 1.0, 1.0)
Rotation:
(0.0, 0.0, 0.0)
Scale:
(0.0, 0.0, 0.0)
Postition:
(0.0, 0.0, 0.0)
Rotation:
(0.0, 0.0, 0.0)
Scale:
(1.0, 1.0, 1.0)
Postition:
(0.0, 0.0, 0.0)
Rotation:
(0.0, 0.0, 0.0)
Scale:
(1.0, 1.0, 1.0)
Postition:
(-0.0, 0.0, -0.0)
Rotation:
(0.0, 0.0, 0.0)
Scale:
(1.0, 1.0, 1.0)
Postition:
(0.0, 0.0, 0.0)
Rotation:
(0.0, 0.0, 0.0)
Scale:
(1.0, 1.0, 1.0)
Postition:
(-0.0, 111.0, 0.0)
Rotation:
(0.0, 1.570796012878418, 0.0)
Scale:
(1.0, 1.0, 1.0)
Postition:
(0.0, 0.0, 0.0)
Rotation:
(0.0, 0.0, 0.0)
Scale:
(1.0, 1.0, 1.0)
Postition:
(-0.0, 0.0, -0.0)
Rotation:
(-0.0, -0.0, -0.0)
Scale:
(1.0, 1.0, 1.0)
Postition:
(9.0, 0.0, 0.0)
Rotation:
(0.0, 0.0, -0.0)
Scale:
(1.0, 1.0, 1.0)
Postition:
(15.0, 0.0, 7.0)
Rotation:
(-0.0, -0.0, -0.0)
Scale:
(1.0, 1.0, 1.0)
Postition:
(5.0, -0.0, -0.0)
Rotation:
(-7.000000096013537e-06, 0.0, 0.0)
Scale:
(1.0, 1.0, 1.0)
User avatar
shakotay2
MEGAVETERAN
MEGAVETERAN
Posts: 4291
Joined: Fri Apr 20, 2012 9:24 am
Location: Nexus, searching for Jim Kirk
Has thanked: 1150 times
Been thanked: 2243 times

Re: IDOLM@STER One For All .pmd

Post by shakotay2 »

MarieRose1301 wrote: Sun Oct 06, 2019 5:25 pm I've tried using floats, and it does not freeze anymore, no bones pop out either though :D
You need to add
mdl.setBones(boneList) before mdlList.append(mdl)

For the endianness thingie: I think readBytes(count) simply reads "byte by byte" no matter which endianness was chosen.
Tuts: a) Bigchillghost, viewtopic.php?f=29&t=17889
b) Extracting simple models: http://forum.xentax.com/viewtopic.php?f=29&t=10894
"Quoting the whole thing. Would u ever stop this nonsense?"
MarieRose1301
veteran
Posts: 97
Joined: Sat Oct 11, 2014 10:29 pm
Has thanked: 17 times
Been thanked: 7 times

Re: IDOLM@STER One For All .pmd

Post by MarieRose1301 »

shakotay2 wrote: Sun Oct 06, 2019 5:39 pm
MarieRose1301 wrote: Sun Oct 06, 2019 5:25 pm I've tried using floats, and it does not freeze anymore, no bones pop out either though :D
You need to add
mdl.setBones(boneList) before mdlList.append(mdl)

For the endianness thingie: I think readBytes(count) simply reads "byte by byte" no matter which endianness was chosen.
That's kind of weird, some bones are pretty much located where they are actually supposed to be, most of those are physical bones like neck/back/knee ribbons and skirt

Just checked again and some bones have their locations all mixed up
for example BASE bone is fine but MUNE1 is mixed up and so on

This is head, for some reason the face bones are on ground and oriented wrong, perhaps the locations arent just locations but offsets relative the parent bone: Image
Post Reply