I tested the sample files you sent with my 010 template and it worked perfectly.
The only problem is that it's been almost 2 years since i touched this so I have forgotten what some of the data types mean but i got your UVs
Here is the c# version of the data structures (using unity3d)
Code: Select all
using UnityEngine;
using System;
using System.Collections.Generic;
namespace XBM
{
//Helper Classes
public struct XBMHeader
{
public uint ID; //00 20 00 00 - Package type (in your game it is different)
public uint lightCount;
public uint otherCount; //mesh? group?
public uint shapeCount;
//------------Line 2---------------
public uint other2Count;
public uint[] addrs; //12
public uint triangleSize;
public uint shdAddr; //ShaderAddress
public uint unkn3;
}
public struct KengoLight
{
public char[] name; //[32];
public float []f0; //[20]
public char[] data; //[144];
}
public struct Other //Bone?
{
public char[] name; //[32];
public int[] unkn; //[8];
public char[] data; //[128];
} //other[header.otherCount]
public struct Other2 //Bone?
{
public char[] data;
}
public struct Shape
{
public char[] name; //[32];
public float[] matrix1; //[16];
//public Vector3[] bbox; //[8];
public Bounds bBox;
public float[] chnk1; //[4];
public struct Header
{
public int vertCount; //or id
public int dataType; //0,5,7
public int unitSize; //Has to do with read size
public int totalSize; //floatCount or datatsize(float size* 3 or 4)
} //header0[3]
public Header hUVs;
public Header hVerts;
public Header hNorms;
public struct UnknStruct00
{
public int i0;
public int i1;
public int i2;
public int i3;
public int i4;
public int i5; //Constant -65536
public int i6;
public int i7; //268435554, 268435746, 268435458
}
public UnknStruct00[] sChnk; //[3];
public int addrUV; //0 = -1s
public int addrVerts; //1 = vertices floats
public int addrTriStr; //2 = faces? shorts?
public int addr0; //3 = addr in un02 hdr(size,size,0,size)?
//------------below are weird ints at the bottom of un03
public int addrSkVertices;// Verts for skinned mesh
public int addrSkNormals; // norms for skinned mesh or bone weights
public int addrSkWeights;
public int[] chunk3; //[33];
}
public struct Addr0
{
public uint count;
public uint size;
public int unkn0;
public int unkn1;
public struct Data
{
public Vector3 pos;
public Vector3 rot;
public Vector3 scale;
//skip 332
public const int SKIP0 = 332;
public uint size;
public uint addr;
public const int SKIP1 = 124;
}
public Data[] data;
//float[] f; //[(hdr.size-64)/4];
}
public struct Addr1 //Skin Verts
{
public struct Header
{
public uint id;
public uint fileSize;
//convert to size
public uint offset0; //ints
public uint offset1; //float[4]s
public uint offset2; //ints
public uint[] pad; //Pad to next line
}
public Header hdr;
public int[] i0; //[(hdr.addr1-hdr.addr0)/4];
public Vector4[] vec4; //[(hdr.addr2-hdr.addr1)/16];
public int[] i1; //[(hdr.fileSize - hdr.addr2 + hdr.addr0 -32 )/4];
}
public struct Addr1_2 //Skin Verts and normal (addr1 and addr2
{
public struct Header
{
public uint id;
public uint unkn0;
public uint unkn1;
public uint size;
} //hdr <bgcolor=cLtGray>;
public Header hdr;
public Vector4[] vec4; //[hdr.size/16] <bgcolor=cLtBlue>;
//float f[hdr.size/4];
}
public struct XBM_UN03
{
public struct UN03_Header
{
public uint id;
public uint count0;
public uint zero;
public uint count1;
//Chunk0
public uint addr;
//TRS
public uint[] transforms; //[3]; Addresses
//Matrices
public uint[] matrices; //[3]; Addresses
public uint[] unkn; //[5];
}
public UN03_Header un03_Hdr;
public struct Item
{
//160
public char[] name; //[32];
public char[] data; //[128];
}
public Item[] item; //[un03_Hdr.count0];
public Vector4[] pos; //[un03_Hdr.count0];
public Vector4[] rot; //[un03_Hdr.count0];
public Vector4[] scale; //[un03_Hdr.count0];
public struct Mat4x4
{
public Vector4 v0, v1, v2, v3;
}
public Mat4x4[] matrix0; //[un03_Hdr.count0];
public Mat4x4[] matrix1; //[un03_Hdr.count0];
public Mat4x4[] matrix2; //[un03_Hdr.count0];
}
public struct Un04_09 //packs of 32
{
/*
public struct Pack
{
uint id;
float []data; //7
}
*/
//shape related
// 0 - might be an id/int or 2 shorts
public float[] un04; //[(header.addrs[5]-header.addrs[4])/4];
public float[] un05; //[(header.addrs[6]-header.addrs[5])/4];
public float[] un06; //[(header.addrs[7]-header.addrs[6])/4]; //shape related
public float[] un07; //[(header.addrs[8]-header.addrs[7])/4]; //shape related
public float[] un08; //[(header.addrs[9]-header.addrs[8])/4]; //shape related
public float[] un09; //[(header.addrs[10]-header.addrs[9])/4]; //shape related
}
public class KengoXBM
{
public XBMHeader xbmHeader;
public Other[] other; //other[header.otherCount]
public Shape[] shape; //[header.shapeCount]
//public Un02 un02; // if((header.addrs[3]-header.addrs[2]) > 0)
public XBM_UN03 un03; //if((header.addrs[4]-header.addrs[3]) > 0)
public Un04_09 un04_09;
//un10 is best not read as it is just a data dump
//un11 is padding
//un12 is shaders
}
}
(You can find the UV address in the ShapeHeader struct)
There are 3 types of uv and they have a mixture of float32 float16 or random -1 separators
You will need to use the "Header hUVs;" to decipher its format
Code: Select all
//From my XBM reader
public struct UVContainer
{
public List<Vector2> UVs0;
public List<Vector2> UVs1;
public List<Vector2> UVs2;
public Vector2[] GetUVs()
{
return UVs0 != null? UVs0.ToArray() : null;
}
}
/// <summary>
///
/// </summary>
/// <param name="reader"></param>
/// <param name="hUV"></param>
/// <param name="uvC"></param>
/// <param name="flipVertical"></param>
void ReadUVChunk(BinaryReader reader, Shape.Header hUV, out UVContainer uvC, bool flipVertical = true)
{
List<Vector2> UVs0 = new List<Vector2>();
List<Vector2> UVs1 = new List<Vector2>();
List<Vector2> UVs2 = new List<Vector2>();
Byte[] bytes;
uvC = new UVContainer();
switch (hUV.dataType)
{
case 0:
for (int i = 0; i < hUV.vertCount; ++i)
{
UVs0.Add(Vector2.zero);
}
break;
case 14:
for (int i = 0; i < hUV.vertCount; ++i)
{
//bytes = reader.ReadBytes(4); //White? 0xFFFF
reader.BaseStream.Position += 4;
bytes = reader.ReadBytes(2);
Array.Reverse(bytes);
float x = BitConverter.ToInt16(bytes, 0).HalfFloat();
bytes = reader.ReadBytes(2);
Array.Reverse(bytes);
float y = BitConverter.ToInt16(bytes, 0).HalfFloat() * (flipVertical? -1:1);
UVs0.Add(new Vector2(x, y));
}
break;
case 15:
for (int i = 0; i < hUV.vertCount; ++i)
{
//bytes = reader.ReadBytes(4); //White? 0xFFFF
reader.BaseStream.Position += 4;
bytes = reader.ReadBytes(2);
Array.Reverse(bytes);
float x = BitConverter.ToInt16(bytes, 0).HalfFloat();
bytes = reader.ReadBytes(2);
Array.Reverse(bytes);
float y = BitConverter.ToInt16(bytes, 0).HalfFloat() * (flipVertical ? -1 : 1);
UVs0.Add(new Vector2(x, y));
bytes = reader.ReadBytes(2);
Array.Reverse(bytes);
x = BitConverter.ToInt16(bytes, 0).HalfFloat();
bytes = reader.ReadBytes(2);
Array.Reverse(bytes);
y = BitConverter.ToInt16(bytes, 0).HalfFloat() * (flipVertical ? -1 : 1);
UVs1.Add(new Vector2(x, y));
}
break;
case 16:
for (int i = 0; i < hUV.vertCount; ++i)
{
//bytes = reader.ReadBytes(4); //White? 0xFFFF
reader.BaseStream.Position += 4;
bytes = reader.ReadBytes(2);
Array.Reverse(bytes);
float x = BitConverter.ToInt16(bytes, 0).HalfFloat();
bytes = reader.ReadBytes(2);
Array.Reverse(bytes);
float y = BitConverter.ToInt16(bytes, 0).HalfFloat() * (flipVertical ? -1 : 1);
UVs0.Add(new Vector2(x, y));
bytes = reader.ReadBytes(2);
Array.Reverse(bytes);
x = BitConverter.ToInt16(bytes, 0).HalfFloat();
bytes = reader.ReadBytes(2);
Array.Reverse(bytes);
y = BitConverter.ToInt16(bytes, 0).HalfFloat() * (flipVertical ? -1 : 1);
UVs1.Add(new Vector2(x, y));
bytes = reader.ReadBytes(2);
Array.Reverse(bytes);
x = BitConverter.ToInt16(bytes, 0).HalfFloat();
bytes = reader.ReadBytes(2);
Array.Reverse(bytes);
y = BitConverter.ToInt16(bytes, 0).HalfFloat() * (flipVertical ? -1 : 1);
UVs2.Add(new Vector2(x, y));
}
break;
default:
if(enableLoging) log += "Unknown UV data type" + hUV.dataType;
Debug.LogError("Unknown UV data type" + hUV.dataType);
return;
}
uvC.UVs0 = UVs0;
uvC.UVs1 = UVs1;
uvC.UVs2 = UVs2;
}
//Half float converter
public static float HalfFloat(this short hbits)
{
int mant = hbits & 0x03ff; // 10 bits mantissa
int exp = hbits & 0x7c00; // 5 bits exponent
if (exp == 0x7c00) // NaN/Inf
exp = 0x3fc00; // -> NaN/Inf
else if (exp != 0) // normalized value
{
exp += 0x1c000; // exp - 15 + 127
if (mant == 0 && exp > 0x1c400) // smooth transition
return BitConverter.ToSingle(BitConverter.GetBytes((hbits & 0x8000) << 16
| exp << 13 | 0x3ff), 0);
}
else if (mant != 0) // && exp==0 -> subnormal
{
exp = 0x1c400; // make it normal
do
{
mant <<= 1; // mantissa * 2
exp -= 0x400; // decrease exp by 1
} while ((mant & 0x400) == 0); // while not normal
mant &= 0x3ff; // discard subnormal bit
} // else +/-0 -> +/-0
return BitConverter.ToSingle(
BitConverter.GetBytes( // combine all parts
(hbits & 0x8000) << 16 // sign << ( 31 - 15 )
| (exp | mant) << 13), 0); // value << ( 23 - 10 )
}