Skip to content
Pyogenics edited this page Sep 19, 2024 · 7 revisions

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).

Alternativa protocol

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.

Research materials

Format

Optional mask

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.

Short null mask

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.

Long null mask

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.

Array

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).

Short array

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.

Long array

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).

A3D1

Oldest version of the format which uses the alternativa protocol serialisation format.

Research materials

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
};

A3D1Box

struct A3D1Box
{
    float bounds[];     // Optional
    int id;             // Optional
};

A3D1Geometry

struct A3D1Geometry
{
    int id;                             // Optional
    A3D1IndexBuffer indexBuffer;        // Optional
    A3D1VertexBuffer vertexBuffers[];   // Optional
};

A3D1Image

struct A3D1Image
{
    int id;         // Optional
    char url[];     // Optional
};

A3D1Map

struct A3D1Map
{
    short channel;  // Required
    int id;         // Optional
    int imageID;    // Optional
    float uOffset;  // Optional
    float uScale;   // Optional
    float vOffset;  // Optional
    float vScale;   // Optional
};

A3D1Material

struct A3D1Material
{
    int diffuseMapID;       // Optional
    int glossinessMapID;    // Optional
    int id;                 // Optional
    int lightMapID;         // Optional
    int normalMapID;        // Optional
    int opacityMapID;       // Optional
    int specularMapID;      // Optional
};

A3D1Object

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
};

A3D1Transform

struct A3D1Transform
{
    A3DMatrix matrix;   // Optional
};

A3D1IndexBuffer

struct A3D1IndexBuffer
{
    char byteBuffer[];  // Optional
    int indexCount;     // Required
};

A3D1VertexBuffer

struct A3D1VertexBuffer
{
    char attributes[];  // Optional
    char byteBuffer[];  // Optional
    short vertexCount;  // Required
};

attributes

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

A3D1Surface

struct A3D1Surface
{
    int indexBegin;     // Required
    int materialID;     // Optional
    int numTriangles;   // Required
};

A3D2

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

Research materials

Format

struct A3D2
{
    A3D2Package package;
};

A3D2Package

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).

Short package

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.

Long package

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.

Data

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
};

A3D2AmbientLight

A3D2AnimationClip

A3D2AnimationTrack

A3D2Box

A3D2CubeMap

A3D2Decal

A3D2DirectionalLight

A3D2Image

A3D2IndexBuffer

A3D2Joint

A3D2Map

A3D2Material

A3D2Mesh

A3D2Object

A3D2OmniLight

A3D2SpotLight

A3D2Sprite

A3D2Skin

A3D2VertexBuffer

A3D2Layer

A3D2Camera

A3D2LOD

A3D3

Proprietary format only used in the Kotlin rewrite of the Alternativa3D engine, completely different from previous versions.

Research materials

Format

struct A3D3
{

};