-
Notifications
You must be signed in to change notification settings - Fork 8
File format
There are currently 3 major version of the A3D format: A3D1, A3D2 and A3D3 which are supported by different version of the Alternativa3D engine. A3D1 and A3D2 are supported by the latest flash release of the Alternativa3D engine (8.32.0), whilst A3D3 is only supported by the proprietary Kotlin rewrite of Alternativa3D that is currently only used in the game Tanki Online (this version of the engine only support A3D3 and not A3D1 or A3D2).
The alternativa protocol is a custom binary serialisation format created by Alternativa Platforma (now Alternativa Games) to store a wide range of binary data types, it has seen use in: A3D1 3D models, A3D2 3D models and multiplayer networking.
The alternativa protocol is based around the optional mask (also called null mask), it is a data structure which allows fields to be marked as optional in the binary data stream, which allows unneeded data to be removed and ultimately reduce the total size of the data. After reading, the optional mask is interpreted as a stream of bits which can be taken as boolean values (where 0 = field is present, 1 = field is not present).
There are two types of null mask: long and short which are specified in the first byte of the nullmask.
0LL00000 [null mask data bytes]
LL | Description |
---|---|
00 | Null mask is contained in the last 5 bits of the first byte |
01 | Null mask is contained in the last 5 bits of the first byte + next byte |
10 | Null mask is contained in the last 5 bits of the first byte + next 2 bytes |
11 | Null mask is contained in the last 5 bits of the first byte + next 3 bytes |
This results in a maximum of 29 optional fields and a minimum of 5.
1L000000 [null mask length bytes] [null mask data bytes]
L | Description |
---|---|
0 | Length of the null mask (in bytes) is contained in the last 6 bits of the first byte |
1 | Length of the null mask (in bytes) is contained in the last 6 bits of the first byte + next 2 bytes |
This results in a maximum of 33554432 optional fields and a minimum of 512.
There are two types of array: short array and long array; the array is also used for strings (in which case it's just an array of characters).
00000000 [array items]
First bit is 0 and the last 7 bits contain the length of the array, resulting in a maximum of 128 array items.
1L000000 [array length bytes] [array items]
L | Description |
---|---|
0 | Length of array in the last 6 bits of the first byte + next byte |
1 | Length of array in the last 6 bits of the first byte + next 2 bytes |
This results in a maximum of 16384 array items (when L=0) or 4194304 array items (when L=1).
Oldest version of the format which uses the alternativa protocol serialisation format.
struct A3D1
{
short version; // 1
short unused; // 0
OptionalMask optionalMask;
A3D1Box boxes[]; // Optional
A3D1Geometry geometry[]; // Optional
A3D1Image images[]; // Optional
A3D1Map maps[]; // Optional
A3D1Material materials[]; // Optional
A3D1Object objects[]; // Optional
};
struct A3D1Box
{
float bounds[]; // Optional
int id; // Optional
};
struct A3D1Geometry
{
int id; // Optional
A3D1IndexBuffer indexBuffer; // Optional
A3D1VertexBuffer vertexBuffers[]; // Optional
};
struct A3D1Image
{
int id; // Optional
char url[]; // Optional
};
struct A3D1Map
{
short channel; // Required
int id; // Optional
int imageID; // Optional
float uOffset; // Optional
float uScale; // Optional
float vOffset; // Optional
float vScale; // Optional
};
struct A3D1Material
{
int diffuseMapID; // Optional
int glossinessMapID; // Optional
int id; // Optional
int lightMapID; // Optional
int normalMapID; // Optional
int opacityMapID; // Optional
int specularMapID; // Optional
};
struct A3D1Object
{
int boundBoxID; // Optional
int geometryID; // Optional
int id; // Optional
char name[]; // Optional
int parentID; // Optional
A3D1Surface surfaces[]; // Optional
A3D1Transform transform; // Optional
bool visible; // Optional
};
struct A3D1Transform
{
A3DMatrix matrix; // Optional
};
struct A3D1IndexBuffer
{
char byteBuffer[]; // Optional
int indexCount; // Required
};
struct A3D1VertexBuffer
{
char attributes[]; // Optional
char byteBuffer[]; // Optional
short vertexCount; // Required
};
The attributes
field specifies the format of each vertex inside the byteBuffer
, there can be any amount of attributes in any order. It is read as 1 byte integers which each correspond to one of the vertex types:
0 - position
1 - normal
2 - tangent
3 - joint
4 - UV1
5 - UV2
struct A3D1Surface
{
int indexBegin; // Required
int materialID; // Optional
int numTriangles; // Required
};
Newest version supported by the opensource flash Alternativa3D engine, also uses the alternativa protocol serialisation format (like A3D1). This version of the format adds zlib compression support, light objects, animation, skinning, sprites and decals as well as reducing amount of optional flags per model by properly using optional fields (only marking select fields as optional instead of most of them).
There are 4 minor versions of this format:
Version | Notes |
---|---|
2.0 | |
2.4 | aka A3DExtra1, adds A3D2Layer |
2.5 | aka A3DExtra2, adds A3D2Camera, A3D2LOD |
2.6 | Package compression is mandatory |
struct A3D2
{
A3D2Package package;
};
The A3D2 is wrapped in a compressable block called the package, it is placed at the very start of the file and begins with a length field, this is followed by a stream of bytes (size of the length field) which contains the A3D2 data (could be zlib compressed, this is encoded in the length field).
0G000000 00000000
G | Description |
---|---|
0 | Package data is not compressed |
1 | Package data is compressed |
Length of the package is contained in the last 6 bits of the first byte + the next byte, resulting in a maximum length of 16,384 bytes.
10000000 00000000 00000000 00000000
Length of the package is contained in the last 7 bits of the first byte + the next 3 bytes, resulting in a maximum length of 2147483648 bytes. Compression is assumed to be true.
The uncompressed package data stores the actual file data:
struct A3D2Package
{
OptionalMask optionalMask;
A3D2AmbientLight ambientLights[]; // Optional
A3D2AnimationClip animationClips[]; // Optional
A3D2AnimationTrack animationTracks[]; // Optional
A3D2Box boxes[]; // Optional
A3D2CubeMap cubeMaps[]; // Optional
A3D2Decal decals[]; // Optional
A3D2DirectionalLight directionalLights[]; // Optional
A3D2Image images[]; // Optional
A3D2IndexBuffer indexBuffers[]; // Optional
A3D2Joint joints[]; // Optional
A3D2Map maps[]; // Optional
A3D2Material materials[]; // Optional
A3D2Mesh meshes[]; // Optional
A3D2Object objects[]; // Optional
A3D2OmniLight omniLights[]; // Optional
A3D2SpotLight spotLights[]; // Optional
A3D2Sprite sprites[]; // Optional
A3D2Skin skins[]; // Optional
A3D2VertexBuffer vertexBuffers[]; // Optional
A3D2Layer layers[]; // Optional, 2.4 only
A3D2Camera cameras[]; // Optional, 2.5 only
A3D2LOD LODs[]; // Optional, 2.5 only
};
Proprietary format only used in the Kotlin rewrite of the Alternativa3D engine, completely different from previous versions.
struct A3D3
{
};