Scenery Compiler

This compiler processed source files in a 'language' that I developed and produced binary graphics files for Microsoft's Flight Simulator (FS) versions 5.1 and 95. The output files were used directly in the simulator and had the filename extension .BGL (BAO Graphics Language), which is a binary format and contains structural elements to implement the geographical hierarchy and opcodes such as vertex definition, textured and untextured polygon drawing, line drawing, calls, shadow calls, rotation calls, ..., control flow opcodes such as various types of 'if' statements.

Back then, the simulator's simple graphics engine did not use Z-buffering. It did sort objects according to the distance of their coordinate system origins (Reference points) to the view point. Within each object, the designer had to control drawing order using binary separation planes (defined via distance and normal vector). My compiler made the task of calculating these BSPs easier by allowing to specify three vertexes and whether they are in clockwise or counterclockwise order.

I developed this compiler in the C++ programming language around 1994/1995 using IBM's Visual Age C++ compiler toolset. The compiler consisted of an estimated 200+ classes, probably more, would need to count them.

The following example shows the source code for the control tower next to the International Terminal of Perth Airport (PER/YPPH). This is still a simple example. The curved International Terminal had a lot more BSPs to control drawing order.

Scenery(id=1,
        B=S33:00, T=S31:00, L=E113:00, R=E117:00,
        Text="Perth Scenery"
       )
{
   Section(VISUAL)
   {
      VisRngN(Pos=S31:56:30 E115:58:20, Vis=255km)
      {
         
... other objects go here ...
         // -------------------
         // Perth Control Tower
         // -------------------
         Obj3D(Pos=S31:56:39.2937 E115:58:21.1313, Scale=1m)
         
// The Obj3D statement created a whole lot of
         // output op codes depending on possible optional parameters

         {
            
// These statements create simple horizontal
            // binary separation planes (BSPs) to split
            // the tower into multiple segments to control
            // drawing order. Other arbitrary BSPs were also
            // possible using the a statement called VecTest
            // together with the PlaneCLW() or PlaneCCW()
            // plane definition primitives.
            IfVarRange(min=sv(80m), max=32767, var=varViewPtA)
            {
               Call TowerBase;
               Call TowerTop;
               Call TowerAntennas;
            }
            else
            {
               IfVarRange(min=sv(76m), max=32767, var=varViewPtA)
               {
                  Call TowerBase;
                  Call TowerAntennas;
                  Call TowerTop;
               }
               else
               {
                  Call TowerAntennas;
                  Call TowerTop;
                  Call TowerBase;
               }
            }
            Jump EndPerthTower;

         TowerBase:
            Call TowerBaseSegment;
            RotCall TowerBaseSegment(Rot=90);
            RotCall TowerBaseSegment(Rot=180);
            RotCall TowerBaseSegment(Rot=270);
            Return;

         TowerTop:
            Call TowerTopSegment;
            RotCall TowerTopSegment(Rot=90);
            RotCall TowerTopSegment(Rot=180);
            RotCall TowerTopSegment(Rot=270);
            Return;

         TowerAntennas:
            Call TowerAntennaSegment;
            RotCall TowerAntennaSegment(Rot=90);
            RotCall TowerAntennaSegment(Rot=180);
            RotCall TowerAntennaSegment(Rot=270);

            Points(First=44)
            {
               [ 0m, 0m, 80m], // 44
               [ 0m, 0m, 86m]  // 45 (very top)
            }
            LinePt { 44,45 }
            IfVarAnd(var=varTOD, mask=0x06)
            {
               IfVarAnd(var=varTimer1, mask=0xf0f0)
               {
                  Colour(Line=n_red, Surface=n_red);
                  DotPt { 45 }
               }
            }
            Return;

         TowerBaseSegment:
            Points
            {
               [4m, 0m, 0m], // 0
               [3m, 3m, 0m], // 1
               [0m, 4m, 0m], // 2

               [4m, 0m, 56m], // 3
               [3m, 3m, 56m], // 4
               [0m, 4m, 56m], // 5

               [12m, 0m, 75m], // 6
               [ 9m, 9m, 75m], // 7
               [ 0m,12m, 75m], // 8

               [11m, 0m, 76m], // 9
               [ 8m, 8m, 76m], // 10
               [ 0m,11m, 76m], // 11
               [ 0m, 0m, 76m]  // 12 (centre)
            }
            Colour(Surface=d_light_grey);
            ShadedPoly(Plane=PlaneCCW(0,1,4)) { 0,1,4,3 }
            ShadedPoly(Plane=PlaneCCW(1,2,5)) { 1,2,5,4 }

            Bitmap(File="PERAPPH.RHV");
            ResetTexture;
            TexPoly(Plane=PlaneCCW(3,4,7), Shading=yes)
            {
               3, ( 0, 40),
               4, (31, 40),
               7, (31, 79),
               6, ( 0, 79)
            }
            ResetTexture;
            TexPoly(Plane=PlaneCCW(4,5,8), Shading=yes)
            {
               4, ( 0, 40),
               5, (31, 40),
               8, (31, 79),
               7, ( 0, 79)
            }

            Colour(Surface=d_light_grey);
            ShadedPoly { 6,7,10,9 }
            ShadedPoly { 7,8,11,10 }

            // this is the lid just below the windows
            ShadedPoly(Plane=PlaneCCW(9,10,11)) { 12,9,10,11 }
            Return;

         TowerTopSegment:
            Points(First=13)
            {
               [ 7m, 0m, 76m], // 13
               [ 5m, 5m, 76m], // 14
               [ 0m, 7m, 76m], // 15

               [ 8m, 0m, 79m], // 16
               [ 6m, 6m, 79m], // 17
               [ 0m, 8m, 79m], // 18
               [ 0m, 0m, 79m], // 19 (centre)

               [ 7m, 0m, 80m], // 20
               [ 5m, 5m, 80m], // 21
               [ 0m, 7m, 80m], // 22
               [ 0m, 0m, 80m]  // 23 (centre)
            }
            // this draws the transparent windows
            Colour(Surface=0x6877); // this is the transparent window colour
            ShadedPoly { 13,14,17,16 }
            ShadedPoly { 14,15,18,17 }

            // this draws the lid
            Colour(Surface=d_light_grey);

            // final lid visible from underneath
            ShadedPoly(Plane=PLaneCLW(16,17,18)) { 19,16,17,18 }

            // border around the lid (between final lid and windows)
            ShadedPoly { 16,17,21,20 }
            ShadedPoly { 17,18,22,21 }

            // the final lid visible from above
            ShadedPoly(Plane=PLaneCCW(20,21,22)) { 23,20,21,22 }
            Return;

         TowerAntennaSegment:
            Points(First=40)
            {
               [ 7m, 0m, 80m], // 40
               [ 5m, 5m, 80m], // 41
               [ 7m, 0m, 83m], // 42
               [ 5m, 5m, 83m]  // 43
            }
            // antennas:
            Colour(Line=d_white);
            LinePt { 40,42 }
            LinePt { 41,43 }
            Return;

         EndPerthTower:
         }
      } // end VisRng
   } // end Section(VISUAL)
} // end Scenery