FBXProperty.typecode 에 따라, stream
에서 FBX 파일을 읽고 FBXProperty.data 를 초기화시킵니다. 결과를 담을 FBXProperty
는 out
입니다. 항상 생성자 FBXProperty() 에서 호출되며, 직접 호출하는 일은 없습니다.
FBXProperty.readPrimitive(stream, dataType, out)
FBXProperty.readArray(stream, dataType, out)
FBXProperty.readString(stream, dataType, out)
FBXProperty.readRawData(stream, dataType, out)
stream
FBX 파일을 읽기 위해 생성한 FileStream.
dataType
배열의 원소의 데이터 형식을 명시하는 DataType
열거형. readPrimitive()
, readArray()
함수에서 사용되며, typecode
에 따라 넘겨야하는 값은 아래와 같습니다:
DataType.Int16
— 2 byte signed Integer. typecode = Y
DataType.Int8
— 1 bit boolean (1: true, 0: false). typecode = C/b
DataType.Int32
— 4 byte signed Integer typecode = I/i
DataType.Float
— 4 byte signle-precision IEEE 754 number. typecode = F/f
DataType.Double
— 8 byte double-precision IEEE 754 number. typecode = D/d
DataType.Int64
— 8 byte signed Integer typecode = L/l
DataType.Uint8
— String/raw binary data typecode = S/R
out
결과를 담을 FBXProperty
.
(none)
Typecode
문자를 읽고 나면, FBXProperty
의 자료형을 알 수 있게 됩니다. 원시 자료형(Primitive Type), 배열 타입(Array type), 특별한 타입(Special type)이 존재합니다:
Primitive Types
Y
: 2 byte signed IntegerC
: 1 bit boolean (1: true, 0: false) encoded as the LSB of a 1 Byte value.I
: 4 byte signed IntegerF
: 4 byte single-precision IEEE 754 numberD
: 8 byte double-precision IEEE 754 numberL
: 8 byte signed Integer원시 자료형(primitive scalar type)들은 항상 little-endian 바이트 순서로 저장되어있습니다. 즉 typecode = I
라면, stream.read(DataType.Uint32, true)
처럼 읽으면 된다는 의미입니다. 이 과정을 수행하는 것이 FBXProperty.readPrimitive()
함수입니다.
Array types
f
: Array of 4 byte single-precision IEEE 754 numberd
: Array of 8 byte double-precision IEEE 754 numberl
: Array of 8 byte signed Integeri
: Array of 4 byte signed Integerb
: Array of 1 byte Booleans (always 0 or 1)배열 자료형(Array type)들을 읽기 전에, 먼저 배열의 길이(ArrayLength)와 인코딩 여부(Encoding), 압축된 배열의 크기(CompressedLength)에 대한 정보가 주어집니다:
Size (Bytes) Data Type Name
------------- ----------- ---------------
4 Uint32 ArrayLength
4 Uint32 Encoding
4 Uint32 CompressedLength
? ? Contents
Encoding == 0
이라면, Contents
는 압축이 되어 있지 않기에, 단순히 sizeof(dataType) * ArrayLength
크기의 byte 들을 읽어주면 됩니다. 이때 읽고 있던 ArrayBuffer
를 공유할 수는 없으며, 항상 새로운 ArrayBuffer
를 생성하여 복사해야 합니다. 이는 메모리 정렬 때문입니다. 예를 들어 배열을 읽고 나서 Uint32Array
으로 변환하기 위해서는, ArrayBuffer.byteOffset
이 반드시 4 의 배수이어야 하기 때문입니다.
Encoding == 1
이라면, Contents
는 deflate/zip 알고리즘으로 압축되어 있으며, CompressedLength
크기의 byte 들을 읽어주어야 합니다. 압축을 풀기 위해서 inflate() 함수를 호출해야 합니다. 압축을 해제하고 나서의, 원본 배열의 크기는 sizeof(dataType) * ArrayLength
처럼 구할 수 있으므로, 불필요한 버퍼의 재할당을 방지하기 위해 미리 할당합니다:
const arrayLength = stream.read(DataType.Uint32);
const encoding = stream.read(DataType.Uint32);
const compressedLength = stream.read(DataType.Uint32);
const byteLength = arrayLength * sizeof(dataType);
if(encoding == 0) {
out.data = new Uint8Array(byteLength);
for(let i=0; i<byteLength; ++i) {
out.data[i] = stream.read(DataType.Uint8);
}
}
else {
out.data = new Uint8Array(byteLength);
inflate(new BitStream(stream), out.data);
}
이후 읽어들인 Uint8Array
를 typecode
에 따라 Float32Array
| Float64Array
| BitInt64Array
| Int32Array
로 변환합니다. 이 과정을 수행하는 것이 FBXProperty.readArray()
함수입니다.
Special types
S
: StringR
: raw binary data