World
Wide Guide | Knowledge Bank
| Kukushkin's Notebook |
Design Fundamentals
In computer graphics, a primitive is a graphics element
that is used as a building block for creating images, such as a point, line,
arc, cone or sphere.
In FS5, projecting real-world coordinates of each graphics primitive onto the screen would take an immense amount of processing time. For this reason, the graphics engine of the program works in a so-called delta coordinate system instead.
Before the drawing can begin, the SDL code must define a so-called reference
point (RefPoint) using real-world coordinates (lat/lon/alt).
The graphics engine determines the relative position of the
RefPoint to the View window and establishes a (Cartesian) coordinate
system around the RefPoint. This is the delta coordinate system.
Drawing instructions themselves never use real-world coordinates, but work
in the delta coordinate system instead.
Besides its geographical location, a RefPoint also has a so-called
scale factor. This scale factor determines the length of the unit
for the delta coordinate system, in meters. With very few exceptions, delta
coordinates are specified as 16-bit signed integer numbers. This limits their
range to between -32,767 and 32,767, and also prohibits fractional values.
Some scenery compilers allow entering fractional parts for delta coordinates
or even calculate them automatically from real-world coordinates. However,
it must be clearly understood that fractional parts of delta coordinates
can never make it into the BGL file, because its format has no place for
them. Thus, the precision of coordinates in the BGL file is limited by the
scale factor of the RefPoint.
This does not mean the less the scale factor the better, because the visibility
range of a RefPoint decreases with decreasing scale factor.
More on this can be found in How to stay within
limits.
There are two families of drawing instructions. Some instructions require
points defined using Points()/VecPoints() instructions [or in
FSASM, DefPoints/DefVecPoints], while a few others allow specifying
coordinates directly. Most polygon drawing instructions require defining
points.
Some primitives are drawn using multiple instructions. For example, a line
segment is drawn by first setting its beginning using MoveTo[Pt]()
and then setting its end using DrawTo[Pt]() [FSASM:
LineTo/DrawToPt]. In such cases, it is important not to mix
instructions that use pre-defined points and directly specified coordinates.
For instance, the sequence
MoveToPt( 0 ) DrawTo( 1000 0 1000 )
would draw the line incorrectly. The line could be drawn correctly either
by using MoveTo() instead of MoveToPt() or by using
DrawToPt() instead of DrawTo().
The choice between using points and explicit coordinates should be made in
order to reduce the resulting code size. Also, explicit coordinates should
not be used in ShadowCalled objects.
When FS5 draws a polygon, it projects coordinates of its vertices onto the screen and then instructs the graphics driver to draw a 2-D polygon. FS5 does not check whether all vertices are located in one plane. This must be ensured by the scenery designer.
Instructions that are expected to draw concave polygons should be prefixed
by the ConcavePoly() instruction. 'Concave' here means that
at least one inner angle of the polygon exceeds 180 degrees. The surface
of the polygon is flat and never concave!
Vectors in FS5 are used for defining directions and imaginary planes. Even in polygon drawing instructions, where it would theoretically be possible to derive the plane equation from polygon vertices, FS5 requires defining the polygon plane using a vector and uses this plane for its visibility tests and shading.
Directions are defined simply by specifying 3 components of a vector. A plane is defined by specifying the coefficients of its equation: ax+by+cz+d=0. a,b,c are also components of a vector orthogonal to this plane. In some polygon drawing instructions, the coordinates of some point on the plane are specified instead of the 'd' parameter.
Visibility tests done by VectorJump() and many polygon drawing
instructions check if the viewpoint is "above" the plane of the polygon.
This is done by calculating ax+by+cz+d, where x,y,z are delta coordinates
of the viewpoint. If the result is a positive number, the viewpoint is "above"
the plane.
Most scenery compilers have an 'automatic' vector mode. In this mode, they calculate plane equations and the like from coordinates of points specified for a polygon, instead of forcing the user to do such calculations. Because such calculations are done at compile time, they are only affected by the order of instructions in the source file. They are NOT affected by the actual execution order:
If...( :Shape2_points ... ) ; Choose between two shapes for the
polygon
:Shape1_points
Points( ... ) ; Points for shape 1 Jump( :Draw_it )
:Shape2_points
Points( ... ) ; Points for shape 2
:Draw_it ; Use a single Poly() instructions for
both shapes
Poly( a ... ) ; The auto-vector is always calculated for shape 2
Because the assembler processes Points() for shape 2 after
Points() for shape 1, the vector for Poly() [FSASM:
FlatPoly] is always calculated in the assumption that the polygon
is drawn using shape 2 points. This can lead to problems with shape 1 when
the two shapes lie in different planes.
Similarly, if a subroutine is used to define points, the assembler does not
know about them when it processes the polygon drawing instruction. Instead,
point coordinates specified in the last Points() instruction
PROCESSED BY THE ASSEMBLER would be used. In most cases, this would cause
the assembler to insert a wrong vector into the output file:
Call( :Define_points ) ; Define points
Poly( a ... ) ; Draw a polygon using
these points... or not?
...
:Define_points
Points( ... )
Return
As it translates the Poly() instruction, the assembler
does not yet know about points defined in the subroutine. This would either
produce an error or result in the visibility vector calculated for wrong
points.
A more detailed description of vectors can be found in FS5STRUC.TXT by Maurizio Gavioli.