Skip to content

Player Model

There is a separate model of MegaMan depending on the equipment. The options for this are if a helmet is equipped or not, and if the shoes are jet, cleat, asbestos, or hover. What this means is that most of the information in the model is duplicated, with the exception of the helmet and shoes.

FileHelmetShoes
PL00P000.BINYESNormal
PL00P001.BINYESJet Shoes
PL00P002.BINYESCleat Shoes
PL00P003.BINYESAsbestos Shoes
PL00P004.BINYESHydo Shoes
PL00P005.BINYESHover Shoes
PL00P010.BINNONormal
PL00P011.BINNOJet Shoes
PL00P012.BINNOCleat Shoes
PL00P013.BINNOAsbestos Shoes
PL00P014.BINNOHydo Shoes
PL00P015.BINNOHover Shoes

Body Parts

Even through there are variations with all of the models, the offsets for the body parts are the same. The mesh information stored in each .BIN files starts at 0x30 and is 0x2b40 in size. These offsets are with respect to the start of the model file which is 0x30.

For the purpose of this document, we will use the term “model” to refer to the enter file, “mesh” refers to a single body part. And “strip” will refer to the list of commands that make up the mesh.

Body PartOffsetNumber of Strips
Bones0x0016
Body0x806
Head0xb603
Feet0x18002
Right Arm0x1dd03
Buster0x22203
Left Arm0x26f03

Strip Format

Each strip is a list of vertices and indices used to draw the mesh. Indices are described in either triangles or quads, and both reference the same vertex list. For the same number of vertices, there are shading vertex colors that describe the local shadows for each face.

typedef struct {
utin8_t triCount;
utin8_t quadCount;
utin8_t vertexCount;
uint8_t nop;
uint32_t triOffset;
uint32_t quadOffset;
uint32_t vertexOffset;
utin32_t activeVertexColors;
utin32_t referenceVertexColors;
} StripHeader;
0x000x010x020x030x040x080x0c0x100x14
Tri CountQuad CountVertex CountNOPTri OfsQuad OfsVertex OfsTri Shadow OfsQuad Shadow Ofs

Vertex Format

Each vertex is encoded in a 32-bit word (uint32_t) which is split into different bit segments for the X, Y, and Z coordinates, as well as scale data:

  • 32-bit word format:
    • X-axis: The lowest 10 bits (bits 0–9).
    • Y-axis: The next 10 bits (bits 10–19).
    • Z-axis: The following 10 bits (bits 20–29).
    • Scale: The highest 2 bits (bits 30–31), which encode scaling information.

Scale Encoding

The two highest bits (30–31) represent scale data, which determines how much to scale the X, Y, and Z coordinates:

  • 0b00: 1x scale (no scaling).
  • 0b01: 2x scale.
  • 0b10: 4x scale.
  • 0b11: 0.5x scale.

Coordinate Representation

Each axis (X, Y, Z) is represented as a signed 10-bit integer:

  • Sign Bit: The most significant bit (MSB) of each axis segment indicates the sign (negative if set).
  • Magnitude: The remaining 9 bits represent the magnitude of the value.

PSX Coordinate System

The PSX coordinate system uses a convention where -Y is up. To align with this, the vertices are rotated by 180 degrees along the X-axis. Additionally, the PSX does not support floating-point values, so we scale down the vertices to bring them closer to real-world units, like meters.

Code Example

The following C code demonstrates how to decode the vertex data from a 32-bit word:

#include <stdint.h>
#include <math.h>
#include <stdio.h>
#define SCALE 0.00125
// Function to read a vertex from a 32-bit encoded integer
void readVertex(uint32_t dword, float* x, float* y, float* z) {
const uint32_t VERTEX_MASK = 0b1111111111;
const uint32_t VERTEX_MSB = 0b1000000000;
const uint32_t VERTEX_LOW = 0b0111111111;
// Extract X, Y, Z using bit shifts and masks
int32_t xBytes = (dword >> 0x00) & VERTEX_MASK;
int32_t yBytes = (dword >> 0x0a) & VERTEX_MASK;
int32_t zBytes = (dword >> 0x14) & VERTEX_MASK;
// Apply sign to X, Y, Z
int32_t xSign = (xBytes & VERTEX_MSB) ? -1 : 1;
int32_t xValue = (xBytes & VERTEX_LOW);
int32_t ySign = (yBytes & VERTEX_MSB) ? -1 : 1;
int32_t yValue = (yBytes & VERTEX_LOW);
int32_t zSign = (zBytes & VERTEX_MSB) ? -1 : 1;
int32_t zValue = (zBytes & VERTEX_LOW);
// Extract scale from the top 2 bits (30 and 31)
uint32_t scaleBits = (dword >> 30) & 0b11;
float scale = 1.0;
switch (scaleBits) {
case 0b00:
scale = 1.0;
break;
case 0b01:
scale = 2.0;
break;
case 0b10:
scale = 4.0;
break;
case 0b11:
scale = 0.5;
break;
}
// Combine high and low parts for each axis
*x = (xSign * xValue) * scale;
*y = (ySign * yValue) * scale;
*z = (zSign * zValue) * scale;
// Apply final scaling to make units closer to meters
*x *= SCALE;
*y *= SCALE;
*z *= SCALE;
// Rotate by 180 degrees across the X-axis to match PSX format (-Y is up)
*y = -*y; // Flip Y
}

Face Format

The face format is shared between triangles and quads. The face_t structure contains UV coordinates and vertex indices. Here’s how the data is laid out:

typedef struct {
uint8_t au;
uint8_t av;
uint8_t bu;
uint8_t bv;
uint8_t cu;
uint8_t cv;
uint8_t du; // Unused for triangles
uint8_t dv; // Unused for triangles
uint32_t indices; // Encodes vertex indices and material information
} face_t;

Field Details:

  • UV Coordinates: The first 8 bytes (au, av, bu, bv, cu, cv, du, dv) represent texture mapping coordinates. These UV values are 8-bit unsigned integers and reference pixels in a 256x256 texture space.

    • For triangles, du and dv are unused.
    • For quads, all UV values are used.
  • Vertex Indices: The indices field contains vertex indices and material information:

    • Bits 0–6: Vertex index for a.
    • Bits 7–13: Vertex index for b.
    • Bits 14–20: Vertex index for c.
    • Bits 21–27: Vertex index for d (unused for triangles).
    • Bits 28–29: Material information, which can have one of four values:
      • 0b00: Megaman’s body texture.
      • 0b01: Megaman’s body texture with a different palette.
      • 0b10: Megaman’s face texture.
      • 0b11: Megaman’s face texture with a different palette (used for special weapons).

UV Coordinate Conversion

The UV coordinates are stored as integers but need to be converted to floating-point values for rendering. The texture space is 256x256, so the following formula converts the UVs to normalized floating-point values:

u_float = (u_int * 1/256) + 0.001953125
v_float = (v_int * 1/256) + 0.001953125

Code Example

#include <stdint.h>
#include <stdio.h>
#define PIXEL_TO_FLOAT_RATIO 0.00390625f
#define PIXEL_ADJUSTMENT 0.001953125f
#define FACE_MASK 0x7F
// Structure to hold decoded face data
typedef struct {
float u, v; // UV coordinates
uint8_t index; // Vertex index
uint8_t materialIndex; // Material information
} Vertex;
typedef struct {
Vertex a, b, c, d; // Vertices for a face
uint8_t isQuad; // 1 if quad, 0 if triangle
} Face;
// Function to decode UV coordinates and vertex indices from a face_t structure
void readFace(const uint8_t* faceData, Face* face, uint8_t isQuad) {
// Read UV coordinates
uint8_t au = faceData[0], av = faceData[1];
uint8_t bu = faceData[2], bv = faceData[3];
uint8_t cu = faceData[4], cv = faceData[5];
uint8_t du = faceData[6], dv = faceData[7];
// Read indices and material information
uint32_t indices = *((uint32_t*)(faceData + 8));
uint8_t materialIndex = (indices >> 28) & 0x3;
uint8_t indexA = (indices >> 0) & FACE_MASK;
uint8_t indexB = (indices >> 7) & FACE_MASK;
uint8_t indexC = (indices >> 14) & FACE_MASK;
uint8_t indexD = (indices >> 21) & FACE_MASK;
// Store the decoded UV and index data in the Face struct
face->a.u = au * PIXEL_TO_FLOAT_RATIO + PIXEL_ADJUSTMENT;
face->a.v = av * PIXEL_TO_FLOAT_RATIO + PIXEL_ADJUSTMENT;
face->a.index = indexA;
face->a.materialIndex = materialIndex;
face->b.u = bu * PIXEL_TO_FLOAT_RATIO + PIXEL_ADJUSTMENT;
face->b.v = bv * PIXEL_TO_FLOAT_RATIO + PIXEL_ADJUSTMENT;
face->b.index = indexB;
face->b.materialIndex = materialIndex;
face->c.u = cu * PIXEL_TO_FLOAT_RATIO + PIXEL_ADJUSTMENT;
face->c.v = cv * PIXEL_TO_FLOAT_RATIO + PIXEL_ADJUSTMENT;
face->c.index = indexC;
face->c.materialIndex = materialIndex;
if (isQuad) {
face->isQuad = 1;
face->d.u = du * PIXEL_TO_FLOAT_RATIO + PIXEL_ADJUSTMENT;
face->d.v = dv * PIXEL_TO_FLOAT_RATIO + PIXEL_ADJUSTMENT;
face->d.index = indexD;
face->d.materialIndex = materialIndex;
} else {
face->isQuad = 0;
}
}