3.3 KiB
.hmap file format (version 1)
Chunked, little-endian binary. Readers must skip chunks they do not know, so new chunks can be added without breaking old readers. A file may carry source data (editable), compiled data (runtime), or both.
header "HMAP" (4 bytes) | u32 version (=1) | u32 flags (bit0 = source chunks, bit1 = compiled chunk)
chunk* tag[4] | u32 payloadSize | payload
Primitive types: u8 u32 i32 f32 (LE) - str = u32 byteLength + UTF-8 bytes (no terminator) -
vec2/vec3 = 2/3 f32 - plane = vec3 normal + f32 d (points p on the plane satisfy dot(n,p) == d, solid is on the
back side dot(n,p) < d) - aabb = vec3 min + vec3 max - uv = vec2 offset, vec2 scale, f32 rotation(deg).
| Tag | Content |
|---|---|
META |
str name, vec3 ambient, f32 gridSize, f32 unitsPerMeter, u32 nextId |
MATS |
u32 n, then n x { str name, str texture, vec2 tileSize, vec3 color, u32 flags } |
BRSH |
u32 n, then n x { u32 id, u32 owner, u32 contents, u32 flags, u32 faceCount, faces: { plane, i32 material, uv, u32 flags } } |
MESH |
u32 n, then n x { u32 id, u32 owner, u32 flags, str name, u32 vertCount, vec3[], u32 polyCount, polys: { i32 material, u32 smooth, uv proj, u32 idxCount, u32[], u32 uvCount, vec2[] } } |
ENTS |
u32 n, then n x { u32 id, u32 flags, str classname, vec3 origin, vec3 angles, vec3 scale, u32 kvCount, (str key, str value)[] } |
CMPL |
compiled map, see below |
owner= id of the brush entity that owns the object (0 = world).contentsbits: 1 solid, 2 water, 4 clip, 8 trigger, 16 sky.- Mesh polygons are convex, indices are CCW seen from the front.
uvCountis either 0 (auto-projected withproj) oridxCount. - Angles are
(pitch, yaw, roll)degrees, applied asR = Ry(yaw) * Rx(pitch) * Rz(roll); forward = -Z at zero angles.
CMPL (compiled)
vec3 ambient | f32 unitsPerMeter | u8 baked | aabb bounds
u32 batchCount, then { i32 material, u8 source (0 brush/BSP, 1 mesh), i32 model,
u32 vertexCount, vertex[] { vec3 pos, vec3 normal, vec2 uv, u32 colorRGBA },
u32 indexCount, u32[] } // triangle lists, CCW front
u32 modelCount, then { u32 entityId, aabb, u32 brushCount, collisionBrush[] } // model 0 = world
BSP: i32 root | u32 depth | aabb | u32 planeCount, plane[] | u32 nodeCount, { i32 plane, i32 front, i32 back }[]
| u32 leafCount, { u32 firstBrush, u32 brushCount }[] | u32 leafBrushCount, u32[] | u32 brushCount, collisionBrush[]
u32 meshCollCount, then { u32 objectId, aabb, u32 vertexCount, vec3[] } // 3 vertices per triangle
u32 lightCount, then { u8 type (0 point, 1 spot, 2 sun), vec3 pos, vec3 dir, vec3 color,
f32 intensity, f32 radius, f32 innerDeg, f32 outerDeg, u32 entityId }
collisionBrush = u32 contents, u32 sourceId, aabb, u32 planeCount, plane[]
BSP child links: >= 0 is a node index, < 0 is leaf ~value. Every node splits on planes[node.plane]
(front = dot(n,p) - d >= 0). Leaves list collision brushes; a point is solid when it lies behind all planes of a brush.
Colour is little-endian RGBA bytes (0xAABBGGRR); it holds the baked vertex lighting when baked = 1, otherwise white.
Entities and materials in a compiled-only file come from the ENTS / MATS chunks that precede CMPL.