MAP2Q3 -- Quake Map Converter

Copyright (C) Laszlo Menczel, 2006-2012 (laszlo.menczel@gmail.com)

MAP2Q3 is free software provided under the General Public Licence version 2.0. There is absolutely NO WARRANTY, you use this software at your own risk.

Original Quake maps are the intellectual properties of the respective authors. If you wish to distribute a converted map, you should ask for permission to do so. I guess that personal use is OK (and nobody will notice it anyway :-)

1. Introduction

This utility can be used for converting Quake and Quake2 maps to Quake III Arena format. This can be handy if you want to remake a map for Q3A (there are a lot of very good Quake and Quake 2 maps).

The conversion is unfortunately not complete. What you get is the basic level structure (brushes), player starts, light sources, and those items which can be replaced by reasonable alternative items (see Appendix). Other items will be lost during conversion.

All normal brushes (walls, floor, etc.) will be textured using the same Q3A texture 'base_floor/concrete' (this is a neutral looking texture with little detail). Doors and platforms use a very prominent lava texture, while teleports use the the texture 'common/trigger'.

So, you will have to retexture the level, and add the missing items, but at least you will not have to start from scratch when converting (remaking) a Quake level for Q3A.

Light intensity and geometry (sizes, positions) can be scaled. When geometry is scaled up, some (all?) staircases will become unusable and must be later adjusted or replaced by ramps. However, unscaled Q1 maps feel too small in Q3, so scaling is unavoidable in most cases.

Note: It is also possible to work with an unscaled map, and scale it up after the BSP file is compiled. The new map compiler 'Q3map2' can do this, but I don't know what the effect of such scaling will be regarding textures.

2. Usage

2.1. Map conversion

The converter assumes that map files are in 'standard' format produced by most map editors. If you do not have the original Quake map, you should use the WINBSPC utility to convert the BSP file to map format. I recommend version 1.4, it makes a clean map. Maps produced by earlier versions appear to be a bit messy according to my experience.

The program can be run as follows (items between square brackets are optional):


  map2q3 -s src [ -q2 -d dst -e table -l light-scale -g size-scale ]

The switch '-q2' tells the converter that the source map is in Quake2 format. The default is Quake1.

'src' is the name of Q1 or Q2 map and 'dst' is the name of the new Q3A map created, If 'dst' is not specified, the name of the new map will be constructed by changing the extension of the name of the source map to '1q3' or '2q3' depending on whether the switch '-q2' has been specified or not.

'table' is the name of a text file which specifies which entities must be replaced and by what other entities. In the table each line must contain a pair of classnames:


  old-classname [space] new-classname

In each line, only the first two strings are processed, the rest is ignored. There must be _no_ empty lines (except at the end of file), because processing is stopped when an empty line is found. The maximum number of pairs is 63. If 'new_classname' is '*', the old name will be used unchanged. If 'table' is not specified, one of the default table files 'q1.ent' or 'q2.ent' is used (see the Appendix for default replacement rules). Do not delete these files, the program will not work if they are absent and no 'ent' file is specified on the command line. Default entity tables ('q1.ent' and 'q2.ent') are provided in the directory 'testdata'.

'light-scale' is a floating point number by which the intensity values of light entities are multiplied. Light scaling is necessary because the original intensity values in Q3A mostly look bad. If 'light-scale' is not specified, light intensities remain unchanged.

'size-scale' is a floating point number. The geometry (size of brushes, the origin of items) will be scaled by this factor. That is, every coordinate will be multiplied by this value and the result clamped to the nearest integer value below (always round down). In my experience, for Q1 maps a scale factor of 1.25 is sufficient. It is usually not necessary to scale Quake 2 maps. If 'size-scale' is not specified, sizes and coordinates remain unchanged.

2.2. Entity numbering

Sometimes during conversion you may get an error message saying 'Error X in entity N'. Maps produced by WINBSPC, however, do not contain entity numbers, so it may be quite a job to locate the offending object. 'map2q3' can be used for adding entity numbers to the orignal map. After numbers are added, finding and correcting (deleting) an entity is trivial.

For entity renumbering you should run the program as follows (items between square brackets are optional):


  map2q3 -enum -s map-name [ -q2 -d new-name ]

where 'map-name' is the name of map in which entities should be numbered. 'new-name' is the name of the new (numbered) map file. If it is not specified, the old name will be used with extension 'q1n' or 'q2n' (this depends on whether '-q2' has been specified or not).

3. Implementation notes

Fortunately, the formats of Q1, Q2 and Q3A maps are similar. The largest difference is in the brush specification as shown below.


Quake:

{
( c11 c12 c13 ) ( c21 c22 c23 ) ( c31 c32 c33 ) texture-name v1 v2 v3 v4 v5
....
....
}

Quake 2 and Quake III Arena:

{
( c11 c12 c13 ) ( c21 c22 c23 ) ( c31 c32 c33 ) texture-path v1 v2 v3 v4 v5 v6 v7 v8
....
....
}

c11, c12, etc. are the coordinates of points defining faces (bounding planes) of brushes. They seem to be used in the same way in all three map formats.

v1, v2, etc. are texture flags and alignment values. For Q3A, v1 to v3 and v6 to v8 are zero in 99 percent of the cases, while v4 and v5 are usually 0.5. These will be the values used in the new map file. For trigger entities v1 is '-4'.

Transformation of brushes:


  while ! end-of-worldspawn-section
  {
    read the next brush block
    replace texture definition of brush
    if geometry-is-scaled
      adjust coordinates of brush faces
    write to output file
  }  

Transformation of entities:


  while ! end-of-file
  {
    read the next entity block
    if item-is-replacable
    {
      replace the "classname" string
      if entity-is-light
      {
        if light-is-scaled
          adjust light by scaling factor
      }          
      if geometry-is-scaled
        adjust coordinates of origin
      if entity-contains-brush
      {
        replace texture definiton of brush(es)
        if geometry-is-scaled
          adjust coordinates of brush faces
      }
      write to output file
    }
    else
      discard the item
  }

4. Compiling

Under Linux it is as simple as executing the command 'make' in the directory that contains the source. No extra dependencies are required.

Under Win32 you will need the MinGW/Msys compiler system. Install the package to your home directory within Msys and run the command 'make' from this directory.

5. Appendix -- Default entity replacement rules

The asterisk characters in the second column indicate that the corresponding emtity exists in Quake 3 and will not be changed.


Quake 1:
------------------------------------------------
func_plat                      *
func_door                      *
info_null                      *
info_player_deathmatch         *
info_teleport_destination      target_position
item_armor1                    item_armor_combat
item_armor2                    item_armor_combat
item_armorInv                  item_armor_body
item_artifact_envirosuit       item_enviro
item_artifact_invisibility     item_invis
item_artifact_super_damage     item_quad
item_cells                     ammo_lightning
item_health                    *
item_rockets                   ammo_rockets
item_shells                    ammo_shells
item_spikes                    ammo_cells
light                          *
trigger_hurt                   *
trigger_multiple               *
trigger_push                   *
trigger_teleport               *
weapon_grenadelauncher         *
weapon_lightning               *
weapon_nailgun                 weapon_plasmagun
weapon_rocketlauncher          *
weapon_supernailgun            weapon_plasmagun
weapon_supershotgun            weapon_shotgun

Quake 2:
-------------------------------------------------
ammo_bullets               *
ammo_cells                 *
ammo_grenades              *
ammo_rockets               *
ammo_shells                *
ammo_slugs                 *
func_button                *
func_door                  *
func_group                 *
func_plat                  *
func_rotating              *
func_timer                 *
func_train                 *
info_notnull               *
info_null                  *
info_player_deathmatch     *
info_player_intermission   *
item_armor_body            *
item_armor_combat          *
item_armor_shard           *
item_enviro                *
item_health                *
item_health_large          *
item_health_mega           *
item_health_small          *
item_quad                  *
light                      *
misc_teleporter            trigger_teleport 
misc_teleporter_dest       *
path_corner                *
target_laser               *
target_speaker             *
trigger_always             *
trigger_hurt               *
trigger_multiple           *
trigger_push               *
weapon_bfg                 *
weapon_chaingun            weapon_lightning
weapon_grenadelauncher     *
weapon_hyperblasters       weapon_plasmagun
weapon_machinegun          *
weapon_railgun             *
weapon_rocketlauncher      *
weapon_shotgun             *
weapon_supershotgun        weapon_shotgun