Graphics

The RFO-BASIC! graphics interface lets you combine text, shapes, and images on the graphics screen. This screen occupies the entire display of the Android device. Display of the graphics screen prevents the display of the text console, which is the simpler method of interaction between user and program, but does not destroy it. Pressing the BACK key recalls the text console. In addition, a GR.FRONT statement lets the program switch between the graphics screen and the text console. Statements that raise a pop-up window for user input (such as INPUT and SELECT) work normally even when the graphics screen is displayed.

Unlike the text console, the graphics screen gives the program precise control over size, position, color, and transparency.

The GR.OPEN statement initializes the graphics interface and puts the graphics screen on display. The GR.CLOSE statement ends graphics operations. Graphics operations also end when the program ends, such as after the user presses the MENU key. To keep the graphics screen on display after the program has completed its computing, use a long PAUSE statement or an infinite loop with a method, such as an interrupt routine, to let the user force the program to terminate.

The GR.CLS statement clears the graphics screen and destroys all graphic elements. The GR.RENDER statement renders graphic elements onto the graphics screen. Nothing appears on the graphics screen until the program executes GR.RENDER. GR.RENDER achieves a flicker-free transition from what was displayed on the graphics screen, to elements the program specified more recently.

A typical use of graphics is to put elements on the graphics screen, and to update them based on real-world events such as received messages. There are two ways to achieve this:
 * 1) Code a main loop that begins with GR.CLS, uses graphics statements to place the desired graphic elements on the screen, and finally executes GR.RENDER.
 * 2) Do the above only once to specify the graphics screen's initial appearance. Then code a main loop in which the program may use GR.MODIFY to change the attributes of certain elements, or GR.HIDE and GR.SHOW to select which elements are displayed, and finally executes GR.RENDER.

Graphics operations work in Portrait Mode and Landscape Mode. The GR.OPEN command can state that the program operates in one specific orientation, or can specify that the orientation will change as the user rotates the Android device.
 * Geometry

When drawing an object onto the graphics screen, the location (typically of the object's upper-left corner) and the size of the object are stated as a number of pixels. The upper-left corner of the graphics screen is identified with horizontal location x=0 and vertical location y=0. Pixels to the right and below this corner are identified with increasing positive pixel addresses (as in Quadrant IV of a Cartesian coordinate system, but with positive y).

Coordinates are measured with respect to the physical screen, not to anything on it. (If you choose to show the Android Status Bar, anything you draw at the top of the screen is covered by the Status Bar. See GR.STATUSBAR.)

A program can use the GR.SCREEN statement to query the size of the graphics screen. If the program has allowed the orientation to shift, the size of the graphics screen may change if the user rotates the Android device during the program's execution. RFO-BASIC! attempts to reconstruct the graphics objects in the new orientation, but the program may elect to re-draw the entire screen (especially if the program prefers different uses or layouts based on the orientation). GR.SCREEN indicates that the device is in Portrait Mode if y > x.

Single-byte integers, such as those used as parameters of GR.COLOR, affect objects drawn subsequently by specifying: Color, transparency, and style are often stored together in a data structure called a paint.
 * Transparency, color, and style
 * Whether they are opaque or transparent
 * Their color, in red/green/blue values
 * Whether their edges are stroked, the element is filled in, or both.


 * General rules

Even if the program does not save an element's number to refer to it later, the program has still created a small data structure. A program that runs continuously for hours and creates new graphic elements rather than modify existing ones, and does not call GR.CLS periodically, can run out of memory. See also the sidebar at the start of the section on Paints.  The BASIC program can draw elements onto the graphics screen, such as lines, circles, text, and images. Whenever it does so:
 * 1) The element's color, transparency, and style is dictated by the current paint.
 * 2) The element receives a number, which the program must use if it refers to the element later, such as in a GR.MODIFY statement.
 * 3) The element's number is added to a display list. Elements have no "z address," but the GR.RENDER statement draws elements in the order in which they appear in the Display List.  Elements drawn later appear "on top of" those drawn earlier.  Programs can create custom display lists and thereby change the order in which elements are drawn.

An exception to this scheme is while BASIC is placed into Draw-Into Mode. In this case, BASIC draws every specified element into a specified bitmap, in the sequence in which the drawing statements are executed.

GR.OPEN
Begin graphics operations

GR.OPEN { {}{, }{, }{, }{, }{, }}
 * Synopsis

The GR.OPEN statement opens the graphics screen and prepares BASIC to paint graphic elements into it. It is a run-time error to execute any other graphics statement without first executing GR.OPEN.
 * Description

The alpha, red, green, and blue expressions become the graphics screen's background color. The alpha parameter does not achieve transparency, as there is nothing beneath the background that might show through; but it is an alternative way to dim the color selected for the background. If any transparency or color parameter is omitted, GR.OPEN uses 255. (If all are omitted,  is used, specifying bright white.)

If  has a value other than 0, the graphics screen incorporates the Android Status Bar. If it is 0 or omitted, the Android Status Bar is not present. If the Android Status Bar is displayed, screen geometry continues to be based on the total size of the Android display; it does not reflect a "client screen" remaining after the Status Bar. This means the program could draw elements that conflict with the Status Bar. (See GR.STATUSBAR.)

The  parameter specifies the initial orientation. Valid values are the same as for the GR.ORIENTATION statement. Notably, a value of -1 means that the orientation of the graphics screen depends on how the user holds the Android device and can change at any time while the program is running. If the expression is omitted, the graphics screen begins in Landscape Mode.

GR.OPEN ,,,,,-1 This statement defaults to a bright white screen without the Android Status Bar. The -1 means that the orientation at any moment will depend on how the user holds the device.
 * Example

GR.CLOSE
End graphics operations

GR.CLOSE
 * Synopsis

The GR.CLOSE statement ends graphics operations, causes the graphics screen to no longer be displayed, and raises the text console in its place. It does not end the BASIC program. However, if the program ends for some other reason, graphics shuts down as with the GR.CLOSE statement.
 * Description

GR.CLS
Clear the graphics screen

GR.CLS
 * Synopsis

The GR.CLS statement deletes all the data structures of the graphics subsystem, including:
 * Description
 * All elements that have been drawn on the graphics screen (making their numbers invalid for future use)
 * All paints
 * All settings of GR.COLOR and GR.TEXT
 * The current display list

GR.CLS does not affect what is shown on the Android display. To display an empty graphics screen in the chosen background color, the program would have to execute GR.RENDER. However, typically, the program first draws a new set of elements that is to be displayed next.

GR.CLS does not delete bitmaps that have been loaded. They are not set to appear on the graphics screen, because the data structures that would achieve this have been deleted, but their bitmap numbers remain valid, and a program could re-draw them (without having to reload them) before executing GR.RENDER.

GR.RENDER
Render the graphics screen

GR.RENDER
 * Synopsis


 * Description

GR.RENDER works by marking the graphics screen "invalidated." This may also happen independently, under certain conditions and Android versions, and whether or not you selected "Graphic Acceleration" in Preferences. Be sure to code GR.RENDER statements wherever the screen needs to be updated, even if some objects are displayed without them.  The GR.RENDER statement displays all the objects in the current working display list. That is, it causes every element that the program has drawn to physically appear on the graphics screen. An exception is objects in the display list that are inhibited from display using GR.HIDE.

GR.RENDER does not return to the caller until: This means that two consecutive GR.RENDER statements delay the BASIC program about 16.7 msec. There is no benefit to trying to render the screen faster than this.
 * All the items in the working display list have been re-rendered, and
 * The screen has been refreshed (which typically happens 60 times per second).

A program designed to display smooth animation should not perform computations that take more than 16.7 msec between GR.RENDER commands; otherwise, some renderings may skip an Android screen refresh and the animation can become jerky. A program can use the CLOCK or TIME functions to measure the amount of time its computations are taking.

If RFO-BASIC! is running in the background (see the BACKGROUND function and the HOME key), GR.RENDER suspends the program's execution until the user returns BASIC to the foreground.

The figures of 60 refreshes per second and 16.7 msec between refreshes may be different on some Android devices.

Here is a working program that combines the GR.OPEN and GR.RENDER statements with others discussed later: GR.OPEN                   % Start graphics; background assumed to be bright white, screen is cleared GR.COLOR 255,0,0,0        % Specify opaque black drawing (bright white is the default paint color too) GR.TEXT.SIZE 80           % Text lines are 80 pixels high GR.TEXT.DRAW textline1, 0,100, "Hello, world!" GR.RENDER                 % Make the text appear PAUSE 2000                % Stay on the graphics screen for 2 seconds before the program ends
 * Example

The GR.TEXT.DRAW statement draws starting at (0,100), 100 pixels below the top of the screen. This is the baseline of the specified text. Drawing at (0,0) would position most of the text off the top of the screen.

GR.FRONT
Select between the graphics screen and the text console

GR.FRONT 
 * Synopsis

An RFO-BASIC! program can maintain both the graphics screen and the text console, but only one is visible at any time. The GR.FRONT statement makes this selection.
 * Description
 * If  is true (nonzero), then the graphics screen is the one the user sees. The BASIC program can still operate on the text console, such as by executing PRINT statements.
 * If  is false (0), then the text console is the one the user sees. The BASIC program can still draw to the graphics screen, but GR.RENDER fails unless the program puts the graphics screen on display.

GR.SAVE
Save the graphics screen to a file

GR.SAVE {, }
 * Synopsis

The GR.SAVE statement saves the graphics screen to a file. The  parameter specifies the name of the file, which is assumed to be in the  directory. Usually, the file is saved as a PNG file. If <filename_sexp> does not specify an extension,  is appended to it. The <quality_nexp> parameter is ignored.
 * Description

If <filename_sexp> ends with, then GR.SAVE writes a JPEG file. This is a "lossy" file format, more suitable for photographs of faces than to capture sharp edges and line-drawings. It does not save the exact image. The <quality_nexp> parameter, if present, must be a value from 0 through 100 and specifies the desired quality:
 * A value of 0 creates a small JPEG file with low resolution.
 * A value of 100 creates a larger JPEG file with the highest resolution the format can achieve.
 * If the parameter is omitted, the quality level is 50.

Another way to create files is to use GR.BITMAP.SAVE. If the RFO-BASIC! program has used Draw-Into Mode to draw graphic elements into a bitmap that can then be drawn on the graphics screen, then GR.BITMAP.SAVE stores the bitmap in a  file for later use by an RFO-BASIC! or other program. These files accurately represent every pixel of the screen.

The GR.SAVE statement operates only on the graphics screen. It cannot save browser output created by the HTML statements, nor text output created by the PRINT statement.

Interacting with Android
Given that Android devices range from a flip-phone with a tiny screen to a Chromebook with a keyboard, one of the first steps of a BASIC program that uses the graphics screen is to discover the attributes and set the operating mode.

GR.ORIENTATION
Specify the screen orientation

GR.ORIENTATION <orientation_nexp>
 * Synopsis


 * Description

A change to the orientation takes time (typically 800 msec) and features on-screen animation, during which GR.RENDER might not take effect. </DIV> An Android device can be operated in one of two Modes:
 * Portrait Mode, in which the long dimension of the display is vertical
 * Landscape Mode, in which the long dimension of the display is horizontal.

The GR.ORIENTATION statement specifies which Mode the program will use. The <orientation_nexp> parameter can have one of the following values:

RFO-BASIC!'s initial mode is Portrait Mode. Using GR.ORIENTATION to specify a different mode results in a time-consuming operation. (See the blue sidebar above.) It is preferable to specify the desired orientation when opening the graphics screen with GR.OPEN. After the program changes the orientation, it may improve results to execute: PAUSE 800
 * Warning on unnecessary rotations


 * Warning on computing during a rotation

If running under the OLI-BASIC private version, the program can use the OnGrScreen interrupt to detect that the user has changed the device's orientation. </DIV>

GR.RENDER executed during the time-consuming animation does not render. If the orientation is -1 and the user rotates the Android device, this interval could occur at any time. The information GR.SCREEN returns is only updated at the end of this interval. The information SCREEN.ROTATION and SCREEN.SIZE return is revised at the start of this interval. Therefore, the program should sense the screen orientation with SCREEN.ROTATION and dimensions with SCREEN.SIZE before using the GR. statements to build the display list for that orientation. The program may check the orientation again after it has built the display list to ensure the user did not rotate the device in the meantime. Even so, this is a race condition and it is possible the RFO-BASIC! program will render the graphics screen once in the old orientation.

SCREEN.ROTATION
Obtain the screen orientation

A SCREEN statement described in the RFO-BASIC manual, which combines the effects of SCREEN.ROTATION and SCREEN.SIZE, was never implemented. </DIV> SCREEN.ROTATION <rotation_nvar>
 * Synopsis

The SCREEN.ROTATION statement obtains the orientation of the Android device.
 * Description
 * If the RFO-BASIC! program specified an orientation (0 through 3) in the GR.OPEN or GR.ORIENTATION statements, then this statement returns that value (as set most recently).
 * If the program specified -1, so that the orientation changes as the user rotates the device (-1), then SCREEN.ROTATION returns the current orientation, 0 through 3, as defined for GR.ORIENTATION. The value that SCREEN.ROTATION returns could change at any moment based on the user's handling of the device.  SCREEN.ROTATION does not return -1.

SCREEN.SIZE
Obtain the screen dimensions

SCREEN.SIZE <size_narr>, <realsize_narr>, <density_nvar>
 * Synopsis

The SCREEN.SIZE statement obtains information about the size in pixels of the screen. All parameters are optional.
 * Description
 * The <size_narr> parameter returns a two-element array with the number of pixels available to the RFO-BASIC! program. The width (x dimension) is in   and the height (y dimension) is in.

On devices prior to Android version 4.2, realsize returns the same information as size. </DIV>
 * The <realsize_narr> parameter returns a two-element array with the screen dimensions. Unlike <size_narr>, this includes areas of the screen with system decorations that might not be available to the RFO-BASIC! program.
 * The <density_nvar> parameter is set to one of the standard Android pixel density values in dots per inch, such as 120, 160, or 240 dpi. This might differ from the exact pixel density.

If the GR.OPEN or GR.ORIENTATION statement has permitted the mode to change depending on the manner in which the user holds the device, then the results that SCREEN.SIZE returns can change at any moment.

GR.SCREEN
Obtain the screen dimensions

GR.SCREEN <width_nvar>, <height_nvar>{, <density_nvar> }
 * Synopsis

The GR.SCREEN statement obtains the dimensions of the Android display. These include:
 * Description
 * The screen width, in pixels
 * The screen height, in pixels
 * Optionally, the pixel density, in dots per inch (dpi).

An RFO-BASIC! program could determine whether the device is in Portrait Mode or Landscape Mode with the following code (but see the warning at GR_ORIENTATION): GR.SCREEN w, h IsPortrait = (w < h)

If the GR.OPEN or GR.ORIENTATION statement has permitted the mode to change depending on the manner in which the user holds the device, then the results that GR.SCREEN returns can change at any moment.

The <density_nvar> parameter, if present, is set to one of the standard Android pixel density values, such as 120, 160, or 240 dpi. This might differ from the exact pixel density.

The SCREEN.ROTATION and SCREEN.SIZE statements return this and additional information.
 * See also

GR.STATUSBAR
Obtain information about the Android Status Bar

GR.STATUSBAR <height_nvar>, <showing_lvar>
 * Synopsis

The Android Status Bar appears at the top of the screen and may show information such as the strength of the cellular and WiFi signals, whether there are notifications, and the time of day. An RFO-BASIC! program dictates whether the Status Bar is displayed by means of a parameter of GR.OPEN. If the program has selected display of the Status Bar, it does not change the screen geometry and the program must coexist with the Status Bar.
 * Description

Most Android Devices implement the Status Bar by drawing text and symbols, in white, on top of any existing background, essentially adding drawing commands, for the information described above, to the end of the current Drawing List. Since the Status Bar is rendered last, you cannot inhibit it if you opted to have it. On older devices, you can draw a background of any desired color, including a white background that renders the Status Bar invisible. However, some Android Devices draw a black bar, then white text, to ensure that the text is readable. As of Android 8 (Oreo), user programs are not allowed to overwrite the Status Bar.

The GR.STATUSBAR statement obtains information on the Status Bar.


 * The logical variable <showing_lvar> is 1 (TRUE) if the Android Status Bar is showing; otherwise, it is 0. This depends solely on whether the program enabled it in the call to GR.OPEN.
 * The numeric variable <height_nvar> is set to the height of the Android Status Bar in pixels. The height and physical appearance of the Status Bar depends on the device, the revision, and the text size the user specified in Settings.

To work with all versions of Android, if an RFO-BASIC! program enables the Android Status Bar in the call to GR.OPEN, it should limit its graphics to y coordinates from the bottom of the Status Bar (<height_nvar>) to the bottom of the physical screen (the <height_nvar> parameter returned by GR.SCREEN, which may change from time to time if the user turns the device sideways).

GR.SCALE
Transform all rendered elements to specified dimensions

GR.SCALE <x_nexp>, <y_nexp>
 * Synopsis


 * Description

Scaling with GR.SCALE does not affect the geometry of touch sensing. If the program uses the GR.TOUCH statements to sense finger touches and if it uses scaling to adapt to having been written for a device with a different screen, the origin and size parameters of the GR.TOUCH statements must be adjusted too. </DIV> The GR.SCALE statement transforms all rendered elements by a factor of <x_nexp> horizontally, and by a factor of <y_nexp> vertically. This includes distorting text (condensing or expanding it). GR.SCALE applies to the entire screen, including elements specified before and after the GR.SCALE statement is executed.

For example, GR.SCALE 1,1 has no effect except to cancel any other scaling that might have been specified. GR.SCALE 2,1 stretches all elements to double width. Drawing a 20✕20 square at origin (30,50) achieves a 40✕20 rectangle with origin at (60,50).

Negative values of <x_nexp> and <y_nexp> are not valid. To create mirrored graphics and text, use Draw-Into Mode. Then use GR.BITMAP.SCALE to copy the bitmap into another bitmap, using negative scale factors, and draw this bitmap onto the graphics screen.

GR.SCALE lets a BASIC program be written, assuming some screen size, and then transformed at the time it is run to fit the screen of the Android device on which the program is running. A program written to run on an 800✕480 screen will run on any Android device if it includes code such as the following:
 * Example

!Specify the dimensions of the screen for which this program is designed di_width = 800 di_height = 480 !Get the dimensions of the screen on which the program is running GR.OPEN GR.SCREEN actual_w, actual_h !Make this program's graphics work on the actual screen GR.SCALE actual_w/di_width, actual_h/di_height

The 800✕480 screen dimensions means the program is assuming the screen is in Landscape Mode. To work correctly when the device is in, or switches to, Portrait Mode, more complex code is needed.

GR.BRIGHTNESS
Select the light level of the display

GR.BRIGHTNESS <br_nexp>
 * Synopsis

The GR.BRIGHTNESS statement sets the brightness of the Android display. A value of 0.01 is the darkest level and 1.00 is the brightest.
 * Description

RFO-BASIC! provides no way to obtain the brightness the user selected via Android (such as using Settings / Display or the pull-down control). However, when the BASIC program ends, the screen illumination returns to that level.

Paints
A paint is an RFO-BASIC! data structure that holds all the implicit settings needed to render a graphic element. These include:
 * Transparency, color, and drawing style, which are specified by GR.COLOR.
 * The anti-alias setting, which is specified by GR.SET.ANTIALIAS.
 * The line stroke width, which is specified by GR.SET.STROKE.

It also holds the following settings needed to render text characters on the graphics screen. These include:
 * The font, which is specified by GR.TEXT.SETFONT.
 * Text size, which is specified by GR.TEXT.SIZE.
 * The alignment of text, relative to the specified point on the graphics screen. Alignment is specified by GR.TEXT.ALIGN.
 * Bloating of text, which is specified by GR.TEXT.BOLD. This effect is comparable to boldfacing, but specifying a boldfaced typeface is preferable.
 * Skewing of text, which is specified by GR.TEXT.SKEW. This effect is comparable to italics, but specifying an italic typeface is preferable.
 * Whether the text is underlined, which is specified by GR.TEXT.UNDERLINE.
 * Whether the text is struck through, which is specified by GR.TEXT.STRIKE.

The BASIC statements in this section take an optional parameter denoted as <paint_nexp>. This is typically the number of a paint.
 * General syntax
 * If you omit <paint_nexp>, or specify a value of -1, the statement affects the current paint. This is the paint that affects the drawing of all elements until the program makes another change to one or more of the settings.
 * If you specify 0, such as providing a variable that has not been used before, then the statement creates a working paint and sets the variable to its number.
 * If you specify some other number that is the number of an existing paint:
 * The statement modifies the setting of the specified paint. Any element drawn using that paint will adopt the modification, and will typically be drawn differently the next time the program executes GR.RENDER.
 * The statement does not affect the current paint, and does not influence the drawing of new elements.
 * If you specify some other number that is not the number of an existing paint, it is a run-time error.

Statements that merely affect the current paint still create and register a paint. This is a small data structure that requires memory. Unless the program periodically calls GR.CLS and rebuilds the graphics screen, a program that runs for a long time will eventually run out of memory. </DIV> You can use GR.COLOR and other statements without specifying a paint number, to affect the drawing of upcoming elements. Each setting remains in effect unless the program should change it again. Since the statement does not provide <paint_nvar>, it has no way to capture the number of this paint in order to specify it by number.
 * Basic usage

A program can capture all the settings in a paint. For example: GR.COLOR 128,255,0,0,1,NewPaint  % Semi-transparent red, fill but don't draw the outline GR.TEXT.ALIGN 2,NewPaint         % Text is drawn centered on the specified point GR.TEXT.SKEW -0.25,NewPaint      % Text is skewed to create an italic effect GR.PAINT.GET NewPaint            % All of the above become the current paint
 * Advanced usage

Assuming NewPaint is an unused variable, the GR.COLOR statement assigns it to the number of a newly created paint, and the next two statements make further modifications to its contents. The GR.PAINT.GET statement fetches this paint so that it affects elements drawn thereafter.

GR.COLOR
Specify transparency, color, and drawing style

GR.COLOR { {<alpha_nexp>}{, <red_nexp>}{, <green_nexp>}{, <blue_nexp>}{, <style_nexp>}{, <paint_nvar>}}
 * Synopsis

The GR.COLOR statement specifies transparency, color, and drawing style for subsequent drawing statements.
 * Description

Only the low-order byte of transparency and color is relevant. If you should specify a value of 256, it wraps around and the effect is the same as specifying 0. </DIV>
 * The <alpha_nexp> parameter specifies transparency. A value of 0 means the element is completely invisible, yielding to material previously drawn on the graphics screen at its location.  255 means the element is opaque; it is visible, hiding anything previously drawn at its location.  Values in between produce a mix of the new element and the background elements at the same location.
 * The <red_nexp>, <green_nexp>, and <blue_nexp> parameters specify the color in which to draw. A value of 0 means that color component is dark.  A value of 255 specifies full brightness.  So   signifies black,   signifies bright red, and   signifies white.
 * The <style_nexp> parameter has one of three values:
 * If drawing a circle, this is the difference between a filled-in circle and simply drawing the circumference. However, style also applies when drawing text.  Selecting a style of 0 does not draw the text but only the outlines of each character.  This is an interesting alternative to "graying out" text that is not relevant at the moment.  A style of 2 is most common when drawing text.


 * The <paint_nvar> parameter specifies the number of a paint. The specified changes affect that paint.  If <paint_nvar> is omitted, the specified changes affect the current paint.

Omitting any parameter for transparency, color, and style means to make no change to that aspect of the paint.

GR.COLOR 255,0,0,0,2 This specifies opaque black and stroke-and-fill style. It applies to subsequent drawing statements that do not specify a paint by number. This example does not save the number of the newly created paint in a variable.
 * Examples

GR.COLOR 100 It is especially useful to omit parameters of GR.COLOR in order to change only certain settings. The above example changes only the transparency (to 100/255), leaving the color and drawing style unchanged. It draws subsequent elements in a dimmer intensity of the color already selected. For text, this is a way to "gray out" options that are not available to the user.

Here is a complete RFO-BASIC! program that shows the effects of stroke versus fill: GR.OPEN 255,0,0,0,,1 PAUSE 800         % Wait for any orientation change GR.TEXT.SIZE 120  % Specify size of characters in pixels GR.SET.STROKE 5   % Pick an exaggerated stroke width GR.COLOR 255,255,255,255,0 % Fully opaque, white, STROKE GR.TEXT.DRAW obj0,50,100, "#0" GR.CIRCLE obj0c,100,200,50 GR.COLOR ,,,,1    % Change to FILL GR.TEXT.DRAW obj1,300,100, "#1" GR.CIRCLE obj1c,350,200,50 GR.COLOR ,,,,2    % Change to STROKE_AND_FILL GR.TEXT.DRAW obj2,550,100, "#2" GR.CIRCLE obj2c,600,200,50 GR.RENDER         % Render all graphics PAUSE 4000        % Admire it for 4 seconds

It can be useful to draw the same element twice with different paint settings. You could fill a circle in a dim color and then stroke its outline in full intensity: GR.COLOR 51,255,0,0,1    % Fill, red, 20% opaque GR.CIRCLE obj3,600,200,50 GR.COLOR 255,, , ,0     % Change to fully opaque and to stroke GR.CIRCLE obj4,600,200,50

GR.SET.ANTIALIAS
Control the Android anti-alias mode

Anti-aliasing is an Android feature that blurs adjacent pixels to create smoother curves. For example, with anti-aliasing enabled, when drawing a black circle on a white background, pixels on the edge of a circle are drawn in gray to avoid jaggedness (aliases) where the edge jumps from one tier of pixels to the next.
 * Overview

Anti-aliasing is enabled by default. It almost always produces a more attractive effect. When drawing polygons, anti-aliasing makes the corners appear to be slightly rounded.

When drawing single pixels that need to appear clearly, anti-aliasing should be disabled; otherwise, the pixel will be diffused among neighboring pixels. Anti-aliasing will also produce a less satisfactory result when drawing horizontal or vertical lines whose width is 1 pixel.

GR.SET.ANTIALIAS
 * Synopsis

The GR.SET.ANTIALIAS statement affects the anti-aliasing setting:
 * Description
 * If <enable_lexp> is false (0), then anti-aliasing is disabled.
 * If <enable_lexp> is true (1), then anti-aliasing is enabled.
 * If <enable_lexp> is omitted, then the state of anti-aliasing is reversed.

If <paint_nexp> is omitted, then the change modifies the current paint, and affects subsequent drawing commands. If <paint_nexp> is specified, then the change affects the paint by that number, and does not modify the current paint.

GR.SET.STROKE
Set the stroke width

Most statements that draw an object rely on the stroke width. For example, to draw a text character, GR.TEXT.DRAW may draw the character's outline in the specified stroke width and may fill the interior of the character. If the stroke width is 0 or 1, any lines drawn are a single pixel wide. If the value is greater, the line width is the specified number of pixels.
 * Overview

Stroke width is closely related to the anti-aliasing setting specified with GR.SET.ANTIALIAS To draw a sharp single-pixel line, the stroke width must be 0 or 1, and anti-aliasing must be off. If anti-aliasing is on, the line will be blurred: It will lack full opacity and will be two pixels wide. In more detail:
 * With anti-aliasing, the Android device paints with varying opacity to draw a blurred line that is, on average, the number of pixels specified by the stroke width. This is the case even if the stroke width is not a counting number.
 * Without anti-aliasing, the Android device paints with the exact opacity of the paint to draw a line using the exact number of pixels specified by the stroke width. It is meaningless for the stroke width to not be a counting number, except when drawing diagonals.

GR.SET.STROKE
 * Synopsis

The GR.SET.STROKE statement sets the stroke width to <stroke_nexp>.
 * Description

If <paint_nexp> is omitted, then the change modifies the current paint, and affects subsequent drawing commands. If <paint_nexp> is specified, then the change affects the paint by that number, and does not modify the current paint.

This example draws white characters with a stroke width of 4, then draws them again in black without stroking the outline at all. This creates a white shadow that makes the black text visible even on a background such as a photograph. GR.COLOR 255, 255,255,255, 0 % Specify opaque white and STROKE only GR.SET.STROKE 4 GR.TEXT.DRAW p, xpos, ypos, DesiredText$ GR.COLOR 255, 0,0,0,      1  % Specify opaque black and FILL only GR.TEXT.DRAW p, xpos, ypos, DesiredText$ GR.SET.STROKE 0              % Return stroke width to the default value
 * Example

GR.PAINT.RESET
Reset the current paint to the default settings

GR.PAINT.RESET {<paint_nexp>}
 * Synopsis

The GR.PAINT.RESET statement works exactly like a GR.COLOR statement that specifies:
 * Description
 * Total opaqueness (255)
 * The color black (0,0,0)
 * Filling of shapes (0)

GR.PAINT.RESET also specifies the minimum stroke width (0.0). If the statement includes <paint_nexp>, then these default settings are assigned to an existing paint or a paint is created with the default settings.

GR.PAINT.COPY
Copy one paint to another

GR.PAINT.COPY { {<src_nexp>}{, <dst_nexp>}}
 * Synopsis

Given two paint numbers, the GR.PAINT.COPY statement copies all the settings from the source paint to the destination paint. If either parameter is omitted, GR.PAINT.COPY uses the current paint.
 * Description

GR.PAINT.COPY s As <dst_nexp> is omitted, this statement uses the settings of paint number s as the current paint.
 * Examples

GR.PAINT.COPY ,d As <src_nexp> is omitted, this statement stores the settings of the current paint as paint number d.

GR.PAINT.COPY s,d This statement modifies paint number d to have the same settings as paint number s.

Graphic objects
Creating a graphic object adds an element to the Display List. Each RFO-BASIC! statement has parameters that describe what to draw and where. Three other BASIC statements that create graphic objects are GR.TEXT.DRAW, GR.BITMAP.DRAW, and GR.CLIP.

Apart from points, lines, and arcs under certain settings, drawing an element may mean:
 * 1) Tracing it, according to the color and fill style, stroke width, and anti-aliasing setting specified by the current paint, then
 * 2) Filling it in, according to the color.

If the style specified by GR.COLOR is 0, BASIC traces the outline of the element. A value of 1 means to fill it in, and 2 means to do both.

GR.POINT
Draw a single pixel

GR.POINT <obj_nvar>, <x_nexp>, <y_nexp>
 * Synopsis

The GR.POINT statement draws a point at the location (x, y) specified by <x_nexp> and <y_nexp>, and returns its object number in <obj_nvar>.
 * Description

By default, the point is a single pixel. If the stroke width is greater than 1, GR.POINT draws a square centered at (x, y). The point's appearance is also affected by the anti-aliasing setting. Unless anti-aliasing is disabled, a single pixel will be blurred with adjacent pixels and may be hard to see.

x, y
 * Modifiable attributes

The GR.SET.PIXELS statement, below, lets a BASIC program draw many pixels in a single operation, whose coordinates are specified in an array.
 * See also

GR.LINE
Draw a line

GR.LINE <obj_nvar>, <x1_nexp>, <y1_nexp>, <x2_nexp>, <y2_nexp>
 * Synopsis

The GR.LINE statement draws a line between (x1, y1) and (x2, y2), and returns its object number in <obj_nvar>.
 * Description

The line's appearance is affected by the stroke width and the anti-aliasing setting. By default, anti-aliasing and the stroke width of 1 blur each point on a horizontal or vertical line over two side-by-side pixels. To draw horizontal or vertical lines a single pixel in width, the program should disable anti-aliasing.

x1, y1, x2, y2
 * Modifiable attributes

GR.RECT
Draw a rectangle

GR.RECT <obj_nvar>, <left_nexp>, <top_nexp>, <right_nexp>, <bottom_nexp>
 * Synopsis

The GR.RECT statement draws a rectangle where one corner is at (left, top) and whose opposite corner is at (right, bottom), and returns its object number in <obj_nvar>.
 * Description

The left and right edges can be exchanged, and the top and bottom edges can be exchanged, and the specified rectangle is drawn without a run-time error. If either pair has the same value, it specifies a width or a height of 0, in which a line segment or a single point may be drawn.

bottom, left, right, top
 * Modifiable attributes

GR.OVAL
Draw an oval

GR.OVAL <obj_nvar>, <left_nexp>, <top_nexp>, <right_nexp>, <bottom_nexp>
 * Synopsis

The GR.OVAL statement draws an oval whose bounding box is a rectangle (as in GR.RECT, just above) extending from (left, top) to (right, bottom), and returns its object number in <obj_nvar>.
 * Description

If the bounding box is a rectangle, then GR.OVAL draws an oval that is tangent with each side of the bounding box at its midpoint. The oval's major axis is always horizontal or vertical, depending on which dimension of the bounding box is longer; but it can be rotated. If the bounding box is a square, then GR.OVAL draws a circle whose diameter is | left&minus;right | =
 * top&minus;bottom |.

If the bounding box is a line segment or a single point, then GR.OVAL draws the same thing as GR.RECT with the same parameters would draw.

bottom, left, right, top
 * Modifiable attributes

A circle can also be drawn by specifying its center and radius using GR.CIRCLE.
 * See also

GR.CIRCLE
Draw a circle

GR.CIRCLE <obj_nvar>, <x_nexp>, <y_nexp>, <radius_nexp>
 * Synopsis

The GR.CIRCLE statement draws a circle whose center is at (x, y) and whose radius is given in <radius_nexp>, and returns its object number in <obj_nvar>. As usual, depending on the style set by GR.COLOR, this may be a circle or a filled-in disc.
 * Description

radius, x, y
 * Modifiable attributes

A circle can also be drawn by specifying its horizontal and vertical boundaries, using GR.OVAL.
 * See also

GR.ARC
Draw an arc

GR.ARC <obj_nvar>, <left_nexp>, <top_nexp>, <right_nexp>, <bottom_nexp>, <start_angle_nexp>, <sweep_angle_nexp>, <fill_mode_nexp>
 * Synopsis

The GR.ARC statement draws an arc-shaped object based on the oval that fits entirely within the bounding box from (left, top) to (right, bottom) that GR.OVAL, would have drawn, and returns its object number in <obj_nvar>.
 * Description

The arc is the portion of the oval starting at <start_angle_nexp>, measuring clockwise from the right edge of the bounding box, and continuing clockwise through <sweep_angle_nexp>. Both numbers are expressed in degrees.

GR.ARC has four effects.
 * The <fill_mode> parameter of GR.ARC determines whether the figure is an arc (plus the associated chord, if GR.COLOR says to fill it in), or a piece of pie:
 * The fill style of the current paint (set by a parameter of GR.COLOR) determines whether RFO-BASIC! traces a figure or fills it in.

The following program produced the four illustrations shown in this section. The numbers shown in green were changed to produce the four effects: f=<SPAN STYLE="color:green">0</SPAN> % Fill mode s=<SPAN STYLE="color:green">0</SPAN> % Style GR.OPEN               % Assumes white background GR.COLOR 255,0,0,0    % Draw bounding rectangle in opaque black GR.RECT obj1, 100,100, 500,300 GR.COLOR 255,255,0,0,s % Set opaque red and desired style GR.SET.STROKE 5       % Wide red line to illustrate GR.ARC obj2, 100,100, 500,300, 30, 90, f GR.RENDER              % Start at 30 deg, continue thru 30+90 deg PAUSE 10000           % Keep it displayed for ten seconds
 * Example

bottom, fill_mode, left, right, start_angle, sweep_angle, top
 * Modifiable attributes

GR.SET.PIXELS
Draw pixels according to an array

GR.SET.PIXELS <obj_nvar>, <pixels_narray> {, <x_nexp>, <y_nexp>}
 * Synopsis


 * Description

The section on GR.POINT explains that anytime individual pixels are drawn on the screen, the effect depends on the stroke width and the anti-aliasing setting specified by the current paint. </DIV> The GR.SET.PIXELS statement draws individual pixels on the screen according to a list of x and y coordinates contained in <pixels_narray>, and returns, in <obj_nvar>, an object number in the Display List that refers to the entire set of pixels.

The array can be specified in either of the following ways:
 * Without subscripts, to denote the entire array:
 * With two numbers, denoting the starting position and number of elements:

The number of array elements must be even. In each pair of elements, the first is an x coordinate and the second is a y coordinate, and GR.SET.PIXELS draws a point at the(x, y) coordinate specified by the pair.

If the parameters <x_nexp> and <y_nexp> are present, they are a relocation to be added to each location in the array to determine where the corresponding point is drawn. This means that the array can describe a figure, relative to itself, and rely on <x_nexp> and <y_nexp> to specify where to put it on the screen. In addition, by using GR.MODIFY on these attributes, the program can easily move the figure around on the screen. Negative <x_nexp> and <y_nexp> values are valid and result in relocation to the left and upward, respectively. If <x_nexp> and <y_nexp> are omitted, no relocation occurs and the (x, y) pairs in the array are absolute screen positions.

Not only can the program use GR.MODIFY to change the relocation distances, it can assign new values to relevant elements in the array to change the figure that BASIC draws, the next time GR.RENDER occurs.

x, y
 * Modifiable attributes

GR.POLY
Draw a polygon from a BASIC list

GR.POLY <obj_nvar>, <list_nexp> {, <x_nexp>, <y_nexp>}
 * Synopsis

The GR.POLY statement draws a closed polygon, and returns its object number in <obj_nvar>. The <list_nexp> is the number of a numeric List (see Data structures). Starting with list element 1, GR.POLY reads pairs of numbers from the list and interprets them as (x, y) coordinates of a point on the graphics screen. If there is only one pair of numbers, GR.POLY has no effect. Otherwise, GR.POLY draws lines from point to point, until reaching the end of the list, then draws a line back to the first point specified in the list. The process of drawing a line is as specified for the GR.LINE statement. It uses the settings in the current paint, which means that it may fill in the polygon if the fill style of GR.COLOR says to do so.
 * Description

If the parameters <x_nexp> and <y_nexp> are present, they are a relocation to be added to each location in the list to determine where the corresponding point is drawn. As with GR.SET.PIXELS above, the list may describe a polygon relative to itself, and rely on <x_nexp> and <y_nexp> to specify where to put it on the screen. In addition, by using GR.MODIFY on these attributes, the program can easily move the polygon around on the screen. Negative <x_nexp> and <y_nexp> values are valid and result in relocation to the left and upward, respectively. If <x_nexp> and <y_nexp> are omitted, no relocation occurs and the (x, y) pairs in the list are absolute screen positions.

The same list can be used in different GR.POLY statements, and the statements may specify a paint that has a different color, stroke width, and fill mode.

In the OLI-BASIC private version, GR.POLY is conceptually different. GR.POLY uses a private copy of the list. Assigning new values to list elements does not cause a change to the drawn polygon until GR.POLY is informed there is a "new" list. </DIV> The program can use GR.MODIFY to change the relocation distances, and to change the list number that defines the polygon. It can also assign new values to relevant elements in the list to change the shape of the polygon that BASIC draws, the next time GR.RENDER occurs. This includes adding and removing points.

When GR.POLY is executed, or when the program changes the list using GR.MODIFY, the specified list must have an even number of elements, 4 or greater, so as to specify at least a line segment. If the program modifies the list, then subsequent GR.RENDER operations silently ignore violations of this rule: If the list now contains an odd number of elements, GR.RENDER does not use the final coordinate pair; and if the list now contains fewer than 4 elements, then GR.RENDER does not draw the polygon at all.

list, x, y
 * Modifiable attributes

The program, included in the RFO-BASIC! distribution, provides several working examples of GR.POLY.
 * Examples

GR_COLLISION
Detect overlap of two graphic objects

GR_COLLISION(<object1_nvar>, <object2_nvar>)
 * Synopsis

The GR_COLLISION function takes as parameters two numeric variables, each containing a valid object pointer returned by one of the following statements:
 * Description
 * GR.ARC
 * GR.BITMAP.DRAW
 * GR.CIRCLE
 * GR.OVAL
 * GR.POINT
 * GR.RECTANGLE
 * GR.TEXT.DRAW

Bug. When an RFO-BASIC! program uses the GR.ROTATE statements to rotate a graphic element, GR_COLLISION does not use the element's new screen location. </DIV> The function returns TRUE (a nonzero value) if the two graphic objects overlap, and FALSE (0) if they do not overlap.

Overlap is defined in terms of the graphic object's rectangular bounding box. Overlap of the bounding boxes is not the same thing as a collision between the objects as drawn:
 * For arcs, circles, and ovals, the thing tested is a rectangle and not the curves drawn. In an on-screen pinball game, GR_COLLISION does not detect when the pinballs touch.  (It returns TRUE too early except if the balls are aligned in the x or y dimension.)  This case is easily detected by instead determining whether the distance between centers exceeds the sum of the radii.
 * For text, the bottom of the rectangle is the baseline of the text. Thus, GR_COLLISION does not detect a collision with the descenders of letters, nor with diacritical marks drawn beneath letters.
 * GR_COLLISION does not take into account the stroke width (see GR.SET.STROKE). For example, the bounding box for a drawn point is a box 1 pixel high and 1 pixel wide, even though, with a stroke width greater than 1, the point would be drawn on many adjacent pixels.  Likewise, if other graphic elements were fattened by being drawn using large stroke widths, GR_COLLISION does not detect their extra area.
 * Bitmaps may have transparent regions. GR_COLLISION does not sense pixels drawn on the screen to determine whether the opaque regions of drawn objects are actually touching or overlapping.

Graphic text
The text console makes it easy to output text, such as with the PRINT statement, but without any special effects, even color. An RFO-BASIC! program can draw text on the graphics screen and take detailed control over things like size, color, exact location, and other typography.

Every character in graphic text is a shape. In rendering that character, BASIC may trace its outline, as it would draw any line or arc; and may then fill in the shape, depending as usual on the fill style that is set by GR.COLOR.

Only the GR.TEXT.DRAW statement draws text onto the graphics screen. There are many other GR.TEXT statements that set the rules for drawing text. These settings are stored in a paint, described above.

GR.TEXT.DRAW
Draw text on the graphics screen

GR.TEXT.DRAW <obj_nvar>, <x_nexp>, <y_nexp>, <text_sexp>
 * Synopsis

The GR.TEXT.DRAW statement draws the contents of <text_sexp> as a line of text onto the graphics screen, using tracing and drawing settings, such as color, that are contained in the current paint. The entire line of text is an object, and GR.TEXT.DRAW returns its object number in <obj_nvar>.
 * Description

The text is drawn starting at <x_nexp> and <y_nexp>, which are pixel positions on the graphics screen.

The horizontal position of the text, specified by <x_nexp>, is by default the left edge of the text. However, a program can use GR.TEXT.ALIGN to make GR.TEXT.DRAW statements accept the center or the right edge.

The vertical position of the text, specified by <y_nexp>, is the position of the text baseline. This is the line for the bottoms of any capital letters, and of most lowercase letters. On letters with descenders, such as "g", the character extends below the baseline. Consequently, the BASIC program should avoid two things:
 * Specifying <y_nexp> close to 0, to write to the "top line" of the graphics screen. This instead puts most of the text off the top of the screen.  Only the descenders would be visible.
 * Specifying <y_nexp> close to the height of the screen, to write to the "bottom line." The program should specify a smaller number so that the descenders are on the screen.  This may depend on the font being used.

text, x, y (If using GR.MODIFY to modify text, the new value must be a string representing the new text to draw.)
 * Modifiable attributes

There is a primitive but complete example of drawing text at GR.RENDER.
 * Example

See Text measurement below for:
 * See also
 * A more detailed discussion of the height of text drawn onto the graphics screen, including certain non-English characters.
 * BASIC statements that measure the dimensions of text if it were drawn on the graphics screen.
 * Formulas to tell if text will fit on the screen.

Fonts
A font is the style of the characters in which RFO-BASIC! draws text. Typical Android devices have a monospace font (a font in which all the characters have equal width), a serif font (in which characters have "feet" to enhance readability, like the fonts in a newspaper), and a sans-serif (without serif) font, which looks simpler and more modern.

GR.TEXT.SETFONT
Set the font in which text is drawn

GR.TEXT.SETFONT {<font_exp> {, <style_sexp>} {,<paint_nexp>}}
 * Synopsis

The GR.TEXT.SETFONT statement selects a font in which subsequent text is drawn. If <paint_nexp> is present, it is the number of a paint in which the setting is stored; if omitted, the statement affects the current paint.
 * Description

The <font_exp> parameter specifies the font. If it is a string expression, it must specify one of the font families available on the Android device, or else the default font is used, which is usually. The string can use capital or lowercase letters. Fonts called,  , and   are available on all Android devices. More recent Android versions also support,  ,  , and.

If <font_exp> is a string, then <style_sexp> can specify the style, again using capital or lowercase letters. If it is not one of the following, or is omitted, or the font is, then neither boldfacing nor italics is in effect:
 * (or ) for boldfacing
 * (or ) for italics
 * (or ) for both effects

If <font_exp> is a numerical expression, it must be a font pointer value to a user font that the FONT.LOAD statement returned. In this case, BASIC ignores <style_sexp>. You cannot load a font, such as, and specify italic, but you may be able to load.

If <font_exp> is omitted entirely, then GR.TEXT.SETFONT uses the user font most recently loaded by FONT.LOAD and not deleted. If there are no such fonts, then it reverts to the default font.

GR.TEXT.TYPEFACE
Set the font in which text is drawn (deprecated)

GR.TEXT.TYPEFACE {{<font_nexp>} {, <style_nexp>} {,<paint_nexp>}}
 * Synopsis

The GR.TEXT.TYPEFACE statement selects a font in which subsequent text is drawn. If <paint_nexp> is present, it is the number of a paint in which the setting is stored; if omitted, the statement affects the current paint.
 * Description

GR.TEXT.TYPEFACE is older and less powerful than the GR.TEXT.SETFONT statement described above. It is limited to the four built-in fonts that have numerical codes. The numerical parameters are optional, and have the following effects:

GR.TEXT.SIZE
Specify the size (height) of text

GR.TEXT.SIZE
 * Synopsis

The GR.TEXT.SIZE statement specifies the height of text, in pixels. BASIC will render text in a size such that characters entirely fit in <size_nexp> pixels, even characters with diacritical marks above the letter, and characters with descenders, such as "g".

Character width varies along with height, to preserve the font as designed. There is no option to stretch text by a specified percentage. To obtain characters wider or narrower than those designed into the font, here are several options:
 * Obtain a font with Condensed, Expanded, or Oblique style designed into it.
 * Use GR.SCALE to stretch or shrink everything written to the screen.
 * For the text that is to be condensed or expanded, use Draw-Into Mode to draw the text into a bitmap, then display the bitmap with altered dimensions. See the example at GR.BITMAP.DRAWINTO.END.

GR.TEXT.UNDERLINE
Specify underlining

GR.TEXT.UNDERLINE
 * Synopsis

The GR.TEXT.UNDERLINE statement determines whether text is drawn with a line beneath it. If <enabled_lexp> has the value 0, underlining is disabled. If it has any other value, underlining is enabled. If the parameter is omitted entirely, underlining is set to the opposite of what it was.
 * Description

GR.TEXT.STRIKE
Specify strikethrough (overstrike)

GR.TEXT.STRIKE
 * Synopsis

The GR.TEXT.STRIKE statement determines whether text is drawn with a line across it (struck out). If <enabled_lexp> has the value 0, strikethrough is disabled. If it has any other value, strikethrough is enabled. If the parameter is omitted entirely, strikethrough is set to the opposite of what it was.
 * Description

Strikethrough is a technique sometimes used to show that text has been deleted, or that information on the screen is no longer in effect.

GR.TEXT.SKEW
Specify skew (italics)

GR.TEXT.SKEW
 * Synopsis

The GR.TEXT.SKEW statement determines whether text is drawn skewed, that is, in italics. If <enabled_lexp> has the value 0, skewing is disabled. If it has any other value, skewing is enabled. If the parameter is omitted entirely, skewing is set to the opposite of what it was.
 * Description

It is more attractive to use a font where font designers have designed italic characters, than to use a font where they have not, and ask BASIC to render italics by simple skewing. Therefore, instead of using GR.TEXT.SKEW, the following techniques are preferred:
 * Specify italics when selecting a font, such as with
 * Load a user font designed with italics, such as

However, if the Android device has a font and does not have the corresponding italic font, then there is no alternative to GR.TEXT.SKEW except to not show italics at all.

GR.TEXT.BOLD
Specify boldfacing

GR.TEXT.BOLD
 * Synopsis

The GR.TEXT.BOLD statement determines whether text is drawn in boldface. If <enabled_lexp> has the value 0, boldfacing is disabled. If it has any other value, boldfacing is enabled. If the parameter is omitted entirely, boldfacing is set to the opposite of what it was.
 * Description

It is more attractive to use a font where font designers have designed boldfaced characters, than to use a font where they have not, and ask BASIC to render boldfaced characters by computation. Therefore, instead of using GR.TEXT.BOLD, the following techniques are preferred:
 * Specify boldfacing when selecting a font, such as with
 * Load a user font designed with boldface, such as

However, if the Android device has a font and does not have the corresponding boldface font, then there is no alternative to GR.TEXT.BOLD except to not show boldfacing at all.

Yet another technique for producing fatter characters is to set the fill style of GR.COLOR to 2 (stroke-and-fill) and use GR.SET.STROKE to set a stroke width much greater than 1. (Suitable values will depend on the text size and on the number of pixels on the Android device.) However, again, this method produces boldfacing by algorithm, which is likely to be less attractive than using a font with boldfacing designed into the characters.

Related techniques
There are several useful techniques that can also be achieved by taking advantage of the fact that drawing text is divided into tracing and filling shapes.

By setting the fill style of GR.COLOR to 0 (stroke and do not fill), text can be drawn as an outline and not filled in. This is an alternative to graying-out text, for instance, to indicate to the user options that are temporarily irrelevant or disabled, with less confusion than removing the options from the screen entirely.
 * Outline

By setting GR.COLOR to opaque white with a fill style of stroke-only, drawing text, setting GR.COLOR to a dark color with a fill style of fill-only, then drawing the same text, a program can produce text with contrasting edges. For example, such text can be drawn on top of a bitmap with good visibility no matter whether it lands over a light or a dark area of the bitmap.
 * Shadowing

GR.TEXT.ALIGN
Specify text alignment

GR.TEXT.ALIGN
 * Synopsis

The GR.TEXT.ALIGN statement governs how subsequent GR.TEXT.DRAW statements interpret their <x_nexp> parameters. This parameter normally marks the left edge of the box where GR.TEXT.DRAW draws the text. However:
 * Description
 * If <align_nexp> is 2, then GR.TEXT.DRAW statements will interpret their <x_nexp> as the center of the text.
 * If <align_nexp> is 3, then GR.TEXT.DRAW statements will interpret their <x_nexp> as the right edge of the text.

If <align_nexp> has any other value, or is omitted entirely, GR.TEXT.DRAW reverts to positioning text so that the horizontal position parameter gives the left edge.

A program can locate text exactly where desired; GR.TEXT.ALIGN merely simplifies the job of specifying it. When drawing several lines that are to appear centered around the same horizontal position, specifying  lets the program use this position as the <x_nexp> for all those lines. When drawing several lines that are to be right-justified, specifying  lets the program supply the right edge to all the GR.TEXT.DRAW statements. Without this simplification, the program would have to compute the position of each line based on the rendered width of the text.

The following Text measurement statements are how a program performs such computations.
 * See also

GR.TEXT.HEIGHT
Measure the height of graphic text

GR.TEXT.HEIGHT {<height_nvar>} {, <up_nvar>} {, <down_nvar>}
 * Synopsis

The GR.TEXT.HEIGHT statement obtains information on the vertical size of text that would be drawn using the current paint. (RFO-BASIC! provides no way to compute the actual height occupied by text that was drawn.)
 * Description

If <height_nvar> is present, GR.TEXT.HEIGHT sets it to the height in pixels of most text in most languages. If the program used GR.TEXT.SIZE, then this value is the value it specified.

Some characters require additional space. For example, "É" in French and Spanish, and "Ż" in Polish, have a diacritical mark above a capital letter. Any font that has this character renders it above the height specified in GR.TEXT.SIZE. The dot is above the entire illustration. If <up_nvar> is specified, GR.TEXT.HEIGHT sets it to the distance in pixels of the tallest character above the baseline. This is always a negative number, because it is a distance from the baseline back toward the top of the screen.

If <down_nvar> is specified, GR.TEXT.HEIGHT sets it to the height of the zone occupied by descenders. This is a positive value, and again, measured from the baseline. Therefore:
 * The sum of these two numbers (actually, down &minus; up since up is a negative number) is the space that must be allowed to accommodate text in the most extreme case.
 * When GR.TEXT.DRAW draws text at vertical position y, the lowest vertical position that descenders could occupy is y + down, and the highest vertical position that a diacritical mark above a capital letter could occupy is y + up.
 * Excluding these foreign characters, text will not range above y + down &minus; height.

GR.TEXT.WIDTH
Measure the width of graphic text

GR.TEXT.WIDTH <width_nvar>, <text_exp>
 * Synopsis

The GR.TEXT.WIDTH returns, in <width_nvar>, the width of graphic text.
 * Description
 * If <text_exp> is a string, then GR.TEXT.WIDTH returns the number of horizontal pixels it would take to draw that string as graphic text, using the settings in the current paint, such as the typeface, size, and style specified most recently.
 * If <text_exp> is numeric, then its value must be the object number returned by a GR.TEXT.DRAW statement, or else it is a run-time error. GR.TEXT.WIDTH returns the number of horizontal pixels that the GR.TEXT.DRAW statement would use if its text element were rendered right now.  (If the program uses GR.MODIFY, or modifies the relevant paint, before calling GR.RENDER, then this value might become inaccurate.)

GR.GET.TEXTBOUNDS
Measure the size of text

GR.GET.TEXTBOUNDS <text_exp>, <left_nvar>, <top_nvar>, <right_nvar>, <bottom_nvar>
 * Synopsis

The GR.GET.TEXTBOUNDS statement gets the boundary rectangle of a string as it would be drawn on the screen.
 * Description
 * If <text_exp> is a string, then GR.GET.TEXTBOUNDS returns the rectangle that would contain that string as graphic text, using the settings in the current paint, such as the typeface, size, and style specified most recently.
 * If <text_exp> is numeric, then its value must be the object number returned by a GR.TEXT.DRAW statement, or else it is a run-time error. GR.GET.TEXTBOUNDS returns the rectangle that the GR.TEXT.DRAW statement would use if its text element were rendered right now.  (If the program uses GR.MODIFY before GR.RENDER, then this value might become inaccurate.)

GR.GET.TEXTBOUNDS reports the dimensions as though a GR.TEXT.DRAW statement were written to draw the text at 0,0. To determine the actual screen space used to hold that text, one must add the x or y values passed to the GR.TEXT.DRAW statement.

Bitmaps
Bitmaps comprise the illustrations on the graphics screen. Instead of points, lines, shapes, or text, these elements come from a file, or through a use of Draw-Into Mode. The file may be of type .BMP, which describes each point (or bit or pixel) in the illustration, or of type .GIF or .JPG or .PNG, which use coding to compress the size of the file.

The GR.BITMAP.LOAD statement loads a bitmap from storage (internal storage or a device such as a microSD card) into Android memory and returns a <B>bitmap pointer</B> the BASIC program uses to refer to the bitmap. The GR.BITMAP.DRAW statement creates a separate object in the Display List. Like any other drawing statement, this object calls for the illustration to be drawn when the program calls GR.RENDER.

Even if a program uses GR.CLS to discard the Display List (typically to start over and regenerate the information to be rendered on the graphics screen), RFO-BASIC! does not discard bitmaps until the program ends, or calls GR.BITMAP.DELETE. Programs structured with a main loop that calls GR.CLS, regenerates the graphics screen, and calls GR.RENDER to render the information, must not reload the bitmap on each pass through the main loop (unless they discard the bitmap after rendering), or they will quickly exhaust the available memory.

Whether or not the stored version of the bitmap uses techniques to reduce file size, the in-memory version of the bitmap uses four bytes of memory for each pixel. So a 400-by-400-pixel bitmap uses 400✕400✕4 = 640,000 bytes. Any BASIC statement that creates a bitmap will fail if there are insufficient memory bytes available to the program. In this case, the statement returns -1 as the bitmap pointer. The program should always check for this. If the returned pointer is -1, the program can call the GETERROR$ function to get more details about the error.

Some cases that exhaust the available Android memory might not be detected by the GR.BITMAP statements. Subsequent statements might fail, displaying an error message on the console screen. When the user returns to the editor, BASIC highlights a line near the one that exceeded the memory limit. This might not be the exact BASIC statement that exceeded it.

GR.BITMAP.LOAD
Load a bitmap

GR.BITMAP.LOAD <bptr_nvar>, <filename_sexp>
 * Synopsis

The GR.BITMAP.LOAD statement creates a bitmap from the file specified in <filename_sexp>. This string is the name of a file containing the bitmap. It is assumed to reside in the  directory. However, the string can contain relative pathnames, using, to specify a different directory. The bitmap may be on a device such as a microSD card, although the pathname that refers to such a device differs among Android devices.
 * Description

If GR.BITMAP.LOAD loads a bitmap, <bptr_nvar> is the bitmap pointer the program uses to refer to the bitmap, such as in a subsequent GR.BITMAP.DRAW statement. If it does not load a bitmap, then it sets <bptr_nvar> to -1, which cannot be used as a bitmap pointer. The program should check for this case. It can call the GETERROR$ function for more information about the failure. This function may return:
 * The file or resource does not exist.
 * There is not enough memory available to create the bitmap.

Loaded bitmaps cannot be used with Draw-Into Mode. However, a program can create an empty bitmap, draw a loaded bitmap into it, and draw over the bitmap.

After loading a bitmap, the program can resize it into another bitmap using GR.BITMAP.SCALE. The bitmap is not added to the Display List until the program draws it using GR.BITMAP.DRAW, and as always, it is not visible on the graphics screen until the program renders the Display List by calling GR.RENDER.
 * See also

GR.BITMAP.SCALE
Load a scaled bitmap

GR.BITMAP.SCALE <new_bptr_nvar>, <bptr_nexp>, <width_nexp>, <height_nexp> {, <smoothing_lexp>}
 * Synopsis

The GR.BITMAP.SCALE statement creates a bitmap whose contents are those of the previously loaded bitmap <bptr_nexp>, changed to the specified width and height. The statement sets <new_bptr_nvar> to a pointer that refers to the new (derived) bitmap. The original bitmap still exists. If the program loaded the original bitmap only to create a scaled bitmap, then it should delete the original bitmap using GR.BITMAP.DELETE.
 * Descrption

GR.BITMAP.SCALE can fail just as GR.BITMAP.LOAD can. The program can react to such failures as it does in the case of GR.BITMAP.LOAD.

Neither <width_nexp> nor <height_nexp> may be zero. However, either or both may be negative. In this case, the scaled bitmap is flipped in that dimension (left-to-right or upside-down).

Normally, the scaled bitmap is smoothed. This uses image enhancement to increase the visual attractiveness of the scaled bitmap. If the optional <smoothing_lexp> parameter is present and if its value is 0, then the scaled bitmap is not smoothed. Instead, if either height or width is reduced from the original bitmap, this is achieved by removing entire rows or columns of pixels. If either height or width is increased from the original bitmap, this is achieved by duplicating entire rows or columns of pixels.

GR.BITMAP.CROP
Load a cropped bitmap

GR.BITMAP.CROP <new_bptr_nvar>, <bptr_nexp>, <x_nexp>, <y_nexp>, <width_nexp>, <height_nexp>
 * Synopsis

The GR.BITMAP.CROP statement creates a bitmap whose contents are a rectangular piece of the previously loaded bitmap <bptr_nexp>, starting at the upper-left corner given by (<x_nexp>, <y_nexp>), and with the specified width and height. The statement sets <new_bptr_nvar> to a pointer that refers to the new (derived) bitmap. The original bitmap still exists. If the program loaded the original bitmap only to create a cropped bitmap, then it should delete the original bitmap using GR.BITMAP.DELETE.
 * Descrption

The cropped bitmap is exactly the size of the specified rectangular region of the original bitmap. To obtain a bitmap with a different size — for example, to take a piece of the original bitmap and produce a bitmap of the same dimensions, consisting only of this piece — pass <new_bptr_nvar> as the <bptr_nexp> in a call to GR.BITMAP.SCALE.

GR.BITMAP.CROP can fail just as GR.BITMAP.LOAD can. The program can react to such failures as it does in the case of GR.BITMAP.LOAD.

GR.BITMAP.DRAW
Draw a bitmap

GR.BITMAP.DRAW <obj_nexp>, <bptr_nexp>, <x_nexp>, <y_nexp>
 * Synopsis

The GR.BITMAP.DRAW statement draws the bitmap whose bitmap pointer is <bptr_nexp>. The statement creates an object in the Display List so that the bitmap appears on the graphics screen, with its upper-left corner at (<x_nexp>, <y_nexp>), when the program renders the graphics screen with GR.RENDER.
 * Description

If the current paint has an alpha value other than 255 (opaque), then the bitmap is drawn on top of what was previously on that region of the graphics screen, with the specified degree of transparency.

bitmap, x, y
 * Modifiable attributes

GR.BITMAP.DELETE
Delete a bitmap

GR.BITMAP.DELETE <bptr_nexp>
 * Synopsis

The GR.BITMAP.DELETE statement releases the specified bitmap from Android memory. The memory the bitmap used is available for other uses by the BASIC program.
 * Description

The program should delete bitmaps from memory if it only loaded them to create a scaled bitmap using GR.BITMAP.SCALE, or a cropped bitmap using GR.BITMAP.CROP, once the bitmap has served that purpose.

Deleting a bitmap does not remove objects in the Display List that refer to the bitmap, such as those created by the GR.BITMAP.DRAW statement. Unless the program applies GR.HIDE to such objects, or uses GR.CLS and then regenerates the Display List to not refer to bitmaps it has deleted, the GR.RENDER statement will fail.

Other bitmap statements
The statements in this section can be used either with bitmaps loaded from storage by GR.BITMAP.LOAD, or blank bitmaps created by GR.BITMAP.CREATE and drawn into using Draw-Into Mode.

GR.BITMAP.SIZE <bptr_nexp>, <width_nvar>, <height_nvar>
 * The GR.BITMAP.SIZE statement returns the dimensions of the specified bitmap in <width_nvar> and <height_nvar>.

GR.BITMAP.SAVE <bptr_nexp>, <filename_sexp>{, <quality_nexp>}
 * The GR.BITMAP.SAVE statement saves the specified bitmap into a stored file whose name is <filename_sexp>, which is assumed to be in the directory .  If the filename ends in ".jpg" then the bitmap is saved as a file in the JPEG format at the quality level specified by <quality_nexp>.  Otherwise, the bitmap is saved as a file in the PNG format.  More details about the <filename_sexp> and <quality_nexp> parameters are the same as for GR.SAVE.

GR.GET.BMPIXEL <bptr_nexp>, <x_nexp>, <y_nexp>, <alpha_nvar>, <red_nvar>, <green_nvar>, <blue_nvar>
 * The GR.GET.BMPIXEL statement analyzes a single pixel of the specified bitmap, at pixel coordinates (x, y), and returns in the variables its alpha (transparency), red, green, and blue components. The pixel coordinates must be valid for the size of the bitmap.

GR.BITMAP.FILL <bptr_nexp>, <x_nexp>, <y_nexp>
 * The GR.BITMAP.FILL statement performs a flood-fill of the specified bitmap. Starting with the pixel at coordinates (x, y), it sets that pixel, and any adjacent area of pixels of the same color, to the color of the current paint.


 * If the specified bitmap was drawn using anti-aliasing, then boundaries between graphic elements are blurred to appear smoother. This means that pixels on the boundary will not be exactly the same color as the rest of the area, and the flood-fill will not reach to the exact edge of the area.

Draw-Into Mode
Normally, the drawing statements of RFO-BASIC! build a Display List of objects, and calling GR.RENDER renders the corresponding elements onto the graphics screen. The objects can be moved, rotated, and modified, affecting their appearance the next time the program renders the Display List.

In Draw-Into Mode, BASIC instead draws every specified element into a specified bitmap. Elements do not receive numbers that would make it easy to modify the elements later, and they are not added to a Display List. It is still true that elements drawn into a bitmap can be modified by elements drawn into it later in time. The bitmap itself does not appear in the Display List until explicitly drawn with GR.BITMAP.DRAW, and does not appear on the graphics screen until the Display List is rendered with GR.RENDER.

GR.BITMAP.CREATE
Create a bitmap to be drawn into

GR.BITMAP.CREATE <bptr_nvar>, <width_nvar>, <height_nvar>
 * Synopsis

The GR.BITMAP.CREATE statement creates an empty bitmap of the specified width and height. This is not limited to the size of the physical screen; the program can prepare a large bitmap and can crop pieces of it for actual display. The statement returns <bptr_nvar>, a bitmap pointer that the program can use to refer to the new bitmap.
 * Description

The new bitmap requires width✕height✕4 bytes of memory. GR.BITMAP.CREATE can fail just as GR.BITMAP.LOAD can. The program can react to such failures as it does in the case of GR.BITMAP.LOAD.

GR.BITMAP.DRAWINTO.START
Start Draw-Into Mode

GR.BITMAP.DRAWINTO.START <bptr_nexp>
 * Synopsis

The GR.BITMAP.DRAWINTO.START statement starts Draw-Into Mode. All subsequent drawing statements do not create objects in the Display List, but instead draw directly into the bitmap whose number is <bptr_nexp>. This must be a blank bitmap created by GR.BITMAP.CREATE; it cannot be a bitmap loaded from storage by GR.BITMAP.LOAD. However, preloaded bitmaps can be drawn into <bptr_nexp> during Draw-Into Mode.
 * Description

While BASIC is in Draw-Into Mode, the <ptr_nexp> returned by any drawing statements is not valid, and the program cannot use any of the usual techniques to affect graphic elements before rendering them, such as moving, hiding, or modifying them.

The bitmap being drawn into has no effect on the graphics screen until the program exits Draw-Into Mode, draws the bitmap normally, using GR.BITMAP.DRAW, and renders the Display List using GR.RENDER.

GR.BITMAP.DRAWINTO.END
End Draw-Into Mode

GR.BITMAP.DRAWINTO.END
 * Synopsis

The GR.BITMAP.DRAWINTO.END statement ends Draw-Into Mode and returns RFO-BASIC! to the usual mode, in which drawing statements assemble a Display List to be rendered on the graphics screen by GR.RENDER.
 * Description

Having drawn into a bitmap during Draw-Into Mode, what the BASIC program does after ending Draw-Into Mode is use the bitmap it was drawing into: Either draw it or derive another bitmap from it by cropping or scaling.

To draw condensed text if a Condensed font is not available, a program could draw the text into a bitmap, compress the entire bitmap into a new bitmap using GR.BITMAP.SCALE, and draw that bitmap onto the graphics screen:
 * Example

OutdoorTmp = 23 GR.OPEN GR.COLOR 255,0,0,0 !Temporary bitmap is 100 pixels high. GR.TEXT.DRAW puts the baseline at y=90. !Text size of 80 means numerals are drawn between y=10 and y=90. GR.BITMAP.CREATE Bmp1,200,100 GR.BITMAP.DRAWINTO.START Bmp1 GR.TEXT.TYPEFACE 2,2 GR.TEXT.SIZE 80 GR.TEXT.DRAW unused,0,90,STR$(OutdoorTmp) GR.BITMAP.DRAWINTO.END GR.BITMAP.SCALE Bmp2,Bmp1,100,100  % Copy into new bitmap of half the width GR.BITMAP.DRAW obj1,Bmp2,0,0       % Draw the second bitmap onto graphic screen GR.TEXT.DRAW obj2,100,90,"Degrees" % Add some uncompressed text GR.RENDER PAUSE 5000 END

Modifying the Display List
Every drawing of a point, line, shape, or string of text adds an object to the Display List. The elements are actually rendered on the screen of the Android device only when the program executes GR.RENDER.

As set out in the introduction, one way to structure a program that outputs to the graphics screen is to have a prologue that draws everything, and a main loop that modifies the objects in response to real-time inputs and then calls GR.RENDER.

Each section that defines a BASIC statement that draws, sets out a list of Modifiable attributes. These attributes can be modified by calling GR.MODIFY. In addition, any object in the Display List can be hidden with GR.HIDE — that is, set to inhibit display — and later re-enabled with GR.SHOW. All such modifications take effect the next time the graphics screen is rendered.

GR.MODIFY
Modify an object in the Display List

GR.MODIFY <obj_nexp>{, <tag_sexp>, <value_exp>}...
 * Synopsis

The GR.MODIFY statement modifies one or more modifiable attributes of an object in the Display List. The <obj_nexp> parameter must have a value that is the number of such an object, as returned by a BASIC statement that draws a graphic element. The <tag_sexp> parameter must be the name of a modifiable attribute of that kind of object. The <value_exp> parameter contains the new value for that modifiable attribute. Most attributes require that <value_exp> be numeric, but the text attribute of an object created by GR.TEXT.DRAW must be followed by a string value. GR.MODIFY can change only one object at a time, but it can contain any number of tag/value pairs.
 * Description

For any object in the Display List, the valid tags depend on the BASIC statement that drew the element and thus created the object. A list of valid tags is set out in the definition of that statement, under Modifiable attributes. Every object has two additional modifiable attributes:
 * paint is the number of the paint that contains the settings governing the drawing of that object, such as color, transparency, stroke width, fill style, and so on. This tag can be modified with the number of another paint.  For example, a circle that was drawn in opaque black paint can be modified to be drawn in transparent blue paint, the next time it is rendered.  This is a simple alternative to re-drawing the element, which also consumes Android memory.
 * alpha is the transparency. Transparency is one component of a paint.  However, by specifying alpha, the program can change an object's transparency without having to create or modify paints.  This makes it easy to animate fade-out and fade-in effects.  Transparency values range from 0 (invisible) to 255 (opaque).  The value of 256 in GR.MODIFY is a special case that makes the object use the transparency value in the current paint.

The following GR.MODIFY statement changes text that was drawn, to reflect current conditions. If a program is using the graphics screen just as a gauge, its main loop may obtain those conditions somehow, execute one or more GR.MODIFY statements like this one, and then do GR.RENDER. The original GR.TEXT.DRAW fixed the size, style, and location of the text, and this GR.MODIFY does not modify those attributes: GR.MODIFY text_ptr, "text", FORMAT$("-##%.%", OutdoorTemp)
 * Examples

Suppose BM_ptr is the object number of a bitmap drawn by. Then the program can move it rightward, from 400 to 420, with: GR.MODIFY BM_ptr, "x", 420

The program can change the object to use a different (pre-loaded) bitmap: GR.MODIFY BM_ptr, "bitmap", saturn_ptr

These two effects could be achieved in a single GR.MODIFY statement: GR.MODIFY BM_ptr, "x", 420, "bitmap", saturn_ptr

The following code uses alpha to make an object fade in and out: DO FOR a = 1 TO 255 STEP 10 GR.MODIFY object, "alpha", a GR.RENDER PAUSE 250 NEXT a FOR a = 255 TO 1 STEP -10 GR.MODIFY object, "alpha", a GR.RENDER PAUSE 250 NEXT a UNTIL 0

Some drawing statements allow their effects to be modified without using GR.MODIFY:
 * See also
 * For GR.SET.PIXELS, the program can make changes to the array that specifies the (x, y) coordinates for the pixels to be drawn.
 * For GR.POLY, the program can modify the List structure that gives the (x, y) coordinates with which to draw the polygon.
 * The program can modify a paint, rather than using GR.MODIFY to make an object use a different paint.

GR.HIDE
Inhibit a graphic element from being rendered

GR.HIDE <obj_nexp>
 * Synopsis

The GR.HIDE statement inhibits a graphic element from being rendered. The <obj_nexp> parameter must be the number of an object in the Display List. It may be the number of a group, in which case, all elements in the group are hidden.
 * Description

GR.SHOW
Allow a graphic element to be rendered

GR.SHOW <obj_nexp>
 * Synopsis

The GR.SHOW statement allows a graphic element to be rendered. The <obj_nexp> parameter must be the number of an object in the Display List. It may be the number of a group, in which case, all elements in the group are shown.
 * Description

All graphic elements are renderable by default, though none is actually rendered until a call to GR.RENDER. There is no reason to use GR.SHOW unless the program had hidden elements by calling GR.HIDE.

GR.SHOW.TOGGLE
Reverse the hidden status of a graphic element

GR.SHOW.TOGGLE <obj_nexp>
 * Synopsis

The GR.SHOW.TOGGLE statement reverses the hidden status of a graphic element. The <obj_nexp> parameter must be the number of an object in the Display List. If <obj_nexp> had been hidden, then GR.SHOW.TOGGLE un-hides it, like GR.SHOW. Otherwise, GR.SHOW.TOGGLE hides it, like GR.HIDE. It may be the number of a group, in which case, each elements in the group has its hidden status reversed; those that were hidden become un-hidden, and those that were shown become hidden.
 * Description

GR.MOVE
Move a graphic element

GR.MOVE <obj_nexp>
 * Synopsis

The GR.MOVE statement moves a graphic element in the direction specified by (dx, dy). Both these parameters can be omitted, in which case they default to a value of 0 (the graphic element is not moved in that dimension).
 * Description

The effect of GR.MOVE is to modify the x and y modifiable attributes of the specified object. Therefore, any subsequent GR.MOVE statement moves the element further in the direction the follow-on statement specifies. GR.MOVE is equivalent, but generally more concise, than modifying these attributes with GR.MODIFY.

The original x and y values are lost. If the program did not store the values, there is no BASIC statement that returns the element to the screen location where it was originally drawn.

The <obj_nexp> parameter can refer to a group, in which case all elements in that group move together (when the graphics screen is next rendered).

GR.MOVE circle1,1,0  % Move a circle one pixel to the right GR.MOVE circle1,1    % Equivalent to omit dy GR.MOVE circle1,0,-5  % Move the circle five pixels up GR.MOVE circle1,,-5   % Equivalent to omit dx
 * Examples

Examining the Display List
Normally, a program stores in well-named variables the objects that it might elect to modify later. However, a program may create graphic elements in response to user input, and use the Display List as a database from which it can extract information later, if the need arises. The following statements query the Display List:

GR.GET.TYPE <obj_nexp>, <type_svar>
 * If <obj_nexp> is the number of an object in the Display List, then GR.GET.TYPE sets <type_svar> to a string value that indicates the BASIC statement that drew it. This may be: arc, bitmap, circle, line, oval, pixels, point, poly, rect, or text.


 * If <obj_nexp> is the number of a group, then GR.GET.TYPE sets <type_svar> to group. If it is the number of an object created by GR.CLIP, then <type_svar> is clip.  If it is the number of an object created by GR.ROTATE, then <type_svar> is rotate.  If it is not an object from the Display List, then <type_svar> is the empty string.  The program can use GETERROR$ to get details about the error.

GR.GET.PARAMS <obj_nexp>, <param_array$[]>
 * If <obj_nexp> is the number of an object in the Display List, then GR.GET.PARAMS places in the one-dimensional string array <param_array$[]> all the modifiable attributes of that object, in no particular order. If the array exists, GR.GET.PARAMS overwrites it; otherwise, it creates a new array.


 * Once obtaining the names of the modifiable attributes with GR.GET.PARAMS, the program can obtain their current values with GR.GET.VALUE and can modify them with GR.MODIFY.

GR.GET.VALUE <obj_nexp> {, <tag_sexp>, <value_var>}...
 * If <obj_nexp> is the number of an object in the Display List, then for each <tag_sexp> containing a modifiable attribute of that object, GR.GET.VALUE sets <value_var> to the current value of that attribute. GR.GET.VALUE can query only one object at a time, but it can obtain any number of values from it.


 * Valid values for <tag_sexp> depend on what type of object <obj_nexp> is. This can be determined using GR.GET.TYPE, above.  The program can also call GR.GET.PARAMS, below, to enumerate the modifiable attributes of <obj_nexp>.  If any <tag_sexp> is not a modifiable attribute of <obj_nexp>, then the corresponding <value_var> is the empty string.  Most attributes require that <value_var> be a string variable, but any time that <tag_sexp> contains text, the corresponding <value_var> must be a string variable.  If the program violates any of these rules, GR.GET.VALUE does not set the corresponding <value_var>.  The program can use GETERROR$ to get details about the error.

Groups
The RFO-BASIC! program can organize arbitrary objects from the Display List into a group. The group receives an object with a number unique to all others in the Display List. Grouping elements into a group does not affect their rendering, but lets the program easily specify changes to each member of the group.

The program can use the group object, as the <obj_nexp> parameter instead of an object describing a single graphic element, in the following statements:
 * In the GR.MOVE statement, to move each element in the group
 * In the GR.HIDE statement, to hide each element in the group
 * In the GR.SHOW statement, to un-hide each element in the group
 * In the GR.SHOW.TOGGLE statement, to reverse the hidden status of each element in the group

GR.GROUP
Create a group by naming specific elements

GR.GROUP <group_obj_nvar>{, <obj_nexp>}...
 * Synopsis

The GR.GROUP statement creates a group and returns the number of its object in <group_obj_nvar>. The program follows this numeric variable with one or more numeric expressions, shown above as <obj_nexp>. Each of these must be a number of an object already in the Display List. Each object becomes a member of the new group.
 * Description

GR.GROUP creates a List (see Data structures) to hold the numbers of the objects that are members of the group. The program can obtain the number of this List with GR.GET.VALUE and can change the list that belongs to the group using GR.MODIFY.

list
 * Modifiable attribute

The following is a complete program that creates four red circles, then creates a group containing one of the circles, and uses its membership in the group to move that circle:
 * Example

GR.OPEN ,,,,,1 GR.COLOR ,255,0,0,2 GR.CIRCLE c1,100,100,40 GR.CIRCLE c2,100,200,40 GR.CIRCLE c3,100,300,40 GR.CIRCLE c4,100,400,40 GR.RENDER : PAUSE 1000           % draw four red circles GR.GROUP g, c1                   % create a group with one circle GR.MOVE g, 0, 50                 % move whole group 0 up/down, 50 right GR.RENDER : PAUSE 1000           % the circle moves GR.GET.VALUE g, "list", gList    % get the number of the list the group is using LIST.ADD gList, c2               % add another circle to the group’s list GR.MOVE g, 0, 50 GR.RENDER : PAUSE 1000           % two circles move LIST.ADD gList, c3               % add another circle to the group’s list GR.MOVE g, 0, 50                 % three circles move GR.RENDER : PAUSE 1000 GR.CLOSE : END

Other Group statements
GR.GROUP.LIST <group_obj_nvar>{, <list_nexp>}
 * Rather than create a BASIC List to hold a sequence of parameters, as GR.GROUP does, GR.GROUP.LIST uses an existing List (see Data structures). GR.GROUP.LIST performs no validation of the contents of the List.  If <list_nexp> is not the number of an existing List, or if the parameter is omitted, then the resulting group contains no elements.

GR.GROUP.GETDL <group_obj_nvar>
 * The GR.GROUP.GETDL statement includes every object currently in the Display List in a new group.

GR.GROUP.NEWDL <group_obj_nvar>
 * The GR.GROUP.NEWDL statement discards the current Display List and installs the specified group as the Display List.

By using GR.GROUP.GETDL and GR.GROUP.NEWDL, the BASIC program could maintain multiple groups and substitute one or the other, from time to time, as the Display List with which to render the graphics screen.

list
 * Modifiable attribute

Rotation
The GR.ROTATE.START and GR.ROTATE.END statements add objects to the Display List. These objects do not draw anything by themselves. Instead, they provide that any objects between them in the Display List are rotated before being drawn.

The program must call both GR.ROTATE.START and GR.ROTATE.END to put both objects in the Display List, bracketing the graphic elements that are to be rotated. Any list of renderable objects to be rotated, such as a list passed to GR.NEWDL to create an alternate Display List, must include both objects.

GR.ROTATE.START
Start a rotation region

GR.ROTATE.START <angle_nexp>, <x_nexp>, <y_nexp>{, <obj_nvar>}
 * Synopsis

The GR.ROTATE.START statement adds an object to the Display List that provides that subsequent objects are rotated before being drawn. The rotation is by <angle_nexp> degrees in the clockwise direction around the point on the graphics screen given by (<x_nexp>, <y_nexp>) pixels.
 * Description

angle, x, y
 * Modifiable attributes

GR.ROTATE.END
End a rotation region

GR.ROTATE.END {<obj_nvar>}
 * Synopsis

The GR.ROTATE.END statement adds an object to the Display List that ends a rotation region begun by GR.ROTATE.START. Subsequent objects are not rotated.
 * Description

None; a program modifies the attributes of a rotation region by applying GR.MODIFY to the object that GR.ROTATE.START creates.
 * Modifiable attributes

The following user-defined routine shows how the compass point in the nearby illustration can be rotated in any desired direction. The compass point itself is drawn as three nearly parallel lines. The routine draws it pointing North but the two GR.ROTATE statements rotate it appropriately. You might instead define a polygon and pass its index to the routine, which would draw it with GR.POLY. FN.DEF Compass(xcenter, ycenter, radius, bearing) GR.SCREEN w, h      % Get screen dimensions GR.SET.STROKE 3     % Temporarily draw with broad lines % Caller specifies the hue; GR.COLOR 64,,,,0    % circle (outline, not disc) is drawn semi-transparent GR.CIRCLE ignore, xcenter,ycenter, radius GR.COLOR 64         % Set transparency for rotating compass point !The following three GR.LINE elements are rotated by "bearing" degrees GR.ROTATE.START bearing, xcenter, ycenter, CompassObject radius *= 0.9 GR.LINE ignore, xcenter,ycenter,         xcenter,ycenter-radius GR.LINE ignore, xcenter+(0.02*h),ycenter, xcenter,ycenter-radius GR.LINE ignore, xcenter-(0.02*h),ycenter, xcenter,ycenter-radius GR.ROTATE.END GR.SET.STROKE 0     % Return to the default stroke width FN.RTN CompassObject FN.END
 * Example

If the main program regenerated and re-rendered the screen, it would call this routine each time. If the main program used GR.MODIFY on the display elements and then re-rendered, it would not have to call the routine again, but could rotate the compass point with: GR.MODIFY CompassObject, "angle", NewBearing

Clip regions
Region Operators 2 through 5 are disallowed in Android devices starting with API 28. Private versions of RFO-BASIC! have adapted to this in different ways. HBASIC has replaced the GR.CLIP statement entirely. </DIV> Clipping means that the effect of an RFO-BASIC! drawing statement applies only to a rectangular sub-region of the graphics screen called a clip region. Clip regions can be combined to produce a clip region that is more complex than a single rectangle.

The manner in which clip regions are implemented and combined is specified using a "Region Operator."

GR.CLIP
Start a clip region

GR.CLIP <ptr_nexp>, <left_nexp>, <top_nexp>, <right_nexp>, <bottom_nexp>{, <RO_nexp>}
 * Synopsis

The GR.CLIP statement does not draw anything, but places an object in the Display List that affects how subsequent drawing statements function. The statement defines a rectangle on the graphics screen by specifying one corner at pixel address (left, top) and the opposite corner at (right, bottom). Usually, any drawing statement that follows GR.CLIP affects only the pixels in this rectangle.
 * Description

The optional <RO_nexp> parameter is the Region Operator. It affects the meaning of the rectangle. If GR.CLIP is used more than once, <RO_nexp> specifies how the new rectangle interacts with the clip region previously established.

bottom, left, right, RO, top.
 * Modifiable attributes

The following program defines two clip regions (two intersecting rectangles) and a Region Operator of Intersect. It displays an image, subject to both clip regions. Then it uses GR.MODIFY to modify the Region Operator of the second GR.CLIP (which was initialized to 0 by the number in red) to each of the five other valid values, re-rendering the display for three seconds each: GR.OPEN GR.BITMAP.LOAD Bmp1,"Fox.jpg"      % Or use a photo in your rfo-basic/data directory GR.CLIP obj1, 20,20,  300,150, 0   % Define the first clip region GR.CLIP obj2, 100,100, 450,250, <SPAN STYLE="color: red">0</SPAN>  % Define the second clip region GR.BITMAP.DRAW obj3,Bmp1,0,0       % Draw clipped photo from upper left corner GR.RENDER PAUSE 3000                         % Leave it up for 3 seconds FOR I=1 TO 5 GR.MODIFY obj2, "RO", I    % Modify 2nd GR.CLIP to have another Region Operator GR.RENDER                  % Re-render it that way PAUSE 3000                 % Leave it up for 3 seconds NEXT I END
 * Examples

The results of this program are the illustrations on the right side of this section. It is not just that the photograph trimmed; anything the program draws is clipped in the same manner.

This example does not work in API 28 and after, because it uses Region Operator 2. Private versions of RFO-BASIC! have new statements to cancel a clip region. </DIV> To cancel a clip region for subsequent drawing statements, a program would specify a new clip region, comprising the entire screen, with a Region Operator of Replace:

GR.SCREEN wid, ht GR.CLIP 0,0, wid-1,ht-1, 2

Examples

 * Example of game with source code