42 KiB
STRUCTURES
All integers here are big-endian unless specified.
All unspecified bytes must be set to 0
when written, although when reading
should not be checked as they may be garbage.
The type "fixed
" refers to a 32-bit fixed point number with the format 15.16s
(the lower 16 bits are fractional, the upper 15 are integral, and one bit for
sign.)
The type "angle
" refers to a 16-bit fixed point number with the format 0.9s.
This is used for all angles. Because they're actually 16-bit, the real format is
6.9s, but the integral part is ignored. "No angle" is represented by 65510
(-1.9) for some reason.
The type "unit
" refers to a 16-bit fixed point number with the format 5.10s.
This is used for all world coordinates.
A "u16opt
" is a 16-bit integer which references something by index. If all
bits are set, it is to be interpreted as "none." Traditionally, these are signed
integers, but they can be treated as unsigned with no repercussions.
Wad
Wad File
Wad files are structured like:
- Wad Header
- Entries/Chunks
- Directory
It must be in this order because the engine assumes that the data directly after the 128th byte is entry data.
Wad Header
The Wad Header is 128 bytes. The Wad header is always at the very beginning of the file, except when it's a MacBin file or an AppleSingle file, in which case it's at the start of the resource fork. You'll have to account for that yourself.
Name | Type | Offset |
---|---|---|
WadVersion |
u16 |
0 |
DataVersion |
u16 |
2 |
OriginalName |
u8[64] |
4 |
Checksum |
u32 |
68 |
WadVersion
is a Wad Version enumeration.DataVersion
is a Data Version enumeration.OriginalName
is the original filename, null byte terminated.Checksum
is a CRC-32 of the entire file with this value set to 0.
If WadVersion
is greater than or equal to VerDir
:
Name | Type | Offset |
---|---|---|
DirOffset |
u32 |
72 |
NumEntries |
u16 |
76 |
AppDataSize |
u16 |
78 |
ChunkSize |
u16 |
80 |
EntrySize |
u16 |
82 |
DirOffset
is the offset to the first Directory Entry structure.NumEntries
is the number of entries in this file.AppDataSize
is the number of bytes to skip for each directory entry.ChunkSize
andEntrySize
may be zero, in which case they will default to 16 and 10 respectively. They exist for forward compatibility with Wad patching, but because they were never actually expanded upon, are useless.
If WadVersion
is greater than or equal to VerOver
:
Name | Type | Offset |
---|---|---|
ParentSum |
u32 |
84 |
ParentSum
is the checksum of the file this one modifies, if any.
Directory Entry
Directory Entry is 8 bytes if WadVersion
is VerBase
, or else `EntrySize
- AppData
bytes. Following this structure is
AppData` bytes, supposed to be
Name | Type | Offset |
---|---|---|
DataOffset |
u32 |
0 |
DataSize |
u32 |
4 |
DataOffset
is the offset to the start of this entry's data (from the start of the file.)DataSize
is the length of this entry's data.
If WadVersion
is greater than or equal to VerDir
:
Name | Type | Offset |
---|---|---|
Index |
u16 |
8 |
AppData |
u8[] |
10 |
Index
is the index of this entry, for instance the map or PICT number.AppData
is an arbitrary data array used by editor applications, and will be ignored by the engine.
Chunk
Chunk is 12 bytes if WadVersion
is VerBase
, or ChunkSize
bytes otherwise.
Most Wad entries are made up of tagged data formats, the engine assumes this for
every entry and so every entry has at least one chunk. These are similar to IFF
or PNG chunks.
Name | Type | Offset |
---|---|---|
Ident |
u8[4] |
0 |
NextOffset |
u32 |
4 |
DataSize |
u32 |
8 |
Ident
is a four character code identifier for the chunk.NextOffset
is the file offset of the next chunk minus the file header.DataSize
is the size of the chunk (not including this header.)
If WadVersion
is greater than or equal to VerDir
:
Name | Type | Offset |
---|---|---|
PatchOffset |
u32 |
12 |
Map
Light Function
Light Function is 14 bytes.
Name | Type | Offset |
---|---|---|
Type |
u16 |
0 |
Period |
u16 |
2 |
DeltaPeriod |
u16 |
4 |
Value |
fixed |
6 |
DeltaValue |
fixed |
10 |
Type
is a Light Function enumeration.
Side Texture
Side Texture is 6 bytes. Just stores a texture and an offset.
Name | Type | Offset |
---|---|---|
OffsetX |
unit |
0 |
OffsetY |
unit |
2 |
TextureId |
u16opt |
4 |
TextureId
references a Shapes bitmap.
Point
Point is 4 bytes. A geometric point.
Name | Type | Offset |
---|---|---|
PosX |
unit |
0 |
PosY |
unit |
2 |
Endpoint
Endpoint is 16 bytes. A point structure which can be loaded directly into memory instead of being calculated at runtime.
Name | Type | Offset |
---|---|---|
Flags |
u16 |
0 |
HeightHi |
unit |
2 |
HeightLo |
unit |
4 |
Position |
struct |
6 |
Support |
u16 |
14 |
Flags
is an Endpoint Flags bit field.HeightHi
andHeightLo
are the highest adjacent ceiling and lowest adjacent floor heights, respectively.Position
is a Point structure.Support
is the index of the highest adjacent polygon.
Line
Line is 32 bytes. A geometric line segment.
Name | Type | Offset |
---|---|---|
PointBeg |
u16 |
0 |
PointEnd |
u16 |
2 |
Flags |
u16 |
4 |
Length |
unit |
6 |
HeightHi |
unit |
8 |
HeightLo |
unit |
10 |
SideFrnt |
u16opt |
12 |
SideBack |
u16opt |
14 |
PolyFrnt |
u16opt |
16 |
PolyBack |
u16opt |
18 |
PointBeg
andPointEnd
are the beginning and terminating endpoints.Flags
is a Line Flags bit field.HeightHi
andHeightLo
are the highest adjacent ceiling and lowest adjacent floor heights, respectively.SideFrnt
andSideBack
are indices of the Sides in the front and back.PolyFrnt
andPolyBack
are indices of the connected Polygons.
Side
Side is 64 bytes. One possibly textured side of a line segment.
Name | Type | Offset |
---|---|---|
Type |
u16 |
0 |
Flags |
u16 |
2 |
TexPri |
struct |
4 |
TexSec |
struct |
10 |
TexTra |
struct |
16 |
ExTopL |
struct |
22 |
ExTopR |
struct |
26 |
ExBotL |
struct |
30 |
ExBotR |
struct |
34 |
PanelType |
u16 |
38 |
PanelPerm |
i16 |
40 |
XferPri |
u16 |
42 |
XferSec |
u16 |
44 |
XferTra |
u16 |
46 |
Shade |
fixed |
48 |
Type
is a Side Type enumeration.Flags
is a Side Flags bit field.TexPri
,TexSec
andTexTra
are Side Texture structures representing the primary, secondary and transparent (middle) textures. Middle textures are not supported ifDataVersion
isDataM1
and soTexTra
must be set to none.ExTopL
,ExTopR
,ExBotL
andExBotR
are Point structures representing the collision bounding rectangle.PanelType
is a control panel preset number.PanelPerm
is the permutation for this control panel (if any.)XferPri
,XferSec
andXferTra
are Transfer Mode enumerations for each respective texture.Shade
is the ambient shading used primarily for visual contrast. IfDataVersion
isDataM1
, this must be set to 0.
Polygon
Polygon is 128 bytes. A geometric polygon, essentially Doom's "sector," but must be convex. More similar to a "subsector" since you have to split it yourself and the map compiler will not help you with this process. (It is a planned feature of Maraiah to allow the user to draw polygons of arbitrary shape and automatically split them.)
Note that u16opt
s not available with DataM1
must be set to none.
Name | Type | Offset |
---|---|---|
Type |
u16 |
0 |
Flags |
u16 |
2 |
Permutation |
i16 |
4 |
VtxNum |
u16 |
6 |
VtxArray |
u16[8] |
8 |
LinArray |
u16[8] |
24 |
TexFlr |
u16 |
40 |
TexCei |
u16 |
42 |
HeightFlr |
unit |
44 |
HeightCei |
unit |
46 |
LightFlr |
u16 |
48 |
LightCei |
u16 |
50 |
Area |
i32 |
52 |
ObjectFst |
u16 |
56 |
ZoneFst |
u16 |
58 |
ZoneNumLin |
u16 |
60 |
ZoneNumVtx |
u16 |
62 |
XferFlr |
u16 |
64 |
XferCei |
u16 |
66 |
Adjacent |
u16[8] |
68 |
NeighborFst |
u16 |
84 |
NeighborNum |
u16 |
86 |
Center |
struct |
88 |
SideArray |
u16[8] |
92 |
If DataVersion
is not DataM1
:
Name | Type | Offset |
---|---|---|
OrigFlr |
struct |
108 |
OrigCei |
struct |
112 |
Media |
u16opt |
116 |
MediaLight |
u16 |
118 |
SoundIndices |
u16 |
120 |
SoundAmbient |
u16opt |
122 |
SoundRandom |
u16opt |
124 |
Type
is a Polygon Type enumeration, unlessDataVersion
isDataM1
, where it is instead an Old Polygon Type enumeration.Flags
is a Polygon Flags bit field.Area
is the power-of-two area of the polygon.ObjectFst
must be65535
.Center
is a Point structure.OrigFlr
is a Point structure for the texture offset of the floor.OrigCei
is a Point structure for the texture offset of the ceiling.
Light
Light is 100 bytes. If DataVersion
is DataM1
this is an Old Light.
Name | Type | Offset |
---|---|---|
Type |
u16 |
0 |
Flags |
u16 |
2 |
Phase |
i16 |
4 |
ActivPri |
struct |
6 |
ActivSec |
struct |
20 |
ActivMid |
struct |
34 |
InactPri |
struct |
48 |
InactSec |
struct |
62 |
InactMid |
struct |
76 |
Tag |
u16 |
90 |
Type
is a Light Type enumeration.Flags
is a Light Flags bit field.ActivPri
,ActivSec
andActivMid
are Light Function structures.InactPri
,InactSec
andInactMid
are Light Function structures.
Old Light
Old Light is 32 bytes. The old lighting system not only sucked, but there was no Media system, so it was even more useless as it couldn't be used as a controller for liquids. So, because of these issues, the new lighting system was put in place, but it was incompatible data-wise because it had too many extensions.
Name | Type | Offset |
---|---|---|
Type |
u16 |
2 |
Mode |
u16 |
4 |
Phase |
u16 |
6 |
ValueMin |
fixed |
8 |
ValueMax |
fixed |
12 |
Period |
u16 |
16 |
ValueCur |
fixed |
18 |
Type
is an Old Light Type enumeration. To create a new light from this, you will need to write a lookup table which imitates each light type in the new lighting system. This table is tedious to write, so please reference either Aleph One or Maraiah for a full table of translations.Mode
is an Old Light Mode enumeration.Phase
is ignored in Aleph One.- If
Type
isStrobe
, you must set each resultingPeriod
to this definition'sPeriod
divided by 4 plus one. Otherwise,Period
is ignored. - For each of the new definition's functions, if the intensity of it is more
than 0, it should be set to
ValueMax
, otherwiseValueMin
. ValueCur
is ignored in Aleph One.
Map Annotation
Map Annotation is 72 bytes.
Name | Type | Offset |
---|---|---|
Type |
u16 |
0 |
Location |
struct |
2 |
Polygon |
u16 |
6 |
Text |
u8[64] |
8 |
Type
is an index into the annotation type definition, but there's only one, so this will always be0
anyway.
Object
Object is 16 bytes.
Name | Type | Offset |
---|---|---|
Group |
u16 |
0 |
Index |
u16 |
2 |
Angle |
angle |
4 |
Polygon |
u16 |
6 |
PosX |
unit |
8 |
PosY |
unit |
10 |
PosZ |
unit |
12 |
Flags |
u16 |
14 |
Flags
is a Map Object Flags bit field, and the upper 4 bits are the activation bias for monsters.
Object Frequency
Object Frequency is 12 bytes.
Name | Type | Offset |
---|---|---|
Flags |
u16 |
0 |
CountInit |
u16 |
2 |
CountMin |
u16 |
4 |
CountMax |
u16 |
6 |
CountRand |
u16 |
8 |
Chance |
u16 |
10 |
Flags
is an Object Frequency Flags bit field.
Platform Data
Platform Data is 32 bytes.
Name | Type | Offset |
---|---|---|
Type |
u16 |
0 |
Speed |
u16 |
2 |
Delay |
u16 |
4 |
HeightMax |
unit |
6 |
HeightMin |
unit |
8 |
Flags |
u32 |
10 |
Index |
u16 |
14 |
Tag |
u16 |
16 |
Type
is a Platform Type enumeration.Index
is the polygon this platform is attached to.Flags
is a Static Platform Flags bit field.
Ambient Sound
Ambient Sound is 16 bytes.
Name | Type | Offset |
---|---|---|
Index |
u16 |
2 |
Volume |
u16 |
4 |
Volume
is the volume of this sound, in range 0-256.
Random Sound
Random Sound is 32 bytes.
Name | Type | Offset |
---|---|---|
Flags |
u16 |
0 |
Index |
u16 |
2 |
Volume |
u16 |
4 |
DeltaVolume |
u16 |
6 |
Period |
u16 |
8 |
DeltaPeriod |
u16 |
10 |
Angle |
angle |
12 |
DeltaAngle |
angle |
14 |
Pitch |
fixed |
16 |
DeltaPitch |
fixed |
20 |
Phase |
u16 |
24 |
Flags
is a Random Sound Flags bit field.Phase
must be65535
.
Media Data
Media Data is 32 bytes. "Media" refers to liquids, presumably because of the plural of the definition of "medium," a "material which waves pass through," in this case liquid. (This is likely the case of whoever programmed this system learning physics before rendering, or conflating the two.)
Name | Type | Offset |
---|---|---|
Type |
u16 |
0 |
Flags |
u16 |
2 |
Control |
u16 |
4 |
Direction |
angle |
6 |
Magnitude |
unit |
8 |
Low |
unit |
10 |
High |
unit |
12 |
Origin |
struct |
14 |
Height |
unit |
18 |
Minimum |
fixed |
20 |
Texture |
u16opt |
24 |
XferMode |
u16 |
26 |
Type
is a Media Type enumeration.Flags
is a Media Flags bit field.Control
is the index of a light which is used to control the height of this media.XferMode
is a Transfer Mode enumeration.
Static Map Info
Static Map Info is 88 bytes.
Name | Type | Offset |
---|---|---|
TextureId |
u16 |
0 |
PhysicsId |
u16 |
2 |
LandscapeId |
u16 |
4 |
MissionFlags |
u16 |
6 |
EnvFlags |
u16 |
8 |
Name |
u8[66] |
18 |
EntryFlags |
u32 |
84 |
TextureId
is a Texture Collection enumeration. It is a preset number for texture collections and some other things such as media (liquid) presets.PhysicsId
used to be used for specifying three physics models: one for the Forge editor, one for the game, and one for low-gravity. However, the first one ended up being useless and the third was made into a map flag instead which simply modifies the current physics model. This should always be set to1
by new editors.LandscapeId
is a Landscape enumeration. It is the landscape number to use for the sky. This starts at0
, since it's an offset into the landscape collections. IfDataVersion
isDataM1
or theMusic
flag ofEnvFlags
is set, then this is used as the music index instead.MissionFlags
is a Mission Flags bit field.EnvFlags
is an Environment Flags bit field.Name
is the level name, intended to be 65 bytes, but one padding byte is left over, so the real length is 66.EntryFlags
is an Entry Point Flags bit field. It is unknown why this is 32 bits wide when it could fit in even 8 bits. IfDataVersion
isDataM1
and this is0
, this implies the value isSolo
.
Terminal
Terminal
Terminal text can be encoded with some weird xor bullshit for some reason. You can decode it and encode it with the same method:
for(i = 0; i < len / 4; i++) {p += 2; *p++ ^= 0xFE; *p++ ^= 0xED;}
for(i = 0; i < len % 4; i++) *p++ ^= 0xFE;
- Terminal Header
- Terminal Groups
- Text Faces
- Terminal text (null byte terminated)
Terminal Header
Terminal Header is 10 bytes.
Name | Type | Offset |
---|---|---|
Size |
u16 |
0 |
Flags |
u16 |
2 |
PageLines |
u16 |
4 |
NumGroups |
u16 |
6 |
NumFaces |
u16 |
8 |
Size
is the total length of the terminal, including this header.Flags
is a Terminal Flags bit field.PageLines
is the number of lines per page, almost always 22.
Terminal Group
Terminal Group is 12 bytes.
Name | Type | Offset |
---|---|---|
Flags |
u16 |
0 |
Type |
u16 |
2 |
Permutation |
i16 |
4 |
TextOfs |
u16 |
6 |
TextSize |
u16 |
8 |
MaxLineCount |
u16 |
10 |
Flags
is a Terminal Group Flags bit field.Type
is a Terminal Group Type enumeration.
Text Face
Text Face is 6 bytes.
Name | Type | Offset |
---|---|---|
TextOfs |
u16 |
0 |
Face |
u16 |
2 |
Color |
u16 |
4 |
Color
is a Terminal Color enumeration.
Physics
Physics Definition
Physics Definition is 104 bytes.
Name | Type | Offset |
---|---|---|
VelForw |
fixed |
0 |
VelBack |
fixed |
4 |
VelPerp |
fixed |
8 |
Accel |
fixed |
12 |
Decel |
fixed |
16 |
DecelAir |
fixed |
20 |
AccelGravity |
fixed |
24 |
AccelClimb |
fixed |
28 |
VelTerminal |
fixed |
32 |
DecelExtern |
fixed |
36 |
AccelAngular |
fixed |
40 |
DecelAngular |
fixed |
44 |
VelAngular |
fixed |
48 |
VelRecenter |
fixed |
52 |
FastVelAng |
fixed |
56 |
FastVelMax |
fixed |
60 |
Elevation |
fixed |
64 |
DecelAngExt |
fixed |
68 |
StepDelta |
fixed |
72 |
StepAmp |
fixed |
76 |
PlayerRadius |
fixed |
80 |
PlayerHeight |
fixed |
84 |
PlayerDeadHi |
fixed |
88 |
PlayerCamHi |
fixed |
92 |
PlayerSplash |
fixed |
96 |
HalfCamSep |
fixed |
100 |
Effect Definition
Effect Definition is 14 bytes.
Name | Type | Offset |
---|---|---|
Collection |
u16 |
0 |
Shape |
u16 |
2 |
Pitch |
fixed |
4 |
Flags |
u16 |
8 |
Delay |
u16 |
10 |
DelaySound |
u16 |
12 |
Flags
is an Effect Definition Flags bit field.
Weapon Definition
Weapon Definition is 134 bytes.
Name | Type | Offset |
---|---|---|
ItemType |
u16 |
0 |
PowerupType |
u16 |
2 |
WeaponClass |
u16 |
4 |
Flags |
u16 |
6 |
LightValue |
fixed |
8 |
LightDecay |
u16 |
12 |
HeightIdle |
fixed |
14 |
AmpBob |
fixed |
18 |
HeightKick |
fixed |
22 |
HeightReload |
fixed |
26 |
WidthIdle |
fixed |
30 |
AmpHorz |
fixed |
34 |
Collection |
u16 |
38 |
FrameIdle |
u16 |
40 |
FrameFiring |
u16 |
42 |
FrameReload |
u16 |
44 |
FrameCharge |
u16 |
48 |
FrameCharged |
u16 |
50 |
TicksReady |
u16 |
52 |
TicksLoadBeg |
u16 |
54 |
TicksLoadMid |
u16 |
56 |
TicksLoadEnd |
u16 |
58 |
TicksPowerup |
u16 |
60 |
TriggerPri |
struct |
62 |
TriggerSec |
struct |
98 |
WeaponClass
is a Weapon Type enumeration.Flags
is a Weapon Flags bit field.TriggerPri
andTriggerSec
are Trigger Definition structures used for the primary and secondary fire buttons.
Trigger Definition
Trigger Definition is 36 bytes.
Name | Type | Offset |
---|---|---|
MagRounds |
u16 |
0 |
AmmoType |
u16 |
2 |
TicksRound |
u16 |
4 |
TicksRecover |
u16 |
6 |
TicksCharge |
u16 |
8 |
Recoil |
unit |
10 |
SoundFire |
u16 |
12 |
SoundClick |
u16 |
14 |
SoundCharge |
u16 |
16 |
SoundCasing |
u16 |
18 |
SoundReload |
u16 |
20 |
SoundCharged |
u16 |
22 |
Projectile |
u16 |
24 |
TODO | u16 |
26 |
TODO | i16 |
28 |
TODO | i16 |
30 |
CasingType |
u16 |
32 |
BurstCount |
u16 |
34 |
CasingType
is a Casing Type enumeration.
Projectile Definition
Projectile Definition is 48 bytes.
Name | Type | Offset |
---|---|---|
Collection |
u16opt |
0 |
Shape |
u16 |
2 |
FxExplode |
u16opt |
4 |
FxExplodeMed |
u16opt |
6 |
FxTrail |
u16opt |
8 |
TicksTrail |
u16 |
10 |
MaxTrails |
u16opt |
12 |
MediaType |
u16opt |
14 |
Radius |
unit |
16 |
AreaOfEffect |
unit |
18 |
Damage |
struct |
20 |
Flags |
u32 |
32 |
Speed |
unit |
36 |
Range |
unit |
38 |
SndPitch |
fixed |
40 |
SndFly |
u16opt |
44 |
SndBounce |
u16opt |
46 |
MediaType
is the type of projectile this becomes when below media.Damage
is a Damage Definition structure.Flags
is a Projectile Flags bit field.
Monster Definition
Monster Definition is 156 bytes.
Name | Type | Offset |
---|---|---|
Collection |
u16 |
0 |
Vitality |
u16 |
2 |
ImmuneTo |
u32 |
4 |
WeakTo |
u32 |
8 |
Flags |
u32 |
12 |
MonsterClass |
u32 |
16 |
FriendTo |
u32 |
20 |
EnemyTo |
u32 |
24 |
SndPitch |
fixed |
28 |
SndSeeEnemy |
u16opt |
32 |
SndSeeFriend |
u16opt |
34 |
SndSeeClear |
u16opt |
36 |
SndKill |
u16opt |
38 |
SndApologize |
u16opt |
40 |
SndAmicide |
u16opt |
42 |
SndFlaming |
u16opt |
44 |
SndActive |
u16opt |
46 |
ActiveMask |
u16 |
48 |
DropItem |
u16opt |
50 |
Radius |
unit |
52 |
Height |
unit |
54 |
HoverHeight |
unit |
56 |
LedgeMin |
unit |
58 |
LedgeMax |
unit |
60 |
ExtVelScale |
fixed |
62 |
FxImpact |
u16opt |
66 |
FxMeleeImpact |
u16opt |
68 |
FxTrail |
u16opt |
70 |
HalfFOVHorz |
u16 |
72 |
HalfFOVVert |
u16 |
74 |
ViewRange |
unit |
76 |
ViewRangeDark |
unit |
78 |
Intelligence |
u16 |
80 |
Speed |
u16 |
82 |
Gravity |
u16 |
84 |
TerminalVel |
u16 |
86 |
DoorTryMask |
u16 |
88 |
ExplodeRadius |
u16opt |
90 |
ExplodeDamage |
struct |
92 |
SeqHit |
u16opt |
104 |
SeqHardDying |
u16opt |
106 |
SeqSoftDying |
u16opt |
108 |
SeqHardDead |
u16opt |
110 |
SeqSoftDead |
u16opt |
112 |
SeqStanding |
u16 |
114 |
SeqMoving |
u16 |
116 |
SeqTeleIn |
u16opt |
118 |
SeqTeleOut |
u16opt |
120 |
AtkFrequency |
u16 |
122 |
AtkMelee |
struct |
124 |
AtkRange |
struct |
140 |
Flags
is a Monster Flags bit field.MonsterClass
is a Monster Class bit field.ExplodeDamage
is a Damage Definition structure.AtkMelee
andAtkRange
are Attack Definition structures.
Damage Definition
Damage Definition is 12 bytes.
Name | Type | Offset |
---|---|---|
Type |
u16 |
0 |
Flags |
u16 |
2 |
DmgBase |
u16 |
4 |
DmgRand |
u16 |
6 |
Scale |
fixed |
8 |
Type
is a Damage Type enumeration.Flags
is a Damage Flags enumeration.
Attack Definition
Attack Definition is 16 bytes.
Name | Type | Offset |
---|---|---|
Type |
u16opt |
0 |
Repetitions |
u16 |
2 |
Error |
angle |
4 |
Range |
unit |
6 |
Shape |
u16 |
8 |
OfsX |
unit |
10 |
OfsY |
unit |
12 |
OfsZ |
unit |
14 |
Images
Picture Resource
Pictures are formed with a header and then a variable number of operations. In other words, a small state machine is used to form an image through effects and various fill instructions. QuickDraw is horrifying. This is the native image format. It's a fucking metafile. I suppose this could be worse, considering they later used PDF files for images.
- Picture Header
- Picture Opcodes
Picture Header
All QuickDraw PICTs begin with a basic 10 byte header as follows.
Name | Type | Offset |
---|---|---|
Size |
u16 |
0 |
Top |
u16 |
2 |
Left |
u16 |
4 |
Height |
u16 |
6 |
Width |
u16 |
8 |
CopyBits
CopyBits has a variable size. Offsets are not provided as they are variable, sequential to the current code path.
If direct copy:
Name | Type | Ignored |
---|---|---|
BaseAddr |
u32 |
Yes |
Always:
Name | Type |
---|---|
PitchFl |
u16 |
Top |
u16 |
Left |
u16 |
Bottom |
u16 |
Right |
u16 |
PitchFl
is the number of bytes per row, and the upper two bits are a CopyBits Flags bit field.
If PICT2:
Name | Type |
---|---|
PixMap |
struct |
PixMap
is a PixMap structure.
Otherwise, assume pack type is default and bit depth is 1.
If packed:
Name | Type | Ignored |
---|---|---|
CLUTIden |
u32 |
Yes |
CLUTFlags |
u16 |
No |
CLUTNum |
u16 |
No |
CLUT |
struct[] |
No |
CLUTFlags
is a Color Table Flags bit field.CLUT
is an array ofCLUTNum
Color Table structures.
Always:
Name | Type | Ignored |
---|---|---|
SrcTop |
u16 |
Yes |
SrcLeft |
u16 |
Yes |
SrcBottom |
u16 |
Yes |
SrcRight |
u16 |
Yes |
DstTop |
u16 |
Yes |
DstLeft |
u16 |
Yes |
DstBottom |
u16 |
Yes |
DstRight |
u16 |
Yes |
XferMode |
u16 |
Yes |
If clip:
Name | Type | Ignored |
---|---|---|
ClipRgn |
struct |
Yes |
ClipRgn
is skipped the same as opcode$0001
in Aleph One.
Image data follows this header.
PixMap
PixMap is 36 bytes.
Name | Type | Ignored |
---|---|---|
Version |
u16 |
Yes |
PackType |
u16 |
No |
PackSize |
u32 |
Yes |
HorzDPI |
u32 |
Yes |
VertDPI |
u32 |
Yes |
Format |
u16 |
Yes |
BitDepth |
u16 |
No |
Components |
u16 |
Yes |
CompDepth |
u16 |
Yes |
PlaneOffs |
u32 |
Yes |
ClutId |
u32 |
Yes |
Color Table
Color Table is 8 bytes.
Name | Type | Offset |
---|---|---|
Index |
u16 |
0 |
Red |
u16 |
2 |
Green |
u16 |
4 |
Blue |
u16 |
6 |
Index
is ignored if device mapping is used.
Header Op
Header Op is 24 bytes.
Name | Type | Offset |
---|---|---|
Version |
u16 |
0 |
Width |
u32 |
4 |
Height |
u32 |
8 |
Top |
u16 |
12 |
Left |
u16 |
14 |
Bottom |
u16 |
16 |
Right |
u16 |
18 |
Shapes
Shapes files start with exactly 32 Collection Headers, followed by everything else. Use the offsets provided by these structures to find where all of the data is.
Collection Header
Collection Header is 32 bytes. Each collection may have two versions, lo-res and hi-res, which are used according to the user's settings. The main purpose of these is for compatibility with older Macs which might not have enough video memory for, for instance, the huge two mebibyte sky boxes that Marathon 2 has.
Name | Type | Offset |
---|---|---|
OffsetLo |
u32 |
4 |
LengthLo |
u32 |
8 |
OffsetHi |
u32 |
12 |
LengthHi |
u32 |
16 |
Collection Definition
Collection Definition is 544 bytes (no, I'm not kidding, there are actually that many unused bytes.) The sequences, frames and bitmaps have their individual offsets stored in tables, which themselves are at offsets specified by this structure. Note that all offsets (including those in offset tables) are relative to the start of this structure.
Name | Type | Offset |
---|---|---|
Version |
u16 |
0 |
Type |
u16 |
2 |
Colors |
u16 |
6 |
TabNum |
u16 |
8 |
TabOfs |
u16 |
10 |
SeqNum |
u16 |
12 |
SeqOfs |
u16 |
14 |
FrmNum |
u16 |
16 |
FrmOfs |
u16 |
18 |
BmpNum |
u16 |
20 |
BmpOfs |
u16 |
22 |
Version
should always be3
, but this isn't checked by the engine.Type
is a Collection Type enumeration.TabNum
andTabOfs
are the number of and offset to the color tables.SeqNum
andSeqOfs
are the number of sequences and the offset to their offset table.FrmNum
andFrmOfs
are the number of frames and the offset to their offset table.BmpNum
andBmpOfs
are the number of bitmaps and the offset to their offset table.
Frame
Frame is 36 bytes. TODO: document how world transform works.
Name | Type | Offset |
---|---|---|
Flags |
u16 |
0 |
MinLight |
fixed |
2 |
BmpIndex |
u16opt |
6 |
WldLeft |
unit |
14 |
WldRight |
unit |
16 |
WldTop |
unit |
18 |
WldBottom |
unit |
20 |
WldOrigX |
unit |
22 |
WldOrigY |
unit |
24 |
Flags
is a Frame Flags bit field.MinLight
is the minimum light intensity (0-1.)
Sequence
Sequence is 88 bytes. A sequence, also known as a "high level shape" in the engine, is essentially a potentially animated sequence of frames organized into angular views which may loop or play sounds. Each sequence has a "key frame" which is used for determining when to run action code or play an attached sound.
Name | Type | Offset |
---|---|---|
Name |
u8[34] |
4 |
ViewType |
u16 |
38 |
FrameNum |
u16 |
40 |
FrameTick |
u16 |
42 |
FrameKey |
u16 |
44 |
XferMode |
u16 |
46 |
XferPeriod |
u16 |
48 |
SndBeg |
u16 |
50 |
SndKey |
u16 |
52 |
SndEnd |
u16 |
54 |
FrameLoop |
u16 |
58 |
Name
is the sequence name, used mainly by editors, supposed to be 33 bytes, but due to padding, the real length is 34.ViewType
is a View Type enumeration.FrameNum
is the number of frames in this sequence.FrameTick
is the number of ticks per frame.FrameKey
is the index of the key frame.XferMode
is a Transfer Mode enumeration.XferPeriod
is the period for the transfer mode in 1/30ths seconds.SndBeg
,SndKey
andSndEnd
are the sounds played at the first, key and last frame of this sequence.
Bitmap Header
Bitmap Header is 26 bytes.
Each Bitmap Header is followed by either Height * 4
or Width * 4
empty bytes
which must be skipped.
Name | Type | Offset |
---|---|---|
Width |
u16 |
0 |
Height |
u16 |
2 |
Pitch |
u16 |
4 |
Flags |
u16 |
6 |
Depth |
u16 |
8 |
Width
is the number of pixels on the horizontal axis.Height
is the number of pixels on the vertical axis.Pitch
is either the number of pixels per row if row ordered, per column if column ordered, or65535
if the data is transparency RLE compressed.Flags
is a Bitmap Flags bit field.Depth
must always be8
.
Sounds
Sounds files start with a header followed by all of the actual sound definitions. Each sound starts with a Carbon Sound Header.
Sounds Header
Sounds Header is 260 bytes. (Seriously, what's with these formats and horrifically excessive padding?)
This header is followed by SrcNum * SndNum
Sound Definitions.
Name | Type | Offset |
---|---|---|
Version |
u32 |
0 |
Magic |
u8[4] |
4 |
SrcNum |
u16 |
8 |
SndNum |
u16 |
10 |
Version
is always1
.Magic
is always"snd2"
.SrcNum
defines the number of sound formats this file provides, similar to Shapes' lo- and hi-res collections, although this applies to the entire file and not just parts of it.0
is invalid for this field, and in the original Marathon 2 engine (on Mac only, not on Windows,) it must be2
because of QuickTime. A value of1
means "8-bit 22kHz only" and a value of2
means "both 8-bit 22kHz and 16-bit 22kHz."
Sound Definition
Sound Definition is 64 bytes.
Name | Type | Offset |
---|---|---|
Code |
u16opt |
0 |
Volume |
u16 |
2 |
Flags |
u16 |
4 |
Chance |
u16 |
6 |
PitchLo |
fixed |
8 |
PitchHi |
fixed |
12 |
NumOfs |
u16 |
16 |
GroupOffset |
u32 |
20 |
Size |
u32 |
24 |
GroupSize |
u32 |
28 |
AddOffset |
u32[5] |
32 |
Volume
is a Sound Behaviour enumeration.Flags
is a Sound Definition Flags bit field.Chance
is the chance out of65535
that the sound will not play.PitchLo
is the lower random pitch bound, if0
then it will be1.0
.PitchHi
is the high random pitch bound, if0
then it will bePitchLo
.NumOfs
is the number of random sounds to pick fromAddOffset
.GroupOffset
is the starting offset for each additive sound offset.Size
is the sound of an individual sound in the group.GroupSize
is the total size of all sounds in the group.AddOffset
is the offset added toGroupOffset
to get an individual sound. While it is an array ofNumOfs
offsets, it has a fixed size in the format.
Carbon Sound Header
Carbon Sound Header is 21 bytes.
The sound format is from Carbon's SoundHeader
structures. It's used primarily
in System 7 programs as snd
resources but in OS X it was deprecated in favor
of QuickTime. HFS still has Resource Forks but they aren't used anymore. I don't
imagine this format was ever used for anything else, except for Marathon, which
embeds it in the Sound files directly, instead of using snd
resources (which
have a larger structure consisting of a resource header and sound commands
rather than just the header and sample data.)
Name | Type | Offset |
---|---|---|
Size |
u32 |
4 |
SampleRate |
u16 |
8 |
LoopBeg |
u32 |
12 |
LoopEnd |
u32 |
16 |
Magic |
u8 |
20 |
- If
Magic
is$00
nothing else needs to be done and raw unsigned 8-bit mono PCM sample data starts at byte 22. If it is$FF
it is followed by a Carbon Extended Sound Header, or if it is$FE
it is followed by a Carbon Compressed Sound Header. The compressed sound header is not documented because it is not actually used by Marathon.
Carbon Extended Sound Header
Carbon Extended Sound Header is 42 bytes.
The extended sound header contains more useless information and even several fields that do absolutely nothing. Wow. At least it can store 16 bit samples. It also has an 80-bit float in it, which horrifies me greatly. There's only one actually useful field.
Name | Type | Offset |
---|---|---|
Frames |
u32 |
0 |
SampleBits |
u16 |
26 |
Frames
is used instead ofSize
for sounds with this header, since it represents how many frames there are rather than how many bytes. Even though this is actually a pointless distinction andSize
is left at1
anyway.SampleBits
must be either16
or8
. If it is16
then the sample data is signed 16-bit little endian mono PCM.