I don't really have the time to go reverse it entirely but if anyone is interested in doing so, I'll share my notes
Notes:
Preliminary MaxScript (Very WIP)
Notes:
Code:
// Xenoblade Chronicles X .camdo
// File is in big endian
// Offsets are relative to the start of the struct pointed to in the CamdoHeader
struct CamdoHeader
{
char[4] magic; // MXMD
u32 unk_int_0x04; // 0x2738
u32 unkStruct1Off; // 0x44
u32 unkStruct2Off; // 0x597C
u32 unk_off_0x10; // 0x6A80
u32 bufferDescriptorOff; // 0x6DA4
u32 unk_off_0x18; // 0x78400
u32 unk_off_0x1C; // 0x83400
u32 unk_int_0x20; // 0x00
u32 unk_off_0x24; // 0x6660
}
struct UnkStruct1
{
f32[6] bbox;
u32 unk_off_0x18; // 0x9C
u32 unk_int_0x1C; // 0x01
u32 unk_off_0x20; // 0xE60
u32 unk_int_0x24; // 0x01
u32[10] unk_0x28; // 0x00
u32 unk_off_0x50; // 0x3090
u32 unk_int_0x54; // 0x35
u32 unk_off_0x58; // 0xED4
u32 unk_int_0x5C; // 0x6B
u32 unk_int_0x60; // 0x00
u32 unk_off_0x64; // 0xFA8
u32 unk_int_0x68; // 0x35
u32 unk_int_0x6C; // 0x40
u32 unk_off_0x70; // 0x1288
u32 unk_int_0x74; // 0x31
u32 unk_off_0x78; // 0x1598
u32 unk_int_0x7C; // 0x30
u32[3] unk_0x80; // 0x00
}
struct UnkStruct2
{
u32 unk_off_0x00; // 0x68
u32 unk_int_0x04; // 0x05
u32 unk_int_0x08; // 0x63
u32 unk_int_0x0C; // 0x0B
u32 unk_off_0x10; // 0x310
u32 unk_int_0x14; // 0x3C
u32 unk_off_0x18; // 0x400
u32 unk_int_0x1C; // 0x0E
u32 unk_int_0x20; // 0x00
u32 unk_off_0x24; // 0x5A0
u32 unk_int_0x28; // 0x0B
u32[5] unk_0x2C; // 0x00
// might be bigger, idk
}
struct BufferDescriptor
{
u32 vertBufDescriptorArrayOffset; // 0x30
u32 numVertBuffers; // 0x04
u32 faceBufDescriptorArrayOffset; // 0x90
u32 numFaceBuffers; // 0x6B
u16 unk_int_0x10; // 0x02
u16 unk_int_0x14; // 0x03
}
struct VertBufDescriptor
{
u32 vertBufOffset;
u32 numVertices;
u32 vertStride;
u32 unkIndicesOffset;
u32 numUnkIndices;
u32 unk_int_0x14; // 0x00
}
struct FaceBufDescriptor
{
u32 faceBufOffset;
u32 numFaces;
u32 unk_0x08; // 0x00
}
Preliminary MaxScript (Very WIP)
Code:
gc()
fn GetOpenFile =
(
clearlistener()
local fname = getOpenFileName \
caption:"Open Model" \
types:"Model (*.camdo)|*.camdo" \
historyCategory:"XENBLADECHRX Object Presets"
if (fname == undefined) then
(
return undefined
)
else
(
--globalImportedFilePath = fname
local f = fopen fname "rb"
return f
)
)
-- Reading functions
fn ReadBEShort fstream =
(
return bit.swapBytes (ReadShort fstream #unsigned) 1 2
)
fn ReadBELong fstream =
(
return bit.swapBytes (bit.swapBytes (ReadLong fstream #unsigned) 1 4) 2 3
)
fn ReadBEFloat fstream =
(
return bit.intAsFloat (bit.swapBytes (bit.swapBytes (ReadLong fstream #unsigned) 1 4) 2 3)
)
fn ReadBEVector2 fstream =
(
return [(ReadBEFloat fstream), ((ReadBEFloat fstream) * -1) + 1, 0]
)
fn ReadBEVector3 fstream =
(
return [(ReadBEFloat fstream), (ReadBEFloat fstream), (ReadBEFloat fstream)]
)
struct VertBufDescriptorStruct
(
/* u32 */ vertBufOffset,
/* u32 */ numVertices,
/* u32 */ vertStride,
/* u32 */ unkIndicesArrayOffset,
/* u32 */ numUnkIndices,
/* u32 */ unk0x14
)
struct FaceBufDescriptorStruct
(
/* u32 */ faceBufOffset,
/* u32 */ numFaces,
/* u32 */ unk0x08
)
file = GetOpenFile()
if (file != undefined) then
(
fseek file 0x14 #seek_cur
bufferDescriptorOffset = ReadBELong file
fseek file bufferDescriptorOffset #seek_set
vertBufDescriptorArrayOffset = ReadBELong file
numVertexBuffers = ReadBELong file
faceBufDescriptorArrayOffset = ReadBELong file
numFaceBuffers = ReadBELong file
fseek file (bufferDescriptorOffset + vertBufDescriptorArrayOffset) #seek_set
vertDescriptorArray = #()
for i = 1 to numVertexBuffers do
(
vtxDesc = VertBufDescriptorStruct()
vtxDesc.vertBufOffset = ReadBELong file
vtxDesc.numVertices = ReadBELong file
vtxDesc.vertStride = ReadBELong file
vtxDesc.unkIndicesArrayOffset = ReadBELong file
vtxDesc.numUnkIndices = ReadBELong file
vtxDesc.unk0x14 = ReadBELong file
vertDescriptorArray[i] = vtxDesc
)
fseek file (bufferDescriptorOffset + faceBufDescriptorArrayOffset) #seek_set
faceDescriptorArray = #()
for i = 1 to numFaceBuffers do
(
faceDesc = FaceBufDescriptorStruct()
faceDesc.faceBufOffset = ReadBELong file
faceDesc.numFaces = ReadBELong file
faceDesc.unk0x08 = ReadBELong file
faceDescriptorArray[i] = faceDesc
)
posArray = #()
uvArray = #()
for i = 1 to numVertexBuffers do
(
if (vertDescriptorArray[i].vertStride == 0x10) then continue -- Weight data
for j = 1 to vertDescriptorArray[i].numVertices do
(
fseek file (bufferDescriptorOffset + vertDescriptorArray[i].vertBufOffset + ((j - 1) * vertDescriptorArray[i].vertStride)) #seek_set
append posArray (ReadBEVector3 file)
fseek file 0x04 #seek_cur
append uvArray (ReadBEVector2 file)
)
)
faceArray = #()
for i = 1 to numFaceBuffers do
(
fseek file (bufferDescriptorOffset + faceDescriptorArray[i].faceBufOffset) #seek_set
for j = 1 to faceDescriptorArray[i].numFaces/3 do
(
append faceArray [(ReadBEShort file) + 1, (ReadBEShort file) + 1, (ReadBEShort file) + 1]
)
)
msh = mesh vertices:posArray faces:faceArray tverts:uvArray
buildTVFaces msh
for j = 1 to faceArray.count do setTVFace msh j faceArray[j]
)
gc()