Object Design Example

At Flight Simulator startup, the user's plane is sitting on the runway at Meigs Field in Chicago, facing north. Suppose, for the sake of example, that you'd like to design an object to add to this scenario; specifically, a black wire-framed cube with a bright red dot centered on each of the side faces and a bright green dot in the center of the top and bottom faces right in front of windshield of the plane. This topic will walk you through the process of creating this cube, step-by-step.

In the topic Using BGL to Create Objects, Stand-Alone Code vs. BGL Files, a couple of ways to use BGL code are discussed. To briefly recap, you can place inline BGL code somewhere in the program and make a call to the BGL interpreter. Alternatively, if an object is to be displayed as part of the world, you can set up a BGL file and integrate it into the database. For this example, the wire-framed cube is going to be an object in the world, sitting on the runway at Meigs field. So, a BGL file is set up to create the object.

Setting Up the BGL File

A BGL file is a file made up of binary bytes that define a header, followed by BGL opcodes that define seeds, objects, navaids and other items. The first step is deciding how you want to create the binary file. In this example, the Microsoft Macro Assembler is used to build the file. You can use any assembler that puts out the same binary file as defined by the macros dd, dw, and db—type directives used in this example file can be used instead. It's important to remember that the first byte in the final binary file on the hard disk must be the first byte of the header; any software tools that attach their own information to the binary file before the header will make the file useless as a BGL file.

Note: The BGL file listing begins in the sample header and assembly directives. The listing is continued to the end of the file, and shown sequentially, in code samples throughout this topic. This file included in this topic is an actual file that you can assemble.

Setting Up the File Header

Only objects are displayed in this database, so a simple header that includes a single pointer to object data is all that you need. The following example shows the beginnings of the BGL file, the header and assembly directives.

;Tutorial, Example Database 1
;A wire-framed cube with a point on each face at Meigs Field
includeasm.inc ;include this in all .asm files!
includedumper.inc;we're dumping data from this file
includebglmac.inc;BGL opcode macro definitions
includefs6def.inc; BGL constant definitions (such as color values)
.data
dumper_dataDUMPERDATA{the_data, the_data_size, 'test.bin'}
the_dataequ$

;DATABASE HEADER ********************************************************
dw0001;00 world set number (not saved to file list)
; 0=off 1=fs5 default world
dd0004c0000h;02 N bound Meter units
dd000400000h;06 S bound
dd0c3400000h;10 E bound 32-bit pseudo
dd0bf000000h;14 W bound
dd0;18 VOR_DATA
dw0;22 lowest vor freq (channel 0–199)
dw0;24 highest vor freq (108.00–117.95)
dd0;26 seeds level 8
dd0;30 seeds level 9
dd0;34 seeds level 10
dd0;38 seeds level 11
dd0;42 seeds level 12
dd0;46 seeds level 13
dd0;50 seeds level 14
dd0;54 seeds level 15
ddobject_data - the_data;58 OBJECT_DATA
dd0;62 LIBRARY_DATA
dd0;66 FACILITIES_DATA
dd0;70 ANCHOR POINT DATA
dd0;74 COM RADIO DATA
dd0;78 ADF DATA
dd0;82 DYNAMIC OBJECT PATHS
dd0,0;86 Library id min
dd0,0;94 Library id max
dd0;102 MISC_DATA (ground alt db)
dd0;106 TITLE AND DESCRIPTION DATA
dd0;110
dd0;114 EXCEPTION LIST PTR
dd0;118
dd0;122 (not saved to file list)
dw0;126 (not saved to file list)
;128

..... LISTING CONTINUED IN NEXT EXAMPLE IN THIS TOPIC

Header and Assembly Directives

The preceding example begins with a couple comments identifying it as the tutorial test file. Then, there are a number of included files, as follows:

Asm.inc—This file sets up assembler options (flat model, case sensitivity, and other systems-related details). The important thing to remember is that the assembler will put out a binary file as the macros, db, dw, and dd directives indicate.

Dumper.inc—This file sets up structures for the database dumper that takes this file and dumps a pure binary file, beginning at the dumper_data label that corresponds to the first byte in the header. Like Asm.inc, this is a system file that is just setting things up so the final binary will be dumped, beginning at the first byte of the header and ending at the end of the BGL data. Files such as Dumper.inc and Asm.inc are necessary for the Microsoft Assembler to assemble the data; other, similar, files might be necessary with other assemblers. These files are important because they ensure that the resulting binary file on disk begins with the first byte of header data and ends with the last byte of BGL code.

Bglmac.inc—This file contains macro definitions for most of the BGL opcodes. A SPNT (start point) opcode is defined as shown in the following example.

SPNTmacroxx,yy,zz
dw06h
dwxx
dwyy
dwzz
endm

Including Bglmac.inc establishes a macro set that effectively creates the BGL graphics language.

FS6def.inc—This file contains many equates for systems used in Flight Simulator as well as equates for standard color values, as shown in the following example.

C_BLACKEQU00000f000h

.data—This directive indicates that the database, from this point onward, will be assembled as part of the "program's" data section (code sections aren't used).

Dumper_data—This directive is used to identify the following information to the dumper:

the_data=the first byte of the header of the file

the_data_size=how many bytes are in the database

‘test.bin’=the name of the resulting file.

The Header

The header is the beginning of BGL database. The header is of the fixed form shown in the example, with the fields filled in.

World Set ID

The world set ID is set to 1 to indicate that the contents of this database is part of the Flight Simulator visual world.

Database Bounds

North, south, east and west bounds are set to let the front-end processor that scans the files know what area is covered by the database and whether or not the area covered by the database is within the visual range of the user. Because the cube is located at the end of the Meigs runway, the bounds that are set must be at least as large as the cube on the runway. The settings for Meigs runway are as follows.

Meigs runway coordinates=0046f7abh, 4650923 Meters North of the equator
0c1b17809h=272.3811 degrees East latitude

Note: North is expressed as meters north of the equator, and east is expressed as 32-bit pseudodegrees east of the prime meridian (100000000h = 360 degrees).

In the example, the bounds are “opened up wide” (the southern bound is 456kM south of the runway) just to make sure that everything is included within them. You don’t have to set the bounds right up to the edge of your design. Database access may be slightly more efficient if you do, but, there is the danger of having your database become visible as the user gets close to its edge. A couple hundred kilometers extra range is normally enough.

Data Pointers

Data pointers begin at offset 18 and go continue to offset 118. A null pointer (value=0) indicates that there is none of that specific type of data in the file. An offset other than zero is a 32-bit absolute pointer to the offset in the file where the data begins. In this example, it is computed as object_data-the_data. Remember that the_data is the zero offset of this file, so this is simply a computation that assures that this absolute file address assumes the beginning of the file is at 0. In this example, there is only object_data; all other pointers are null.

Additional Macro Definitions

Some macros used in BGL aren't defined in the Bglmac.inc file. These opcodes are usually associated with file structure, while those included in Bglmac.inc generally contain elements associated with graphics generation. The macros that aren't defined in Bglmac.inc are defined as shown in the following example.

;UNIVERSAL ENTITY OPCODES ***************************************************
EOLmacro
db0
endm

LATBAND_RELmacrolatmin,latmax,band_addr
db21
dwlatmin;;lat min (inclusive) 512M units
dwlatmax;;lat max (exclusive)
dd(offset band_addr) - (offset rel_base);;32-bit rel_base relative ptr
endm

LARGE_OBJECT_HEADERmacrolatitude,longitude,object_end
LOCALopcode
opcodedb5
ddlatitude,longitude
db100;;image power
dw(offset object_end) - (offset opcode)
endm

LISTING CONTINUED IN NEXT EXAMPLE

Object_Data Section

The actual cube design is located in the object data section of the database. First, the object_data label defines the beginning of the object data section. The header points to this label.

; OBJECT DATABASE ************************************************************
object_datalabelword
rel_base=object_data
LATBAND_REL8960,9216,OBJ_LIST_0001
EOL

OBJ_LIST_0001label word
;Test cube at Meigs
LARGE_OBJECT_HEADER0046f9e5h,0c1a09a0ah,object_end
..... LISTING CONTINUED IN NEXT EXAMPLE

Establishing Object_Data Section Base Address

Many offsets within a data area (objects, seeds, navaids) are expressed as being relative to the individual section’s base address. This section’s base address is established as follows:

rel_base = object_data

Setting Latitude Range of the Object

When the database is scanned, additional filtering is performed by examining the latitude range of the specific object. A list of LATBAND references define the range of various objects or groups of objects in the object data section. There's only one object in this example, so there is only one LATBAND_REL instruction in the list. If other objects were in close proximity, they would fall within the same latitude range and we would still only need one entry in this list. If, however, the database included another object that was at a vastly different latitude, we would add a second LATBAND_REL instruction to the list.

Notice that the latband precision is in 512-meter units. The following example shows the conversion to Meters hexadecimal.

460000h=4587520 meters=8960 512m units
480000h=4718592 meters=9216 512m units

Meigs runway, at 46f7abh, is right in the middle of this range. The LATBAND_REL command points at the list of objects in this latitude range at OBJ_LIST_0001.

Terminating the LATBAND List

An EOL (end of list) is required at the end of this list.

Creating an Object Header for this Object

In this example, the cube and its associated dots are going to be passed to the scenery system as a single object. A large_object_header is used to define this object. Arguments in the header instruction include the center point of the object (or a point close to it) and a pointer to the end of the object. Everything from the first byte that follows the header to the byte before the end of the object are included in this object, as shown in the following graphics definition.

SCALEobject_end,0,0,13768,0046f7abh,0,0c1b17809h,0,180,0
RESLIST0,8
VERTEX192,0,80
VERTEX202,0,80
VERTEX192,0,180
VERTEX202,0,180
VERTEX192,4,80
VERTEX202,4,80
VERTEX192,4,180
VERTEX202,4,180
LCOLORC_BLACK
STRRES0;cube base
CNTRES1
CNTRES3
CNTRES2
CNTRES0
STRRES4;cube top
CNTRES5
CNTRES7
CNTRES6

CNTRES4
STRRES0;cube vertical edges
CNTRES4
STRRES1
CNTRES5
STRRES3
CNTRES7
STRRES2
CNTRES6

Setting the Scale Factor and Center

The preceding example shows the definition of the black wire-framed cube. First, you need to set up a local design coordinate system using a SCALE command, as follows.

SCALEobject_end,0,0,13768,0046f7abh,0,0c1b17809h,0,180,0

In the SCALE command, the first argument is the out-of-range jump address; it points to object_end, the label at the end of the object. If the object is too far away to project, the graphics system uses this label to jump over the whole object, bypassing it.

The signal and size variables aren't used in this example and are set to zero (0, 0).

The scale factor is set to 13768. This is a 32-bit value fractional scale factor that represents 65536/13768, or 4.76 meters per unit.

The 0,0,0 center of our local coordinate system is specified as follows:

North=Z=0046f7ab.0000 h
East=X=c1b17809.0000 h
Altitude=Y=   180.  000 decimal

The 32-bit north and east coordinates are familiar as the center of the Meigs runway, expressed in meters. The 0000h values that follow them are fractional meters, used for precise positioning. The altitude is expressed in decimal in this example and is at 180 m (590.4 feet), the altitude of Meigs Field.

The local coordinate system is now defined, with an origin (0,0,0) on the ground in the center of the runway at Meigs field. Each design unit in this coordinate system is 4.76 meters in length. Now, the cube can be drawn.

Defining the Cube’s Vertices

You can draw the wire-framed cube's edges using SPNT (start point) and CPNT (continue point) commands. But, in BGL design, it's more common to set up a list of reserved points, and then connect them. A cube has three lines going to each of its corners. It's more efficient to transform these points only once, and then connect them.

The RESLIST command specifies that the reserved points begin with reserved point 0 and there will be a total of 8 reserved points. The list of vertices begins with a VERTEX command for reserved points 0 through 7, respectively.

Each VERTEX command specifies an X,Y,Z coordinate in the coordinate reference frame that was set up using the SCALE command. Looking at the Y arguments, notice that the first four vertices are on the ground and the next four are at an elevation of 4 units; the cube is 4 * 4.76 = 19 meters tall (62.5 feet).

Setting the Cube’s Color

Before drawing the lines using the STRES (start reserved point) and CNTRES (continue reserved point) commands, you must specify the color. Use the LCOLOR command to specify the color. Any lines that you draw after using this command will be drawn in the specified color until you issue another LCOLOR command. The C_BLACK argument is defined in fs6def.inc as the following value:

C_BLACKEQU00000f000h

Drawing the Cube

The cube’s base is drawn, beginning at reserved point 0, with a STRES point. Then, CNTRES commands connect reserved points 1, 3, 2 and back to 0, connecting the points with black lines. First, the base is drawn, and then the four vertical edges, as shown in the following example.

;points on cube faces
LCOLORC_BRIGHT_GREEN
PNT197,2,180
PNT197,2,80
LCOLORC_BRIGHT_RED
PNT192,2,130
PNT202,2,130
PNT197,0,130
PNT197,4,130
object_endlabelword
EOL
the_data_sizeequ$ - the_data
end

Drawing Points on Cube’s Faces

The preceding example shows the red and green points being drawn on the cube’s faces, using the LCOLOR command to set the color and the PNT command to draw the dot.

Finishing Up the Object

The last PNT instruction is the end of the object. The object_end label follows this (last) instruction. The object_end label is used by the LARGE_OBJECT_HEADER to define the end of the object and by the SCALE command as a label to bypass this object if it’s out of range. Finally, use an EOL command to specify the end of the object list for the OBJ_LIST_0001 list.

Assembling and Placing the BGL File

You can use the Microsoft Macro Assembler and the BGL file dumper to assemble, link, and write out a binary BGL file with the first byte of the header as the first byte of the file. This file is named Test.bgl and it is saved in the Scenery directory. At startup, Flight Simulator scans all .bgl files in the Scenery folder for world set and range bounds. When you start up Flight Simulator, this .bgl file will be found and the wire-framed cube will be displayed.

Viewing the Scenery

At startup, Flight Simulator creates a view looking down the runway at Meigs field, as usual. But, out in front of the plane is the wire-framed cube. The dots on the faces of the cube are very small and hard to see because they are just points, but you can make them out if you look carefully. You can judge the height of the cube by putting the plane in slew mode, rising to the top face of the cube, and noting the difference in altitude. The height of the cube seems to be approximately 63 feet, which corresponds well to the projected design size of 62.5 feet.