Thornton 2 Library of Scraps
1K4AS

GEOS Graphics

Ariel's GEOS Programmer's Reference Guide
Back: Preface Up: Contents Next: GEOS Kernal Routines
GEOS Development
Back: GEOS Development Up: GEOS Development Next: GEOS: Environment

This page is still a work in progress.

Table of Contents

Graphics Overview

The most obvious programming feature is graphics. GEOS uses bitmap graphics modes and provides a number of graphics routines to access the screen in a standardized platform-independent way.

However, GEOS treats the screen as a monochrome bitmap and has no routines for colors. The default color theme is black pixels on a white background or dark grey pixels on a light grey background.

The Virtual Screens

GEOS uses two virtual screens, one foreground and one background, for display buffering. The foreground screen is fed as directly as possible to the display hardware. The GEOS Kernal uses the background screen as a buffer for overwriting the foreground screen with temporary GUI controls such as menus and dialog boxes. Virtually all of the GEOS graphics routines let you draw and erase on either screen, and there are routines for imprinting parts of the foreground onto the background and for recovering parts of the background onto the foreground.

GEOS uses a left-handed Cartesian coordinate system for pixels: The horizontal axis, X, increases one pixel at a time to the right; the vertical axis, Y, increases one pixel at a time downward; and the origin coordinate, (0,0), is the pixel in the upper-left corner of the screen.

For patterns, bitmap images, and bitmap compression, GEOS treats the screen as a linear bitmap: Each byte is a row of 8 pixels side-by-side, and each byte is lined up side-by-side, filling a single row one pixel high before starting the next row of pixels. When pixels need to be set within a byte, the high bit (7) is the left-most pixel of the 8, and the low bit (0) is the right-most pixel of the 8.

The GEOS Kernal takes care of translating this simple coordinate system to the different and not-so-straightforward layouts of graphics memory on each platform.

Display Buffering and dispBufferOn

GEOS uses the variable dispBufferOn to determine whether your program draws on the foreground screen, the background screen, or both.

The Screen Bounds

GEOS does not do bounds checking with screen coordinates; your programs must do that themselves. If you feed the GEOS Kernal screen coordinates outside the limits, then the results will be unpredictable and could result in program code corruption similar to stack, heap, and buffer overflows.

The maximum number of pixels in each dimension depends on the platform and GEOS mode. The geosSym file in geoProgrammer provides the constants SC_PIX_WIDTH and SC_PIX_HEIGHT to make bounds-checking platform-agnostic. The screen dimensions in GEOS (and the values of SC_PIX_WIDTH and SC_PIX_HEIGHT respectively) are:

The four corners of the screen are:

Note that the highest addressable pixel coordinate is one less than the number of pixels in that dimension. For example, if the screen is 320 pixels wide, then the right-most X coordinate is 319.

Coordinates Are Inclusive

Every GEOS graphics routine includes the coordinates of each endpoint within the object it draws. Line routines draw both of the pixels given, not just the pixels in between, and Rectangle routines draw vertical lines through pixels at both X coordinates and horizontal lines through pixels at both Y coordinates.

Cards As Screen Subdivisions

Some GEOS Kernal routines divide the screen into 8x8 regions called cards. These are identical in size and structure to character cells and 8-byte graphics regions in Commodore 64 graphics and character memory.

The 40-column Commodore screen is 40 cards to a row and 25 card rows high, the 80-column Commodore screen is 80 cards to a row and 25 card rows high, and the Apple II screen is 70 cards to a row and 24 card rows high.

Cards are always aligned to 8-pixel boundaries. Card width, card height, and card position are also units some routines use. Converting pixel coordinates to card coordinates is a simple matter of dividing by 8 and rounding down, or three logical shifts right. Converting pixel widths and heights to card widths and heights is the same but rounding up, or three logical shifts right and adding 1.

The Hitchhiker's Guide to GEOS offers the following code snippet as an example of pixel to card conversion:

************************************************************************
;MseToCardPos:
;converts current mouse positions to card positions
;
;Pass:        nothing
;
;Uses:        MouseXPos, MouseYPos
;
;Returns:     r0L    mouse card x-position (byte)
;             r0H    mouse card y-position (byte)
;
;Destroys:    a,x,y
;                                                              (mgl)
************************************************************************
MseToCardPos:
       php                   ; save current interrupt disable status
       sei                   ; disable IRQs so mouseXPos doesn't change
       MoveW  MouseXPos,r0   ; copy mouse x-position to zp work reg (ro)
       plp                   ; reset interrupt status asap.
       ldx    #r0            ; divide x-position (r0) by 8
       ldy    #3             ; (shift right 3 times)
       jsr    DShiftRight    ; this gives us the card x-position in r0L
       lda    MouseYPos      ; get mouse y-position
       lsr    a              ; and shift right 3 times
       lsr    a              ; which is a divide by 8
       lsr    a              ; and gives us the card y-position in a
       sta    r0H            ; set down card y-position
       rts                   ; exit

geoProgrammer 128 Notes

The geosSym file in geoProgrammer 128 also provides width and height maximums specific to each screen mode in GEOS 128: SC_40_WIDTH and SC_40_HEIGHT for 40-column mode, and SC_80_WIDTH and SC_80_HEIGHT for 80-column mode.

In geoProgrammer 128, the actual values of SC_PIX_WIDTH and SC_PIX_HEIGHT depend on the values of the C64 and C128 constants.

If C64=$00 and C128=$01, indicating that your program is designed to run only on GEOS 128, then the constants have the 80-column values.

If C64=$01 and C128=$01, indicating that your program is designed to run on both GEOS and GEOS 128, then the constants have the 40-column values.

Detect GEOS 128

The Hitchhiker's Guide to GEOS offers the following code snippets to detect whether your program is running on GEOS or GEOS 128:

.if (0)
************************************************************************
Check128:
       Check for GEOS 128.

Pass:
       nothing

Returns:
       st     minus flag set if running under GEOS 128.

Example usage:

       jsr    Check128
       bpl    10$          ;ignore if under GEOS 64
       jsr    DoDoubling   ;else, patch x-coordinates with doubling bits
10$:

************************************************************************
.endif

Check128:
       lda    #$12         ; c128Flag not guaranteed to be valid in
                           ; versions 1.2 and lower
       cmp    version      ; first see if version <= 1.2
       bpl    10$          ; if so, branch and say C64. Note this is a
                           ; signed comparison. (it WILL NOT work if
                           ; GEOS goes beyond version $7f!)
       lda    c128Flag     ; else set minus based on high bit c128Flag
10$:
       rts

It also says you can check graphMode to determine whether GEOS 128 is in 40-column or 80-column mode:

       bit    graphMode    ; check 40/80 mode bits
       bpl    C64Mode      ; branch if in 40-column mode
                           ; else, handle as 80-column...

40-Column X-Axis Doubling in 80-Column Mode

The GEOS Kernal in GEOS 128 provides the routine NormalizeX to automatically double X-coordinate values so that your program can have the same aspect ratio in 80-column mode as in 40-column mode. GEOS graphics routines use it automatically, but it helps explain how GEOS handles 40-column graphics in 80-column mode.