The Level Design Book
BookResources
  • The Level Design Book
  • ✨What is level design
  • Book 1, Process
    • πŸ—ΊοΈHow to make a level
    • 🧠Pre-production
      • Pacing
      • Research
      • Worldbuilding
      • Scope
    • πŸ”«Combat
      • Enemy design
      • Encounter
      • Cover
      • Map balance
    • πŸ› οΈLayout
      • Flow
        • Circulation
        • Verticality
      • Critical path
      • Parti
      • Typology
        • Gates
    • 🏠Blockout
      • Massing
        • Landscape
        • Composition
        • Prospect-refuge
      • Metrics
        • Modular kit design
        • Doom metrics
        • Quake metrics
      • Wayfinding
      • Playtesting
        • Player persona
    • πŸ“œScripting
      • (stub) Navigation
      • Doors
    • β˜€οΈLighting
      • Three point lighting
      • D6 lighting
      • Lighting for darkness
    • 🏑Environment Art
      • Shape and color psychology
      • Texturing
      • Storytelling
      • Optimization
    • 🌈Release
  • Book 2, Culture
    • 🦜Level design as culture
    • History of the level designer
    • Zero player level design
    • (unfinished pages)
      • History of architecture
      • Structural engineering primer
      • History of environment art
      • History of furniture
      • History of encounter design
  • Book 3, Studies
    • πŸ”How to study a level
    • Single player studies
      • Undead Burg (Dark Souls 1)
      • Assassins (Thief 1)
      • (STUB) The Cradle (Thief 3)
      • (STUB) Sapienza (Hitman)
      • (STUB) Silent Cartographer (Halo 1)
    • Multiplayer studies
      • Chill Out (Halo 1)
      • (STUB) de_dust2 (Counter-Strike)
    • Real world studies
      • Disneyland (California, USA)
      • (STUB) Las Vegas (Nevada, USA)
  • Book 4, Learning
    • πŸŽ’Notes for educators
    • Project plans
      • Classic Combat
      • (Unfinished WIP pages)
        • Modern Combat
        • Modern Stealth
        • Exercise: Direct Lighting
        • Exercise: Whiteboard 2D
        • Level Design Portfolio
        • Design Test: Adaptation
        • Exercise: Layout
        • Exercise: Verticality
  • Appendix
    • Tools
      • TrenchBroom
    • Assets & Resources
      • Recommended talks
      • Recommended books
      • Quake resources
        • How to package a Quake map/mod
      • File formats
        • FGD file format
        • MAP file format
        • MDL file format
    • Communities
    • About this book / authors
    • License / copyright
Powered by GitBook
On this page
  • Parsers
  • File format
  • Entities
  • Brush geometry
  • Example .MAP file
  • Sources
Export as PDF
  1. Appendix
  2. Assets & Resources
  3. File formats

MAP file format

file format spec + sample parser code for Quake .MAP files ("Valve" style, mapversion 220)

PreviousFGD file formatNextMDL file format

Last updated 5 months ago

This is a technical file format specification article for programmers.

For mapping tutorials, see instead.

The .MAP file format is a 3D file format devised for Quake 1 (1996).

It is gradually emerging as the standard file type for brush-based levels in any game engine, partly because it is relatively simple to parse and edit. It's similar to how .OBJ has become a simple 3D standard too, even though it lacks many advanced features.

Parsers

There's a good chance someone has already written a generic .MAP parser for your game engine / programming language.

  • C++ ()

  • C# ( or )

  • Rust ( or )

For game engine-specific MAP importers and integrations, see .

File format

  • Text based with curly braces and line breaks

  • Z axis is up (Quake convention), right-handed

  • angle values are Euler degrees from 0-359

    • -1 means "up"

    • -2 means "down"

    • some Quake mods implement rotations as a 3D vector called m_angle

Entities

Every object in a .MAP must be an entity, a generic actor / game object container type.

There are two types of entities:

  • point entities: monsters, items, lights, things with fixed size / no size

  • brush entities: point entities with 3D shapes embedded inside them

    • worldspawn: global static brush entity, the "root" of the entire game world

    • world brushes: brushes bound to worldspawn

Entity schema
{
   // classname: the type of entity
   "classname" "(ENTITY TYPE)"
   
   // moreentity data goes here
   
   {
      // (optional) brush data goes here
   }
}
Point entity
// a Point Entity is a curly brace scope
// with keyvalue pairs surrounded by quotation marks
{
    // classname: the type of entity
    "classname" "info_player_start"
    
    // spawnflags: a bitmask of toggles for the entity
    "spawnflags" "0"
    
    // origin: the entity's position in 3D space
    "origin" "32 32 24"
    
    // but this is just Quake convention, you could put any arbitrary data here
}
Brush entity
// a Brush Entity is like a Point Entity but with 3D brush definitions inside
{
    "spawnflags" "0"
    
    // remember: worldspawn is the traditional root entity of all world brushes
    "classname" "worldspawn"
    // note that 'classname' is often NOT the first keyvalue pair, don't assume!
    
    // a file path to a Quake WAD (texture set)
    "wad" "E:\q1maps\Q.wad"
    {
        // 3D brush geometry information, see next section for details
        ( -16 -64 -16 ) ( -16 -63 -16 ) ( -16 -64 -15 ) __TB_empty [ 0 -1 0 -0 ] [ 0 0 -1 -0 ] -0 1 1
        ( -64 -16 -16 ) ( -64 -16 -15 ) ( -63 -16 -16 ) __TB_empty [ 1 0 0 -0 ] [ 0 0 -1 -0 ] -0 1 1
        ( -64 -64 -16 ) ( -63 -64 -16 ) ( -64 -63 -16 ) __TB_empty [ -1 0 0 0 ] [ 0 -1 0 0 ] 0 1 1
        ( 64 64 16 ) ( 64 65 16 ) ( 65 64 16 ) __TB_empty [ 1 0 0 0 ] [ 0 -1 0 0 ] 0 1 1
        ( 64 16 16 ) ( 65 16 16 ) ( 64 16 17 ) __TB_empty [ -1 0 0 -0 ] [ 0 0 -1 -0 ] -0 1 1
        ( 16 64 16 ) ( 16 64 17 ) ( 16 65 16 ) __TB_empty [ 0 1 0 -0 ] [ 0 0 -1 -0 ] -0 1 1
    }
}

Brush geometry

A brush is a convex 3D shape defined by 4 or more planes.

It is NOT a traditional 3D mesh format made of vertices and triangles. You need an additional map compile step to process the brush data into a usable 3D mesh. For example, Quake maps use an editor-time command line tool called QBSP that outputs a compiled .BSP map file; meanwhile many .MAP parsers for other engines instead generate this mesh at runtime.

Every brush line defines one 3D plane (a triangle) and its texture coordinates:

Brush plane
(x1 y1 z1) (x2 y2 z2) (x3 y3 z3) TEXTURE_NAME [ ux uy uz offsetX ] [ vx vy vz offsetY ] rotation scaleX scaleY

Texturing / UVs

The Quake .MAP file format has two versions: the original Standard version, and an updated format by Valve Software.

Standard texture coordinates:

TEXTURE_NAME offsetX offsetY rotation scaleX scaleY

Valve format texture coordinates:

TEXTURE_NAME [ ux uy uz offsetX ] [ vx vy vz offsetY ] rotation scaleX scaleY

We generally recommend using Valve format, and there's no reason to use standard format other than backwards compatibility / porting old files to the updated format.

ValveFormatTexParse.c
// in the Valve texture format, parsing the file would yield these values in order:
// texname [ ux uy uz offsetX ] [ vx vy vz offsetY ] rotation scaleX scaleY
// NOTE: Valve format doesn't actually use the "rotation" value anymore

// per vertex and per face, coordinates can be calculated like this

Vec3 axisU = Vec3(ux, uy, uz) / scaleX;
Vec3 axisV = Vec3(vx, vy, vz) / scaleY;

for (FaceVertex& v : Vertices)
{
   // Dot product of (v.Point, axisU)
   v.TexU = v.Point.x * axisU.x + v.Point.y * axisU.y + v.Point.z * axisU.z;
   // Dot product of (v.Point, axisV)
   v.TexV = v.Point.x * axisV.x + v.Point.y * axisV.y + v.Point.z * axisV.z;
   v.TexU += offsetX;
   v.TexV += offsetY;
   v.TexU /= Texture->GetWidth();
   v.TexV /= Texture->GetHeight();
}

Example .MAP file

SimpleExampleMap.map
// entity 0
{
    "spawnflags" "0"
    "classname" "worldspawn"
    "wad" "E:\q1maps\Q.wad"
    // brush 0
    {
        ( -16 -64 -16 ) ( -16 -63 -16 ) ( -16 -64 -15 ) __TB_empty [ 0 -1 0 -0 ] [ 0 0 -1 -0 ] -0 1 1
        ( -64 -16 -16 ) ( -64 -16 -15 ) ( -63 -16 -16 ) __TB_empty [ 1 0 0 -0 ] [ 0 0 -1 -0 ] -0 1 1
        ( -64 -64 -16 ) ( -63 -64 -16 ) ( -64 -63 -16 ) __TB_empty [ -1 0 0 0 ] [ 0 -1 0 0 ] 0 1 1
        ( 64 64 16 ) ( 64 65 16 ) ( 65 64 16 ) __TB_empty [ 1 0 0 0 ] [ 0 -1 0 0 ] 0 1 1
        ( 64 16 16 ) ( 65 16 16 ) ( 64 16 17 ) __TB_empty [ -1 0 0 -0 ] [ 0 0 -1 -0 ] -0 1 1
        ( 16 64 16 ) ( 16 64 17 ) ( 16 65 16 ) __TB_empty [ 0 1 0 -0 ] [ 0 0 -1 -0 ] -0 1 1
    }
}

// entity 1
{
    "spawnflags" "0"
    "classname" "info_player_start"
    "origin" "32 32 24"
}

Sources

Entity data and templates are defined by a loaded into the level editor.

Building the 3D mesh based on plane intersections is a bit complicated. Most libraries implement some variant on . His paper explains the math and process in detail, PDF download mirrored below:

The original Standard format had problems storing texture rotations. Given a 3D brush plane normal in XYZ, it discards the longest axis and stores the resulting Vector2. But if the plane is at a 45 degree angle, then the longest axis is now ambiguous and the map compiler must now arbitrarily favor an axis; makes this preference even less predictable, often resulting in unpleasant texture stretching.

Meanwhile, more recent Valve format .MAPs have the "mapversion" "220" key value set in the worldspawn. Valve format 220 resolves the 45 degree ambiguity case by storing UVs in Vector3 space, which also enables some useful UV skewing operations in as well.

For much more complex example .MAP files, see .

Quake resources
https://github.com/stefanha/map-files
https://github.com/Figglewatts/MapParse
https://github.com/LogicAndTrick/sledge-formats
https://github.com/reslario/nomap
https://github.com/QodotPlugin/quarchitect
TrenchBroom
.FGD file
Stefan Hajnoczi's 2001 C++ implementation
floating point imprecision
TrenchBroom
Quake resources
https://quakewiki.org/wiki/Quake_Map_Format
https://www.quakewiki.net/archives/qref/wcs/info.html
Quake MAP Specs (1996) via Internet Archive
244KB
MAPFiles_2001_StefanHajnoczi.pdf
pdf
uploaded from on 23 March 2022
https://github.com/stefanha/map-files