O
O is a file extension in EA Sports games which is used for model and animation files. The file itself has an ELF structure. EA used their own code for ELF reading.
The file may contain model (geometry) data, skeleton information, animations, rendering information, effects (shaders) and embedded textures.
Games[edit | edit source]
O files were used mostly in games developed by EA Vancouver, between 1999 and 2009.
Elf File Structure[edit | edit source]
The overall file structure is following (the order of sections might be different, but for most files it is same):
- Elf Header (52 bytes)
- .data section data (Data section)
- .shstrtab section data (Section names table)
- .strtab section data (Symbol names table)
- .symtab section data (Symbol table)
- .rel.data section data (Relocation table)
- Section descriptions (section header table)
Each block is aligned by 16 bytes.
Header[edit | edit source]
The file starts with ELF header:
| Data type | Name | Value |
|---|---|---|
| UINT8[16] | e_ident | 7F 45 4C 46 01 01 01 00 00 00 00 00 00 00 00 00 |
| UINT16 | e_type | ET_REL (1) |
| UINT16 | e_machine | EM_MIPS (8) |
| UINT32 | e_version | EV_CURRENT (1) |
| UINT32 | e_entry | 0 |
| UINT32 | e_phoff | 0 |
| UINT32 | e_shoff | sections offset - different for each file |
| UINT32 | e_flags | 546455552 |
| UINT16 | e_ehsize | 52 (size of this header) |
| UINT16 | e_phentsize | 0 |
| UINT16 | e_phnum | 0 |
| UINT16 | e_shentsize | 40 (size of section header entry) |
| UINT16 | e_shnum | 6 (number of sections) |
| UINT16 | e_shstrndx | index of .shstrtab section (section with section names) |
Sections[edit | edit source]
There are 6 sections in the Elf File. Information about each section is stored in section table header.
Null section[edit | edit source]
| Attribute | Value |
|---|---|
| s_name | SHN_UNDEF |
| s_type | SHT_NULL (0) |
| s_flags | SF32_None (0) |
| s_addr | 0 |
| s_offset | 0 |
| s_size | 0 |
| s_link | 0 |
| s_info | 0 |
| s_addralign | 0 |
| s_entsize | 0 |
Inactive section.
Data section[edit | edit source]
| Attribute | Value |
|---|---|
| s_name | .data |
| s_type | SHT_PROGBITS (1) |
| s_flags | SF32_Alloc_Exec (3) |
| s_addr | 0 |
| s_offset | 64 |
| s_size | different for each file |
| s_link | 0 |
| s_info | 0 |
| s_addralign | 16 |
| s_entsize | 0 |
Objects data is stored in this section.
Section names table[edit | edit source]
| Attribute | Value |
|---|---|
| s_name | .shstrtab |
| s_type | SHT_STRTAB (3) |
| s_flags | SF32_None (0) |
| s_addr | 0 |
| s_offset | different for each file |
| s_size | 48 |
| s_link | 0 |
| s_info | 0 |
| s_addralign | 1 |
| s_entsize | 0 |
6 null-terminated strings, names for each section. The local offset of the name (relative to table start) is stored in each section header (s_name value). The table consists of following strings (the order may differ):
(empty) .data .shstrtab .strtab .symtab .rel.data
Symbol names table[edit | edit source]
| Attribute | Value |
|---|---|
| s_name | .strtab |
| s_type | SHT_STRTAB (3) |
| s_flags | SF32_None (0) |
| s_addr | 0 |
| s_offset | different for each file |
| s_size | different for each file |
| s_link | 0 |
| s_info | 0 |
| s_addralign | 1 |
| s_entsize | 0 |
A table of null-terminated strings for symbol names.
Symbol table[edit | edit source]
| Attribute | Value |
|---|---|
| s_name | .symtab |
| s_type | SHT_SYMTAB (2) |
| s_flags | SF32_None (0) |
| s_addr | 0 |
| s_offset | different for each file |
| s_size | different for each file |
| s_link | .strtab section index (section index with symbol names) |
| s_info | unknown flag (2 for regular files, 6 for eaglrm) |
| s_addralign | 4 |
| s_entsize | 16 |
Table of symbols. Each symbol is represented with 16-byte structure:
| Data type | Name | Value | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| UINT32 | st_name | Local offset to name in string table | ||||||||||||
| UINT32 | st_value | Symbol value (data offset or 0 if there's no data) | ||||||||||||
| UINT32 | st_size | Value (data) size (4 for pointer) | ||||||||||||
| UINT4 | st_info_type |
| ||||||||||||
| UINT4 | st_info_bind |
| ||||||||||||
| UINT8 | st_other | Value (data) type | ||||||||||||
| UINT16 | st_shndx | Index of section where the value (data) is located (if not a global symbol) |
Symbol names which start with __ prefix and also contain ::: substring, are translated to ObjectType-VariableName pair:
__ObjectType:::VariableName
Relocation table[edit | edit source]
| Attribute | Value |
|---|---|
| s_name | .rel.data |
| s_type | SHT_REL (9) |
| s_flags | SF32_None (0) |
| s_addr | 0 |
| s_offset | different for each file |
| s_size | different for each file |
| s_link | .symtab section index (section with symbols) |
| s_info | .data section index (section with data) |
| s_addralign | 4 |
| s_entsize | 8 |
Table with relocation information. Each relocation is represented with 8-byte structure:
| Data type | Name | Value | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| UINT32 | r_offset | offset in s_info section | ||||||||||||
| UINT8 | r_info_type | relocation type:
In FIFA Manager files, only type "2" is used. The "base" argument depends on symbol type. | ||||||||||||
| UINT24 | r_info_sym | symbol index in symbols table |
Objects[edit | edit source]
Objects can be obtained by symbols in the ELF symbol table or by pointers in other objects.
Objects structure may differ on different platforms (PC, PS2, XBOX). This part of article shows file structure for PC files.
Model[edit | edit source]
| Object name | Size | Visible |
|---|---|---|
| Model | 0xE0 | Yes |
Model is a set of layers which determine which geometry data must be rendered. An .o file may contain several model instances.
OFFSET Variables (points to an array of Variable) UINT32 Number of variables UINT32 Total instances (variations) count (usually 1; 25 for player model; 4 for corner flags) MATRIX4X4 Transformation matrix (always an identity matrix) VECTOR4 Rough bounding corner 1 (2x next one, W component is 1) - probably unused VECTOR4 Rough bounding corner 2 (W component is 0) - probably unused VECTOR4 Bounding min (W component is 1) VECTOR4 Bounding max (W component is 1) VECTOR3 Cull sphere center FLOAT Cull sphere radius UINT32 Groups count OFFSET Groups names (points to an array of pointers to null-terminated strings) UINT32 unknown1 (always 0) OFFSET unknown2 (always 0) OFFSET unknown3 (always 0) OFFSET Next model (always 0) OFFSET Model name (points to null-terminated string) OFFSET Interleaved vertices information (points to InterleavedVertices) OFFSET Textures (points to ModelTextures) UINT32 Instance index (variation ID) OFFSET Group states (points to GroupStates) BOOL32 Is model renderable (always 1) OFFSET Groups (points to Groups) OFFSET Model "patch" (points to EAGL::Variation object, used to change values/offsets in mode struct? Always 0) OFFSET Morph pointer (runtime, always 0) UINT32 Animation version (for files with skeleton; might be 0, 49370 (0xC0DA), 60007 (0xEA67) or other value) UINT32 Current frame number (always 0)
BBOX[edit | edit source]
Simply a bounding box.
| Object name | Size | Visible |
|---|---|---|
| BBOX | 0x18 | Yes |
VECTOR3 Min VECTOR3 Max
RenderMethod[edit | edit source]
| Object name | Size | Visible |
|---|---|---|
| RenderMethod | 0x34 | Yes |
Stores an information about data rendering.
OFFSET Code block (points to where the code starts - usually geoprimdatabuffer+4) OFFSET Used code block - array of pointers to code blocks for each selected technique (runtime, always 0) OFFSET EAGL MicroCode (points to EAGLMicroCode object) OFFSET Effect (runtime, always 0) OFFSET Parent render method (points to RenderMethod objects) OFFSET Parameter names (always 0) UINT32 unknown2 (always 0) INT32 unknown3 (always -1) OFFSET unknown4 (always 0) OFFSET Geometry data buffer (points to geoprimdatabuffer object) INT32 Index of command with computation index as global argument (-1 if command is not present) OFFSET Effect name (points to null-terminated string) OFFSET EAGL Model object (runtime, always 0)
EAGLMicroCode[edit | edit source]
| Object name | Size | Visible |
|---|---|---|
| EAGLMicroCode | Dynamic | Yes |
Represents an effect (shader).
UINT32 number of techniques UINT32 section type (always 0 - Effect) UINT32 number of vertex shader declarations #FOR number of vertex shader declarations UINT32 vertex shader declaration #END FOR UINT32 number of techniques implementations #FOR number of techniques implementations UINT32 section type (always 1 - Technique) UINT32 tecnique type (0-4) UINT32 number of Sampler assignments UINT32 number of GeoPrimState assignments #FOR total number of state assignments UINT32 state assignment type CHAR[] state assignment data (see Stage Assignments) #END FOR UINT32 number of passes #FOR number of passes UINT32 section type (always 2 - Pass) UINT32 number of Sampler assignments UINT32 number of GeoPrimState parameter assignments UINT32 unknown (always 548, 548 is a size of TextureStageState struct) #FOR total number of state assignments + 3 UINT32 state assignment type CHAR[] state assignment data (see Stage Assignments) #END FOR #END FOR #END FOR
Each technique may contain a different number of implementation. For each technique type the game will select the first technique implementation which is compatible with user hardware. For example, if we have 3 techniques (number of techniques = 3), the layout of effect might be the following (number of techniques = 7):
Technique #1 - tecnique type 0 implementation 1 Technique #2 - tecnique type 0 implementation 2 Technique #3 - tecnique type 0 implementation 3 Technique #4 - tecnique type 1 implementation 1 Technique #5 - tecnique type 1 implementation 2 Technique #6 - tecnique type 2 implementation 1 Technique #7 - tecnique type 2 implementation 2
Usually the first implementation of technique is the most advanced one, and following implementations are simplified.
The meaning of technique types is different in different games.
Effect pass always contain at least 3 state assignments - VertexShaderState (or Vertex Shader Reference), PixelShaderState and TextureStageState.
Vertex Shader Declaration[edit | edit source]
UINT8 index UINT8 unknown (0) UINT8 data type (see Data types) UINT8 type (0x20 - vertex stream, 0x40 - vertex element, 0xFF - end of declaration)
Data types[edit | edit source]
0 - UBYTE4 COLOR1 1 - FLOAT2 TEXCOORDX (X - occurance index) 2 - FLOAT3 (first occurance - POSITION, second - NORMAL) 3 - FLOAT4 POSITION 4 - D3DCOLOR COLOR0
Stage Assignments[edit | edit source]
| Type | Name | Size | Data | ||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 3 | Sampler | 8 |
| ||||||||||||||||||||||||||||
| 4 | TextureStageState | 548 |
| ||||||||||||||||||||||||||||
| 5 | GeoPrimStateAssignment | 8 |
| ||||||||||||||||||||||||||||
| 6 | VertexShaderState | Dynamic | Vertex shader code.
| ||||||||||||||||||||||||||||
| 7 | PixelShaderState | Dynamic | Pixel shader code.
| ||||||||||||||||||||||||||||
| 8 | VertexShaderStateReference | Dynamic | Uses previously created vertex shader. "size" is always 1. "data" is unknown value (example: 66, 86, 322, 326, 338, 342, 598)
|
Groups[edit | edit source]
| Object name | Size | Visible |
|---|---|---|
| Unknown | Dynamic | No |
Stores a list of model groups.
Version 3 and later
OFFSET Unknown (0) #FOR number of groups in model UINT32 number of meshes #FOR number of meshes OFFSET mesh (points to Mesh) #END FOR #END FOR
Version 2 and earlier
In version 2 and earlier, model groups is a list of descriptors:
UINT32 id (0xA0000000 - start descriptor, 0xA0000001 - group descriptor, 0xA000FFFF - mesh descriptor #IF id is 0xA000FFFF OFFSET mesh (points to Mesh) #ELSE UINT32 unknown1 (0) #IF id is 0xA0000000 UINT32 group and mesh descriptors size (number of groups * 2 + total number of meshes * 2) #ELSE IF id is 0xA0000001 UINT32 mesh descriptors size (number of meshes * 2) #END IF
The list ends with a null descriptor (id = 0).
GroupStates[edit | edit source]
| Object name | Size | Visible |
|---|---|---|
| Unknown | Dynamic | No |
Stores a list of model layers states.
INT32 unknown1 #FOR number of model layers UINT16 default state (always 1 - enabled) UINT16 unknown2 #END FOR
Mesh[edit | edit source]
| Object name | Size | Visible |
|---|---|---|
| Unknown | Dynamic | No |
Contains a pointer to RenderMethod and a list of global parameters for each command in the code block.
OFFSET render method (points to RenderMethod) #FOR (number of commands in code block - 1) UINT32 global command parameter - objects count UINT32 global command parameter - object (might be an integer or offset to object/objects) #END FOR
First parameter in the list in most cases is a pointer to GeometryInfo.
GeometryInfo[edit | edit source]
| Object name | Size | Visible |
|---|---|---|
| Unknown | 0x10 | No |
UINT32 Indices count UINT32 Vertices count UINT32 Primitives count BOOL32 unknown1
geoprimdatabuffer[edit | edit source]
| Object name | Size | Visible |
|---|---|---|
| Unknown | Dynamic | Yes |
Stores a code (list of instructions) for rendering. Eeach instruction, except the first and the last one, may additionally use a global parameter, which is stored in RenderDescriptor.
#FOR number of techniques in RenderMethod's effect UINT32 unknown1 (usually 0) #WHILE Instruction id != 0 AND Instruction size != 0 UINT16 Instrution size (real size in bytes = Instruction size * 4) UINT16 Instruction id #IF Instruction size > 1 UINT32[Instruction size - 1] Instruction parameters #END WHILE #END FOR
Commands[edit | edit source]
| ID | Name | Parameters | Global parameter | Description | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | - | - | - | Code-end marker | ||||||||||||||||||||
| 1 | SET_GEOMETRY_INFO (NOP) | - | GeometryInfo (local) | No-operation. Takes GeometryInfo as parameter | ||||||||||||||||||||
| 2 | SET_VERTEX_SHADER_CONSTANT | INT32 register, INT32 numContants | constantData (global) | Sends constants (each constant - 4 bytes) to vertex shader | ||||||||||||||||||||
| 3 | NOP | |||||||||||||||||||||||
| 4 | SET_STREAM_SOURCE | INT32 streamNumber, INT32 vertexSize, INT32 vertexFVF,
INT32 unknown (-1), INT32 unknown (-1), OFFSET vertexBuffer, INT32 vertexCount, INT32 variationsCount (can be -1), INT32 vertexBufferIndex, INT32 unknown (-1), INT32 unknown (-1) |
vertexBuffer (local) | Setup vertex buffer. FVF flags:
| ||||||||||||||||||||
| 6 | NOP | |||||||||||||||||||||||
| 7 | SET_INDEX_BUFFER | INT32 unknown (2), INT32 unknown (-1), INT32 unknown (-1),
OFFSET indexBuffer, INT32 indexCount |
indexBuffer (local) | |||||||||||||||||||||
| 9 | SET_SAMPLER | |||||||||||||||||||||||
| 12 | SET_VERTEX_SHADER_CONSTANT_MATRIX | |||||||||||||||||||||||
| 16 | DRAW_PRIM | |||||||||||||||||||||||
| 17 | DRAW_INDEXED_PRIM_NO_Z_WRITE | INT32 unknown (4) | - | |||||||||||||||||||||
| 18 | DRAW_INDEXED_PRIM | |||||||||||||||||||||||
| 28 | SET_VERTEX_BONE_WEIGHTS | INT32 num3Bones, INT32 num2Bones, INT32 num1Bone | vertexSkinDataBuffer | Setup vertex bone weights | ||||||||||||||||||||
| 29 | ||||||||||||||||||||||||
| 30 | SET_VERTEX_SHADER_CONSTANT | |||||||||||||||||||||||
| 31 | SET_VERTEX_SHADER_CONSTANT | |||||||||||||||||||||||
| 32 | SET_SAMPLER | INT32 samplerIndex, INT32 textureObjectSize (48) | Texture array | Sets sampler at index | ||||||||||||||||||||
| 33 | SET_GEO_PRIM_STATE | - | GeoPrimState | |||||||||||||||||||||
| 35 | SET_VERTEX_SHADER_TRANSPOSED_MATRIX | INT32 register | Matrix4x4 | Transposes passed matrix and sends it to vertex shader | ||||||||||||||||||||
| 40 | SET_ANIMATION_BUFFER | INT32 unknown, INT32 unknown | EAGLAnimationBuffer | Setup animation buffer | ||||||||||||||||||||
| 46 | SET_VERTEX_SHADER_CONSTANT | INT32 register, INT32 numContants | constantData (local) | Sends constants (each constant - 4 bytes) to vertex shader | ||||||||||||||||||||
| 57 | DRAW_INDEXED_PRIM | |||||||||||||||||||||||
| 65 | DRAW_INDEXED_PRIM_AND_END | |||||||||||||||||||||||
| 69 | SETUP_RENDER | BOOL32 SoftwareVertexProcessing, INT32 unknown (-1) | - | Enable/disable software vertex processing; setup fog | ||||||||||||||||||||
| 72 | SET_PIXEL_SHADER_CONSTANT | INT32 register, INT32 numContants | constantData (global) | Sends constants (each constant - 4 bytes) to pixel shader | ||||||||||||||||||||
| 73 | SET_PIXEL_SHADER_CONTANT | |||||||||||||||||||||||
| 74 | ||||||||||||||||||||||||
| 75 | SET_STREAM_SOURCE_SKINNED | INT32 streamNumber, INT32 vertexSize, INT32 vertexFVF,
INT32 unknown (-1), INT32 unknown (-1), OFFSET vertexBuffer, INT32 vertexCount, INT32 variationsCount (can be -1), INT32 vertexBufferIndex, INT32 unknown (-1), INT32 unknown (-1) |
vertexBuffer (local) | Setup vertex buffer for skinned mesh |
Vertex structure[edit | edit source]
Vertex structure depends on vertex shader declarations in EAGLMicroCode.
For skinned models, while BLENDWEIGHTS and BLENDINDICES attributes are present in declaration, they aren't present in Vertex buffer. Instead, there's always COLOR1 attribute, where an index (32-bit integer) to Vertex skin data buffer is stored.
A Vertex skin data buffer is an array of entries:
#union UINT8 bone index 1 FLOAT weight value 1 (clear lower 8 bits when unpacking) #end #union UINT8 bone index 2 FLOAT weight value 2 (clear lower 8 bits when unpacking) #end #union UINT8 bone index 3 FLOAT weight value 3 (clear lower 8 bits when unpacking) #end UINT32 padding
The pointer to these entries is passed through SET_VERTEX_BONE_WEIGHTS command. It's not possible to have more than 128 such entries for one mesh. To bypass this limit, the mesh must be splitted.
GeoPrimState[edit | edit source]
| Object name | Size | Visible |
|---|---|---|
| EAGL::GeoPrimState | 0x44 | No |
Rendering states for geometry.
UINT32 Primitive type UINT32 Shading BOOL32 Culling enabled UINT32 Cull direction UINT32 Depth test method UINT32 Alpha blend mode BOOL32 Alpha test enable UINT32 Alpha compare value UINT32 Alpha test method BOOL32 Texture enabled UINT32 Transparency method UINT32 Fill mode UINT32 Blend operation UINT32 Source blend UINT32 Destination blend UINT32 Number of patch segments INT32 Z-Writing state (-1 - undefined?)
Variable[edit | edit source]
| Object name | Size | Visible |
|---|---|---|
| Unknown | 0x10 | No |
Container with model data which can be edited in runtime, from the program. Primarly used for lights attributes and geometry states.
OFFSET Name (points to null-terminated string) UINT16 Entry size UINT16 unknown1 (same as entries count?) UINT32 Entries count (always 1) OFFSET Entries (points to an array of entries)
ModelTextures[edit | edit source]
| Object name | Size | Visible |
|---|---|---|
| Unknown | Dynamic | No |
Model textures descriptors.
#REPEAT OFFSET Name (points to null-terminated string) #IF Name != 0 UINT32 number of TAR (texture) objects #FOR (number of TAR objects) OFFSET TAR (texture) object (single or array) #END FOR #IF version is 4 UINT16 unknown2 UINT16 unknown3 #END IF #END IF #UNTIL Name = 0
TAR[edit | edit source]
| Object name | Size | Visible |
|---|---|---|
| TAR | 0x30 | No |
Texture (sampler) descriptor.
UINT32 unknown1 (usually 0) CHAR[4] texture tag (4-character name) UINT32 unknown2 (usually 0) FLOAT unknown3 (usually 0.0) UINT32 unknown4 (usually 0) FLOAT unknown5 (usually 0.0) UINT32 unknown6 (usually 0) UINT32 U wrap mode UINT32 V wrap mode UINT32 W wrap mode UINT32 unknown7 (usually 0) UINT32 unknown8 (usually 0)
ComputationIndex[edit | edit source]
| Object name | Size | Visible |
|---|---|---|
| ComputationIndex | 0x4 | No |
UINT16 Active technique index (always 0) UINT16 unknown2 (1 or 2)
EAGL_TOOLLIB_VERSION-X[edit | edit source]
| Object name | Size | Visible |
|---|---|---|
| EAGL_TOOLLIB_VERSION-* | 0x0 | Yes |
Dummy object. EAGL library version (most recent is 4). Used since version 3.
LASTCHANGELIST[edit | edit source]
| Object name | Size | Visible |
|---|---|---|
| LASTCHANGELIST | 0x0 | Yes |
Dummy object. Used before version 3.
Skeleton[edit | edit source]
| Object name | Size | Visible |
|---|---|---|
| Skeleton | Dynamic | Yes |
Skeleton information.
UINT16 Signature (usually 0xC0DA) UINT16 unknown1 (usually 510) UINT16 Signature (usually 0xC0DA) UINT16 unknown2 (usually 0) UINT32 Number of bones OFFSET unknown3 (always 0) #FOR Number of bones VECTOR3 Bone scale (usually 1.0 1.0 1.0) INT32 ParentBoneID (-1 - no parent) VECTOR4 Bone rotation (quaternion) VECTOR4 Bone translation (W component is 0.0) MATRIX4X4 Inversed bone matrix #END FOR
Bone[edit | edit source]
| Object name | Size | Visible |
|---|---|---|
| Bone | 0x10 | Yes |
Bone information.
UINT32 Index UINT32 unknown1 (always 0) UINT32 unknown2 (always 0) UINT32 unknown3 (always 0)
Morph[edit | edit source]
| Object name | Size | Visible |
|---|---|---|
| Morph | Dynamic | Yes |
Vertices morphing information.
UINT32 Blend weights count OFFSET Blend weights names (points to array of pointers to null-terminated strings, array count is BW count) OFFSET Blend weights (points to array of zero floats, array count is BW count) UINT32 unknown1 (0) UINT32 Number of blend targets (each "target" is connected to InterleavedVertices instance) #FOR Number of blend targets OFFSET Interleaved vertices name (null-terminated string) UINT32 Blendshapes count (same as Blend weights count) #FOR Blendshapes count UINT32 Blend weight index UINT32 Number of vertex attributes for blending #FOR Number of vertex attributes for blending UINT28 Blend data size (number of vertices * entry size) UINT2 Blend data component type (1 - BYTE, 2 - USHORT, 4 - FLOAT, 0 - default (FLOAT)) UINT2 Number of components in one blend data entry (0 - 4, 0 - default (4 components)) UINT32 Number of vertices UINT32 Offset in Interleaved vertex buffer UINT32 Interleaved vertex buffer index CHAR[Blend data size] Blend data #END FOR #END FOR #END FORThe morphing process can be desribed with this pseudocode:
for (auto &blendTarget : blendTargets) {
for (auto &blendShape : blendTarget.blendShapes) {
float weight = morph->blendWeights[blendShape.weightIndex];
for (auto &bva : blendShape.blendVertexAttributes) {
for (unsigned int v = 0; v < bva.numVertices; v++) {
auto &iv = FindInterleavedVerticesBuffer(blendTarget.interleavedVerticesName, bva.interleavedVBIndex);
unsigned char *dst = iv->vb + iv->vbSize * model->instanceId + iv->vertexSize * v + bva.offsetInVertex;
unsigned char *src = bva.blendData + (bva.blendDataSize / bva.numVertices) * v;
for (unsigned int c = 0; c < bva.numComponents; c++) {
if (bva.componentType == 1)
*(unsigned char *)dst += (unsigned char)((double)(*(unsigned char *)src) * weight);
else if (bva.componentType == 2)
*(unsigned short *)dst += (unsigned short)((double)(*(unsigned short *)src) * weight);
else if (bva.componentType == 0 || bva.componentType == 4)
*(float *)dst += *(float *)src * weight;
dst += (bva.componentType == 0) ? 4 : bva.componentType;
src += (bva.componentType == 0) ? 4 : bva.componentType;
}
}
}
}
}
InterleavedVertices[edit | edit source]
| Object name | Size | Visible |
|---|---|---|
| Unknown | Dynamic | No |
Represent a set of vertex buffers.
UINT32 unknown1 (0) #REPEAT OFFSET name (null-terminated string, usually "InterleavedVertices") #IF name is not null UINT32 number of vertex datas #FOR number of vertex datas UINT32 vertex data index (starting from 0, increated by 1) UINT16 vertex count UINT1 multiple vertex buffers used (morph vertex data exists for each model instance) UINT15 morph vertex data size (same as vertex size) UINT32 vertex buffer size OFFSET vertex buffer offset #END FOR #END IF #UNTIIL name is not null
When this information is present for vertex buffer, the vertex buffer acts as a morph vertex data (this data is modified in-game during morphing), and original vertex bufer is placed right before the vertex buffer itself (normally, same vertex data is duplicated twice):
vertex buffer copy offset | CHAR[vertex count * vertex size] vertex buffer copy #IF morph vertex data exists for each model instance vertex buffer offset | CHAR[vertex count * morph vertex data size * number of model instances] vertex buffer #ELSE vertex buffer offset | CHAR[vertex count * morph vertex data size] vertex buffer #END IF
During the morphing, vertex buffer is modified. Vertex buffer copy can be used to access unmodified vertex data. The offset to vertex buffer copy is calculated as following:
vertex buffer copy offset = vertex buffer offset - vertex buffer size
AnimationBank[edit | edit source]
| Object name | Size | Visible |
|---|---|---|
| AnimationBank | 0x20 | Yes |
Animations container.
UINT32 unknown1 UINT32 Animations count UINT32 unknown2 UINT32 unknown3 OFFSET Animations OFFSET Animation names UINT32 unknown4 UINT32 unknown5
Animation[edit | edit source]
| Object name | Size | Visible |
|---|---|---|
| Animation | Dynamic | No |
Animation description.
UINT16 Type UINT16 Animation version (usually 0xC0DA) CHAR[] Data (depends on animation type)
Animation types
| ID | Name | Description | Data |
|---|---|---|---|
| 0 | ANIM_RAWPOSE | ||
| 10 | ANIM_DELTALERP |
OFFSET Data offset UINT16 unknown1 UINT16 unknown2 UINT16 unknown3 UINT16 unknown4 | |
| 11 | ANIM_DELTAQUAT |
OFFSET Data offset UINT16 unknown1 UINT16 unknown2 | |
| 15 | ANIM_COMPOUND | Animation container, contains other animations |
OFFSET unknown1 UINT16 Number of child animations UINT16 unknown3 #FOR Number of child animations OFFSET Child animation #END FOR |
| 20 | ANIM_DELTAF3 | ||
| 22 | ANIM_STATELESSQ | ||
| 23 | ANIM_STATELESSF3 | ||
| 25 | ANIM_POSEANIM |
ORD and ORL[edit | edit source]
In some games, .ORD and .ORL are used as an alternative to .O
In order to get .O from .ORD and .ORL, these 2 files must be simply concatanated.
ORD and ORP[edit | edit source]
In some games, .ORD and .ORP are used as an alternative to .O
In order to get .O from .ORD and .ORL, these 2 files must be concatanated: the data from .ORL file, from (offset 4) to (end of the file) must be placed at (value at offset 0) in ORD file.
ORD file[edit | edit source]
CHAR[] ORD data CHAR[] buffer for ORP data (ORP data must be placed there)
ORP file[edit | edit source]
UINT32 offset in ORD file where ORP data must be placed CHAR[] ORP data
Tools[edit | edit source]
OTools - open-source tool for .O files import/export, by Dmitri
OEdit - .O files editor, by Arushan