Information on 6.50 .env files

This web page contains sample code and information on the X-Plane 6.xx .env file formats.  I try to keep this page as up to date as possible, but if it appears to be behind, please email me.

Authors: Read about the new packaged scenery format and how to optimize scenery.
Authors: Read about how land uses work, what they look like, and what's changed with XP 6.13 and beyond!

Sample Code

NOTE: The sample code is now up to date for 6.50.  X-Plane7 as of this writing is still using 6.50 .env files.

Simply implement for yourself the functions that are declared in EnvParser.h but not EnvParser.c; they will be called when you parse a .env file.

The Env Parser itself:

EnvParser.h
EnvParser.c
All code, including support code and examples...
Source Code

Tools

I have Macintosh-specific .env file processing tools; they are very rough with poor user interfaces and I use them primarily for my own authoring work.  However, if you need special .env processing done, drop me an email; I may have something you can use.

File Format Information

6.x .env files are binary files.  They can be either little or big endian, depending on the program that wrote them, so all programs must be prepared to handle endian-swapping issues.  The layout of a 6.06 .env file is:
  1. Header
  2. Vertex Data (6.06 format)
  3. Obstacle Placements
  4. Custom Textures (6.06 format)
The format of a 6.10-6.50 .env file is slightly different:
  1. Header
  2. Vertex Data (6.10 format)
  3. Obstacle Placements
  4. Road, Trail, Railroad, and Power Line Paths and optionally taxiways and maybe rivers
  5. Custom Textures (6.10 format)
The information below is broken down into the information for version "6" and then all higher versions; most versions from "61" on are very similiar to each other.  The .env format had major changes from version 6 to 61.

The information below details the specifics of each section.  All strings are ASCII.  Directory separators should match their native platform.

Header

The 6.x .env file start with a five-byte header:
 
Field Length Data Type Contents Meaning
Endianness of the file 1 byte char 'a' or 'i' Big Endian or Little Endian
Version 4 bytes long int 6, 61, 631 or 650 Native Endian Version

The header starts with a 1-byte character: lower case 'a' ("Apple") indicates Big Endian, lower case 'i' ("Intel") indicates Little Endian.  Except where otherwise noted, all 2-byte and 4-byte integers and 4-byte floating point values will be in the endianness specified in hte header.

The version identifies which format the sections below will be in as well as which layout the file consists of; see the charts above for which sections are included in which file version.

NOTE: previous versions of this spec were wrong; the version is an endian native 32-bit long int. 

Every version of X-Plane 6.xx is backward compatible with previous forms of the .env file back to the original.  This chart indicates what X-Plane application is required to read a given file version.  Each version of WorldMaker writes the most recent version of the format it knows about.

File format Version
Minimum Version of X-plane to read File
Major Change from Previous Version
6
600
Grid Size Changed to 201x151
61
610
Land Uses, vector roads, etc.
631
640
Taxiways added
650
650
Vector Rivers/Streams added

X-Plane 7 reads all four version 6 .env formats listed above, but only writes the 650 file format.

Vertex Data

The vertex data section contains definitions of the grid points that form the actual landscape, terrain mesh, etc.  Each 6.x .env file is organized into a grid of 151 horizontal and 201 vertical grid points, forming 150 x 200 quadrilaterals.  Vertices occur in order in the file from the lower left to right of the file, then go to the next higher row on the left, etc, as illustrated by the figure on the right.

The lower left vertex corresponds to the latitude and longitude the .env file is named after.  In the above example, this would be the .env tile for +42 latitude, +71 longitude.  Each .env file covers one degree of latitude and longitude, with the latitude of the top vertices and longitude of the right vertices being an even degree multiple.

For custom textures and 6.06 default textures, a quad's texture is specified by the vertex that specifies its lower left corner; the upper and rightmost vertices textures are ignored.  For 6.10 default textures (based on land use), the corner of each quad is separately textured by the land use of that vertex.  Each vertex thus creates a 1x1 quad textured patch that is centered around the vertex.

Each version 6.06 vertex has the following structure:
 
Field Length Type Contents
Latitude 4 Bytes float The vertices latitude in decimal degrees
Longitude 4 Bytes float The vertices longitude in decimal degrees
Altitude 4 Bytes float The vertices altitude in meters above sea level
Texture Information 4 Bytes Integer Texture Properties (see below)

The latitude, longitude, and altitude are simply stored as floating point coordinates.  The texture information is further encoded as decimal digits with the following interpretation:

 XYSRUCTTT
Digit Meaning
X A horizontal offset into the texture.
Y A vertical offset into the texture
S A scaling factor to increase the texture's size, 0 = normal, 1 = double the scale, etc.
6.13 only: for custom textures, this field is the same.  For default land use, this is a join code.
R Rotation (1 = 90 CCW, 2 = 180 CW, 3 = 90 CW, 4 = None)
U Land Use.  0 = Land, 1 = Water, 2 = City.  (6.06 Only!)
0 for 6.10
C Custom Texture (1 = yes, 0 = default land use/texture)
TTT The texture number.

Each texture field contains a texture number between 0 and 999.  For custom textures, this is a 1-based index into the custom texture table found at the end of the file.  For built-in textures, this is one of the 16 default scenery codes (for 6.06) or a land-use code (for 6.10).  The Custom Texture Field contains a flag, 0 or 1 to determine which kind of texture this is.

X-Plane 6.06 featured a flag that specified the "land use" for the vertex; a 1 in this field indicated that the quad to the upper right of the vertex was water.  A 2 indicated that dynamic scenery shoud be drawn; this dynamic scenery was always houses except for a few special-case default textures.  Since 6.10 features a wide variety of land use in the texture number field this field is not used in 6.10 and should always contain 0.  6.10 will place dynamic scenery based on land use, etc.

The rotation field specifies one of four possible orientations for the texture as specified in the table.  Any custom texture may be rotated, but default textures may only be rotated in 6.06.

X-Plane can spread a texture over many quads.  This is actually done by only drawing a part of the texture on each quad.  To specify this behavior, a scaling factor may be applied.  The scaling factor is the number of times to increase the texture's apparent size to the user minus one, e.g. 0 = no scale, 1 = double, 2 = triple, etc.  This effectively reduces the amount of texture shown in the specific quad by 1/(scale+1).  The X and Y offsets indicate which part of the texture to use since each quad will only show a part of it.  An offset of 0 indicates the lower left corner of the texture; positive X is right and positive Y is up.  The maximum value for these offsets is the scale value.

Two things should be noted about this scheme that might not be apparent from the use of WorldMaker:

For X-Plane 6.13 the scaling code is shared; for default (land use-style) terrain this code is now a join code.  For 6.10 files, this should always be 0 for non-custom terrain (since non-custom terrain cannot be stretched.)  Please read this to understand join codes.

A join code applies to the quad for which it is the lower-left (southwest) corner.  The join code indicates how the corners of this quad will or won't connect if they have the same land use.  The join code should be 0 if the corners are of different land use types.
 
Code Connect lower left to upper right? Connect lower right to upper left? Description Picture
0 X-Plan decides X-Plan decides This code indicates that X-Plane may decide the joining pattern and is used for backward compatibility.
1 Yes No This connects one diagonal.
2 No Yes This connects the other diagonal
3 No No This keeps both diagonals disconnected.

Join codes greater than 3 are reserved and should not be used.

The X-Plane 6.06 default texture numbers were as follows:
 
Number Texture Number Texture Number Texture Number Texture
0 Grass 4 Commercial 8 3/4 Grass, 1/4 Mountain 12 1/4 Grass, 3/4 Water
1 Mountains 5 Industrial 9 1/4 Grass, 3/4 Mountain 13 Half Grass/Residential
2 Water 6 Field 10 Half Grass/Water 14 3/4 Grass, 1/4 Residential
3 Residential 7 Half Grass/Mountains 11 3/4 Grass, 1/4 Water 15 1/4 Grass, 3/4 Residential

A 6.10 vertex takese the following form:
 
Field Length Type Contents
Latitude/Longitude Code 4 Bytes Integer An encoded latitude and longitude value.
Altitude 2 Bytes Big Endian signed integer The altitude also encoded
Texture Code 4 Bytes Integer Texture properties as described above.

The latitude and longitude of a vertex in 6.10 are compressed using the following scheme:

  1. The value of the latitude and longitude of the lower left vertex of the .env file (the one the .env file is named after) is subtracted from the vertices latitude and longitude.  This lower left corner latitude and longitude is the reference laitutde and longitude.  The resulting latitude and longitude deltas are between 0.0 for the left and lower edges and 1.0 for the upper right edges.
  2. The latitude and longitude deltas are then multiplied by 9999.0 each and rounded to the nearest even integer.

  3. The latitude is multiplied by 10000 and they are then summed.
The effective result of this encoding is two numerators over 9999 stored in decimal form that describe fractions of degrees.

The altitude is stored as meters above sea level plus 10000.  This number is always big endian; it is the only part of the .env file that is like this.

The texture code for 6.10 is the same as 6.06 except that default texture numbers are land uses and the land use field is ignored.

Obstacle Placements

The obstacle data section contains a list of obstacles and their placements.  This section is variable lengthed and features a stop-marker to indicate the end.  However, there is a finite limit to the number of obstacles that canbe placed in the section.  Right now I do not know the value of obsDIM.

Each object starts off with an integer type code.  This is a 4-byte signed integer in the platform-native endian format.  A value of 99 indicates that this is the end of the obstacle placement section; no other data for obstacles follows.  If the value is anything other than 99, this value is an object type code.  The following fields are then read:
 
Field Length Type Contents
Latitude 4 Bytes Float The latitude of the obstacle.
Longitude 4 Bytes Float The longitude of the obstacle.
Rotation/Heading 4 Bytes Float The elevation of the default obstacle in meters or the rotation of the custom obstacle in degrees.

The following obstacle types are defined:
 
Obstacle Kind Description Obstacle Kind Description
1 Control Tower 5 Water Tower
2 Sky Scraper 6 Smoke Stacks
3 Radio Tower 7 Unused (reserved)
4 Power Tower 8 Custom Obstacle

The latitude and longitude of the obstacle are in decimal degrees.  The rotation/heading field is the height of the top of the obstacle above ground for the default obstacles.  For a custom obstacle, it specifies the number of degrees to rotate the obstacle from its natural orientation.

For custom textures, a 150-character obstacle name follows the heading field.  This field is padded with 0s and contains the name of the file (minus the .obj extension) including any partial paths using the system-native directory indicator from the Custom Objects directory.  For example the string

MyFunkyTrains\SteamEngine
woudl expand to the full file path
C:\Program Files\X-System 6.10 Folder\Resources\Custom Objects\MyFunkyTrains\SteamEngine.obj

Road, Trail, Railroad,  Power Line Paths and taxiways

The path section contains specifications of paths for roads, trails, railroads,  powerlines and possiblt taxiways.  Each of the types of paths has the same format, and they occur in the previously listed order.

Each path consists of a series of latitude/longitude values encoded into a single integer, the same way 6.10 vertices are encoded.  This integer is a 4-byte native endian int.  Two special codes must be noted:

Because 99 has special meaning, there is one latitude/longitude code point for a non-ending path point that cannot be used because it is used as the end of file marker.  To gaurantee file integrity, when writing path points always check for an accidental encoding of 99 from a valid lat/lon code and add or subtract one to prevent forming an end of file marker.  This encoding will be referred to as standard vector encoding in the chart below.

Taxiways are only present in the 6.40+ version of the file, noted by a version number of "631" on the file header. Taxiways are different than other paths.  Taxiways have the following format:

This encoding will be referred to as floating point encoding in the chart below.

Rivers are included in version 6.50+ of the file, noted by a version of "650" in the file header.  Rivers are encoded in the same format as roads, etc.

The chart below summarizes the vectors included in an .env file in order they appear.

Data
Encoding
Minimum File Version
Minimum X-Plane Version
Roads
Standard
61
610
Trails
Standard
61
610
Railroads
Standard
61
610
Powerlines
Standard
61
610
Taxiways
Floating Point
631
640
Rivers
Standard
650
650

Custom Texture Table

The last part of the .env file is the custom texture table.  Each entry is simply a 150-character 0-padded string indicating a texture name (without the .bmp extension).  Like obstacle paths again, a partial path may be specified from the Custom Object Textures folder.

The custom texture table simply ends at the end of file; 6.06 files must contain empty entries (containing "Untitled" plus zero padding) for the entire maximum size of the file; 6.10 texture tables are variable length and may end when no textures are available.  Unused entries should contain a zero-padded "Untitled" entry.  The maximum size of the texture table may have been 100 textures in previous X-Plane revisions, but is 500 textures long in 6.10.



Questions, comments, corrections?  Email: bsupnik@xsquawkbox.net