Format of the Cvx BGL Files

From FSDeveloper Wiki
Jump to navigationJump to search

Introduction

CVX Files can be read by the TmfViewer.exe application provided with the FS SDK. They contain TERRAIN_VECTOR_DB sections. These sections and subsections describe the different layers (roads, railways, water polygons, etc.) along with the geographical coordinates.
In this document, I will often take examples from the cvx2815.bgl file since that is the one I used to figure out the structure of the cxv file and it describes the area I live in. This file is located in: (....)\Microsoft Flight Simulator X\Scenery\0301\scenery.

BGL Common Format

All BGL files share the same generic format. A BGL file is made of a header, sections, subsections and subsection data. Subsections are children of sections. The sections are here to help us locate the subsections in the file. Data specific information is contained in the subsections data and their format is dependent on the section type.
A BGL file always start with a header (Size = 0x38 bytes), followed by a list of section pointers. The number of section pointers is defined in the header.

File Header

The header consists of 0x38 (56) bytes. It contains the number of sections defined in the file as well as the bounding geographical coordinates of the covered squared area.

Offset Number of bytes Description
0x00 4 - DWORD Magic Number #1 – Must be 0x01, 0x02, 0x92, 0x19
0x04 4 - DWORD Header size : 0x38
0x08 4 - DWORD Unknown – Maybe a timestamp
0x0C 4 - DWORD Unknown – Maybe a timestamp
0x10 4 - DWORD Magic Number #2 – Must be 0x03, 0x18, 0x05, 0x08
Maybe to identify the FS version
0x14 4 - DWORD The number of sections following this header.
0x18 32 Array[8] of unsigned integers (DWORD).
Each value describes the bounding coordinates of a squared subarea.

Even if 8 slots are provided, it is not necessary to have all 8 values filled. The list stops at the first null (0x00000000) value.
I don’t know what these subareas are used for.
To compute the bounding coordinates, please see Annexe A.
To get the bounding coordinates of the square area covered by the file, just keep the minimal and maximal values of each bounding coordinates.



Example

For example, in cvx2815.bgl :

Offset Values Description
0x00
01 02 92 19
Magic Number #1
0x04
38 00 00 00
Header size
0x08
EF 82 DF E2
0x0C
E8 C7 C6 01
0x10
03 18 15 08
Magic Number #2
0x14
01 00 00 00
1 section following this header
0x18
E8 07 02 00
MinLatitude(Deg) = 46.40625
MaxLatitude(Deg) = 47.8125
MinLongitude(Deg) = -75.0
MaxLongitude(Deg) = -73.125
0x1C
E9 07 02 00
MinLatitude(Deg) = 46.40625
MaxLatitude(Deg) = 47.8125
MinLongitude(Deg) = - 73.125
MaxLongitude(Deg) = -71.25
0x20
EA 07 02 00
MinLatitude(Deg) = 45.0
MaxLatitude(Deg) = 46.40625
MinLongitude(Deg) = -75.0
MaxLongitude(Deg) = -73.125
0x24
EB 07 02 00
MinLatitude(Deg) = 45.0
MaxLatitude(Deg) = 46.40625
MinLongitude(Deg) = -73.124
MaxLongitude(Deg) = -71.25
0x28
00 00 00 00
0x2C
00 00 00 00
0x30
00 00 00 00
0x34
00 00 00 00

You’ll notice that only 4 subareas are defined (on a possibility of 8) and the last 4 available slots are empty (Value = 0)
So the bounding coordinates of the area covered by cvx2815.bgl are:

MinLatitude(Deg) = 45.0
MaxLatitude(Deg) = 47.8125
MinLongitude(Deg) = -75.0
MaxLongitude(Deg) = -71.25

Sections

Following the header, at offset 0x38, there are as many sections as defined at offset 0x14 of the header. Each section has a size of 20 bytes and has the following structure:

Relative Offset Number of bytes Description
0x00 4 - DWORD Section type: one of the following values:
  • None = 0x0
  • Copyright = 0x1
  • Guid = 0x2
  • Airport = 0x3
  • Nav = 0x13
  • Ndb = 0x17
  • Marker = 0x18
  • Boundary = 0x20
  • Waypoint = 0x22
  • Geopol = 0x23
  • SceneryObject = 0x25
  • AirportNameIndex = 0x27
  • VorIcaoIndex = 0x28
  • NdbIcaoIndex = 0x29
  • WaypointIcaoIndex = 0x2A
  • ModelData = 02B
  • AirportSummary = 0x2C
  • Exclusion = 0x2E
  • TimeZone = 0x2F
  • TerrainVectorDb = 0x65
  • TerrainElevation = 0x67
  • TerrainLandClass = 0x68
  • TerrainWaterClass = 0x69
  • TerrainRegion = 0x6A
  • PopulationDensity = 0x6C
  • AutogenAnnotation = 0x6D
  • TerrainIndex = 0x6E
  • TerrainTextureLookup = 0x6F
  • TerrainSeasonJan = 0x78
  • TerrainSeasonFeb = 0x79
  • TerrainSeasonMar = 0x7A
  • TerrainSeasonApr = 0x7B
  • TerrainSeasonMay = 0x7C
  • TerrainSeasonJun = 0x7D
  • TerrainSeasonJul = 0x7E
  • TerrainSeasonAug = 0x7F
  • TerrainSeasonSep = 0x80
  • TerrainSeasonOct = 0x81
  • TerrainSeasonNov = 0x82
  • TerrainSeasonDec = 0x83
  • TerrainPhotoJan = 0x8C
  • TerrainPhotoFeb = 0x8D
  • TerrainPhotoMar = 0x8E
  • TerrainPhotoApr = 0x8F
  • TerrainPhotoMay = 0x90
  • TerrainPhotoJun = 0x91
  • TerrainPhotoJul = 0x92
  • TerrainPhotoAug = 0x93
  • TerrainPhotoSep = 0x94
  • TerrainPhotoOct = 0x95
  • TerrainPhotoNov = 0x96
  • TerrainPhotoDec = 0x97
  • TerrainPhotoNight = 0x98
  • FakeTypes = 0x2710
  • IcaoRunway = 0x2711
0x04 4 - DWORD Unknown
0x08 4 - DWORD Number of subsections in the section.
0x0C 4 - DWORD File offset = position in the file where the first subsection starts.
0x10 4 - DWORD Total Size (in bytes) of all the subsections. This value should be equal to : 16 * nbSubSections


Note that a cvx*.bgl file have at least a section of type 101 (0x65) = TerrainVectorDb.

Example

For example, in cvx2815.bgl, the only one section, at offset 0x38, has this:

Offset Values Description
0x38
65 00 00 00
TerrainVectorDb = 101 = 0x65
0x3C
01 00 00 00
Unknown
0x40
8D 07 00 00
0x078D = 1933 subsections in the section
0x44
01 CD 1F 00
0x1FCD01 = File offset = position in the file where the first subsection starts.
0x48
D0 78 00 00
Size (in bytes) =0x78D0 = 30928 bytes

Subsections

A subsection contains information about the geographical area it covers. If also contains the file offset of the subsection’s data. All subsections of a same section are contiguous meaning that they are following each other in the file.
A subsection has the following structure:

Relative Offset Number of bytes Description
0x00 4 - DWORD Bounding coordinates of a squared area covered by this subsection. See Annexe A.
0x04 4 - DWORD Number of records (for RIFF subsections ?)
0x08 4 - DWORD File Offset = Position in the file of the subsection’s data
0x0C 4 - DWORD Size of the subsection’s data


The interpretation of the section data depends on the section type.

Example

Offset Values Description
0x1FCD01
00 FA 81 00
Bounding coordinates:
  • MinLatitude(Deg) = 47.63671875
  • MaxLatitude(Deg) = 47.8125
  • MinLongitude(Deg) =- 75.0
  • MaxLongitude(Deg) = -74.765625
0x1FCD05
00 00 00 00
Number of records = 0
0x1FCD09
4C 00 00 00
0x4C = File Offset = Position in the file of the subsection’s data.
0x1FCD0D
DD 00 00 00
Size of the subsection’s data = 0xDD = 221 bytes.

Subsection for section of type Terrain_Vector_DB

This type of subsection contains values to retrieve geographical coordinates, organized as segments. These coordinates are used to draw lines (roads, railways, etc.) or polygons (lakes, airport bounds, etc.).

The Bgl file does not contain geographical coordinates per se but offsets to the lower left corner of the covered area (minimum latitude / longitude). The covered area is also defined in the subsection.

The data is organized in lists of pair values (One pair per geographical coordinate). Each pair can then be used to compute the final geographical coordinates. There are 3 ways to retrieve these lists of pairs.

The first value in a pair is longitude-related. The second value is latitude-related.

The algorithm to compute the geographical coordinates from a pair is:


void convertToCoordinates (double longitude_related_Value, double latitude_related_Value)
{
    var deltaLongFactor = (MaxLongitudeDeg - MinLongitudeDeg) * 0.000030517578125;
    var deltaLatFactor = (MaxLatitudeDeg - MinLatitudeDeg) * 0.000030517578125;

    var LongitudeDeg = MinLongitudeDeg + (longitude_related_Value * deltaLongFactor);
    var LatitudeDeg = MinLongitudeDeg + (latitude_related_Value * deltaLatFactor);
}

Subsection Header

Each subsection starts with the following structure:

Relative Offset Number of bytes Description
0x00 4 - DWORD 6
I did not find a cvx file with a value other than 6.
0x04 4 - DWORD Bounding coordinates of a squared area covered by this subsection. See Annexe A.
0x08 4 - DWORD 0
I did not find a cvx file with a value other than 0.
0x0C 4 - DWORD Number of entities.
An entity is a list of segments. (a segment is a list of points).
0x10 4 - DWORD Number of bytes in the signatures buffer.
The signatures buffer contains some GUIDs identifying the segments of this subsection. Some GUID values (like the Texture) are not used by the TmfViewer application.


It also contains some extra bytes the use of it is unknown.
The GUID values are defined at: http://msdn.microsoft.com/en-us/library/cc707102.aspx - Terrain and Scenery
(See Vector Attributes for the Shp2Vec Tool)
The usable GUID values are:

{359C73E8-06BE-4FB2-ABCB-EC942F7761D0} Airport Bounds
{91CB4A9B-9398-48E6-81DA-70AEA3295914} Parks
{EA0C44F7-01DE-4D10-97EB-FB5510EB7B72} Water Polygons (GPS)
{956A42AD-EC8A-41BE-B7CB-C68B5FF1727E} Water Polygons
{AC39CDCB-DB78-4628-9A7C-051DA7AC864A} Exclusions
{0CBC8FAD-DF73-40A1-AD2B-FE62F8004F6F} Shorelines
{714BF912-F9DF-467E-80AE-28EB27374DBD} Streams
{C7ACE4AE-871D-4938-8BDC-BB29C4BBF4E3} Utilities
{33239EB4-D2B8-46F5-98AB-47B3D0922E2A} Railways
{560FA8E6-723D-407D-B730-AE08039102A5} Roads
{54B91ED8-BC02-41B7-8C3B-2B8449FF85EC} Freeway Traffic Roads
0x14 4 - DWORD Maximum allowed number of signature offsets.
Signature offsets (see Entity Structure below) are offset into the signature buffer and point to the GUID identifying the corresponding segment.
0x18 4 - DWORD Maximum number of pair values per segment for this subsection.
= 2 * maximum number of points per segment
0x1C 4 - DWORD 0
I did not find a cvx file with a value other than 0.
0x20 N Signatures buffer containing <N> bytes, where N is defined at relative offset 0x10

Entity Structure

Then for each entity (the number of entities is defined at relative offset 0x0C of the subsection header (see Subsection Header above), we have the following structure:

Relative Offset Number of bytes Description
0x00 4 - DWORD Number of segments in the entity.
0x04 4 - DWORD Segment type:
  • 1 – Points only
  • 2 – Lines
  • 3 - Polygons
0x08 2 - WORD Number of signatures offsets (Must be < 0x64).
0x0A 4 - DWORD N = Number of signatures offsets (see above).
Will contain the offsets into the signature buffer.

Segment Structure

Then for each segment (the number of segments is defined at relative offset 0x00 of the entity structure (see Entity Structure above), we have the following structure:

Relative Offset Number of bytes Description
0x00 4 - DWORD Number of points (geographical coordinates) in this segment.
0x04 1 - BYTE AddFlag : Determines how many additional bytes to read after the data buffer has been read.
0x05 1 - BYTE Method used to build the pairs list from the data buffer.
Possible values are 1,2 or 3
  • 1 – Method1
  • 2 – Method2
  • 3 – Method3


Note: I did not find a cvx file with a value of 3 but it looks like Method3 read the pairs list directly from the data buffer without any extra processing.
Methods 1 and 2 need some extra processing. See below.

0x06 Data buffer – Size may vary depending on the method used. See below.
- N N depends on the AddFlag defined at relative offset 0x04.
  • If AddFlag = 0 then N = 0
  • If AddFlag = 1 then N = 4 x NumberOfPoints (as defined at relative offset 0x00)
  • If AddFlag = 2 then N = 4


I don’t know what the use of these extra bytes is.

Method 1

By far the most complex method. I have some code for it. But I still have to figure out the big picture.

The data buffer for this method has the following structure:

Relative offset Number of bytes Description
0x00 4 - DWORD First Longitude Data - First value in the list of pairs.
0x04 4 - DWORD First Latitude Data - First value in the list of pairs.
0x08 4 - DWORD LongitudeData Increment
0x0C 4 - DWORD LatitudeData Increment
0x10 4 - DWORD Number of bytes
0x14 N N is the number of bytes defined above at relative offset 0x10.
These N bytes are the raw data used to build the final list of pairs.

Method 2

Example

Annexe A