The eighth disk in the AppleIIAsm Library consists of macros and subroutines used in low-resolution graphics mode. This includes procedures for managing viewing and working pages, plotting "pixels," lines, shapes and characters, and retrieving the state of a pixel at its given coordinates.
---
## LoRes Components
The LoRes Collection contains the following components:
- A header file that includes number of hooks and vectors used for low resolution graphics, as well as a plotting routine that is used by the rest of the collection.
- A macro library that includes all of the macros used for low-resolution graphics.
- Subroutines used by the macros.
- A demonstration file that illustrates how each of the macros work.
| Purpose | Provide appropriate hooks and routines for the LoRes Collection |
| Dependencies | none |
| Bytes | 169+ |
| Notes | none |
| See Also | none |
---
*DETAILS*
The LoRes Header file includes a number of hooks and vectors used for low resolution graphics as well as a subroutine used for plotting to the screen, which is shared by the rest of the collection to function properly.
`LISTING 8.00: HEAD.LORES.ASM Heading Source`
```assembly
*``````````````````````````````*
* HOOKS.LORES *
* *
* THIS FILE INCLUDES HOODS AND *
* A FEW SUBROUTINES AND TABLES *
* USED BY THE REST OF THE LOW *
* RESOLUTION SUBROUTINES. *
* *
* AUTHOR: NATHAN RIGGS *
* CONTACT: NATHAN.RIGGS@ *
* OUTLOOK.COM *
* *
* DATE: 11-MAY-2021 *
* ASSEMBLER: MERLIN 8 PRO *
* LICENSE: APACHE 2.0 *
* OS: DOS 3.3 *
* *
* SIZE: 169 BYTES *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
TEXTOFF EQU $C050 ; TURN ON GRAPHICS MODE
TEXTON EQU $C051 ; TURN ON TEXT MODE
MIXEDOFF EQU $C052 ; SET FULLSCREEN MODE FOR GRAPHICS
MIXEDON EQU $C053 ; SET MIXED MODE FOR GRAPHICS
LORES EQU $C056 ; SOFT SWITCH FOR USING LORES GRAPHICS
HIRES EQU $C057 ; SOFT SWITCH TO SPECIFY HIRES GRAPHICS
VPG1 EQU $C054 ; SET THE VIEWING PAGE TO PAGE 1
VPG2 EQU $C055 ; SET THE VIEWING PAGE TO PAGE 2
LRGBCALC EQU $F847 ; FOR CALCULATING LORES COORDINATES
| Input | .X = X position<br/>.Y = Y position<br/>.A = Color |
| Output | none |
| Dependencies | none |
| Flags Destroyed | NZCV |
| Cycles | 168+ |
| Bytes | 109 |
| Notes | This shares the same source as the `LRPLOT` subroutine |
| See Also | `LRPLOT` |
---
*DETAILS*
The `LOCPLOT` subroutine accepts an X-coordinate, a Y-coordinate and a color code to plot a low-resolution pixel at the given coordinate and in the given color. This subroutine is used for most of the plotting subroutines and macros in the library.
`LISTING 8.01: The HEAD.LORES.ASM LOCPLOT Subroutine Source`
```assembly
*
*``````````````````````````````*
* LOCPLOT *
* *
* PLOT AT A GIVEN X,Y POINT IN *
* A GIVEN COLOR. *
* *
* INPUT *
* *
* .X = X POSITION *
* .Y = Y POSITION *
* .A = COLOR CODE *
* *
* DESTROY: NZCIDV *
* ^^^ ^ *
* *
* CYCLES: 168+ *
* SIZE: 109 BYTES *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
LOCPLOT
*
STY ]Y ; {4C3B} Y POSITION PASSED IN .Y
STX ]X ; {4C3B} X POSITION PASSED IN .X
STA ]LOCCOL ; {4C3B} COLOR PASSED IN .A
LDA ]LOCCOL ; {4C3B} TAKE THE COLOR SENT
ASL ; {2C1B} AND MOVE IT LEFT 4 BITS
ASL ; {2C1B} TO THE HIGH BYTE
ASL ; {2C1B}
ASL ; {2C1B}
CLC ; {2C1B} CLEAR CARRY
ADC ]LOCCOL ; {4C3B} NOW ADD THE LOW BYTE, MEANING
STA ]LOCCOL ; {4C3B} COLOR WILL BE REPEATING NIBBLES
LDA LWP ; {4C3B} LOAD THE WORKING PAGE FLAG
CMP #2 ; {3C2B} IF WORKING PAGE IS NOT PAGE 2,
BNE :PG1 ; {3C2B} THEN ASSUME IT'S PAGE 1.
LDA #4 ; {3C2B} ELSE, SET OFFSET FOR PAGE 2
STA ]PAGEOFF ; {4C3B} STORE IN THE PAGE OFFSET
JMP :CNT ; {3C3B} SKIP TO CONTINUE ROUTINE
:PG1
LDA #0 ; {3C2B} OTHERWISE, IT'S PAGE ONE
STA ]PAGEOFF ; {4C3B} SO THERE IS NO PAGE OFFSET
:CNT
LDA #0 ; {3C2B}
LDY #0 ; {3C2B}
LDX #0 ; {3C2B}
LDA ]Y ; {4C3B} GET Y COORDINATE
LSR ; {2C1B} SHIFT BOTTOM BIT TO CARRY
BCC :EVEN ; {3C2B} IF CARRY = 0, THEN ROW IS EVEN
LDX #$F0 ; {3C2B} OTHERWISE, IT IS ODD; SO MASK
; THE LEFT NIBBLE
BCS :LPLOT ; {3C2B} IF CARRY SET, BR TO PLOTTING
:EVEN
LDX #$0F ; {3C2B} EVEN, SO MASK LOW BYTE
:LPLOT
STX ]MASK ; {3C2B} STORE THE EVEN OR ODD MASK
ASL ; {2C1B} SHIFT CARRY BACK INTO BYTE
TAY ; {2C1B} HOLD VALUE INTO .Y
LDA LROFF,Y ; {5C3B} GET LORES MEMORY ADDRESS
CLC ; {2C1B} CLEAR THE CARRY
ADC ]X ; {4C3B} ADD THE X COORDINATE
STA GBASLO ; {4C3B} STORE LOW BYTE FOR GBASCALC
INY ; {2C1B} INCREASE Y OFFSET
LDA LROFF,Y ; {5C3B} GET LORESS MEMORY ADDRESS
ADC ]PAGEOFF ; {4C3B} ADJUST FOR PAGE AND CARRY HIGH
STA GBASHI ; {4C3B} STORE HIGH BYTE FOR GBASCALC
LDY #0 ; {3C2B}
LDA ]MASK ; {4C3B} RELOAD THE MASK
EOR #$FF ; {2C2B} EXCLUSIVE OR THE MASK
AND (GBASLO),Y ; {6C2B} AND THE LOW FOR GBAS
STA ]COLMASK ; {4C3B} STORE THE COLOR MASK
LDA ]LOCCOL ; {4C3B} LOAD THE COLOR
AND ]MASK ; {4C3B} AND THE MASK
ORA ]COLMASK ; {4C3B} OR WITH THE COLOR MASK
STA (GBASLO),Y ; {6C2B} STORE INTO GBAS LOW BYTE
RTS ; {6C1B}
*
LWP DS 1,1 ; {OC1B} BYTE TO DETERMIN WORK PAGE
*
** THE FOLLOWING TABLE HELPS WITH FASTER PLOTTING TO THE
The MAC.LORES.ASM file contains all of the macros used for manipulating low-resolution graphics. All subroutines, save for `LOCPLOT` in the collection header file, are located in their own respective files.
The `LWORKPG` macro allows the user to set which low-resolution graphics page to plot on; this is limited to page **#1** or page **#2**. If the work page is set to the same page as the viewing page (see `LVIEWPG`), then plotting will happen on screen in the order a plotting routine is called. Likewise, if the work page is different from the viewing page, the plotting will not be immediately visible; the viewing page must be switched to the same as the working page in order for the result of plotting to be seen. This can be useful for animation, or holding a static page in memory that is easily flipped to.
The `LVIEWPG` macro sets the current viewing page, either page 1 (**#1** being passed) or page 2 (**#2** being passed). The viewing page is the page that the end user sees; thus, if the working page is page 1, and the viewing page is also page 1, then the user will see plotting to the screen as it happens. In most cases, this is not an issue, as the speed of the subroutines are adequate enough to make most low-resolution operations seem nearly instantaneous. However, in cases like heavy animation, it would be better to set the working page to a different page than the viewing page, then flipping the viewing page once all of the plotting has finished on the working page. This leads to smoother animation, and the plotting is, essentially, truly instantaneous to the viewer.
| Purpose | set partial/mixed low resolution mode |
| Input | none |
| Output | none |
| Dependencies | none |
| Flags Destroyed | NZCV |
| Cycles | 12+ |
| Bytes | 9 |
| Notes | none |
| See Also | `LRGF` |
---
*DETAILS*
The `LRGF` macro sets the graphics to partial, low resolution mode (mixed mode), with columns numbering 0..39 and rows numbering 0..39. This mode allows for four lines of text at the bottom of the screen.
The `LFCLR` macro clears the screen in full screen mode, filling it with the specified color in the parameter. Note that this should only be used when the low resolution graphics mode has been set to full screen, not mixed mode. For the latter, see `LPCLR`.
The `LRGFCLR` subroutine accepts a color code passed in the .A register and fill the entire screen (or page) with that color. This should be used only when the graphics mode is set to low resolution and full screen, as set by the `LRGF` macro.
The `LPCLR` macro clears the screen in partial screen mode (mixed mode), filling it with the specified color in the parameter. Note that this should only be used when the low resolution graphics mode has been set to partial screen, not full screen. For the latter, see `LPCLR`.
| Purpose | fill the mixed mode screen with a given color |
| Input | .A = Color code |
| Output | none |
| Dependencies | none |
| Flags Destroyed | NZCV |
| Cycles | 137+ |
| Bytes | 94 |
| Notes | none |
| See Also | `LPCLR``LRGFCLR``LRGP` |
---
*DETAILS*
The `LRGPCLR`subroutine is used to clear a mixed mode, or partial, low resolution graphics page. The screen is filled with the color passed via the **.A** register except for the four text lines at the bottom of the screen, which remain untouched. This subroutine should be used only when mixed mode is in use, as initialized by the `LRGP` macro.
The `LVLIN` macro creates a vertical line from a Y-origin to a Y-destination at a given X-coordinate on the low resolution screen. When it is known that a line will be perfectly vertical, this macro should be used instead of the more cycle-expensive `LLINE` macro.
The `LRVLINE` subroutine plots a vertical line from an origin to a destination at the given column. When possible, this should be used instead of the `LLINE` macro, as this macro costs significantly fewer cycles and bytes.
The `LHLIN` macro creates a horizontal line from an X-origin to an X-destination at a given Y-coordinate on the low resolution screen. When it is known that a line will be perfectly horizonal, this macro should be used instead of the more cycle-expensive `LLINE` macro.
The `LRHLINE` subroutine plots a horizontal line from an origin to a destination at the given row. When possible, this should be used instead of the `LLINE` macro, as this macro costs significantly fewer cycles and bytes.
The `LRGET` macro retrieves the color of a low-resolution pixel at the given X,Y coordinates and returns the color code in **.A**. Currently, this only works for retrieving a value from the viewing page, but this will likely change in the future.
The `LRGETPIX` subroutine retrieves the color value from a low resolution pixel at the given X, Y coordinate, passing back the color code in the .A register. Note that this currently works only for the viewing page, but this may change in future revisions.
`LISTING 8.22: The LRGETPIX Subroutine Source`
```assembly
* LRGETPIX (NATHAN RIGGS) *
* *
* THIS SUBROUTINE RETURNS THE *
* COLOR CODE OF A GIVEN LORES *
* PIXEL AT THE X,Y COORDINATE. *
* NOTE THAT IF THE ROW IS EVEN *
* THE THE COLOR CODE IS PASSED *
* BACK VIA THE HIGH BYTE, AND *
* IF THE ROW IS ODD THEN THE *
* COLOR CODE IS PASSED IN THE *
* LOW BYTE. THE UNUSED BYTE *
* FOR EACH WILL ALWAYS BE 0. *
* *
* INPUT: *
* *
* BPAR1 = X COORDINATE *
* BPAR2 = Y COORDINATE *
* *
* DESTROY: NZCIDV *
* ^^^ ^ *
* *
* CYCLES: 90+ *
* SIZE: 58 BYTES *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
]HALFX EQU VARTAB ; X COORD / 2 FOR GBASCALC
]FULLX EQU VARTAB+1 ; ORIGINAL X COORD
]FULLY EQU VARTAB+2 ; ORIGINAL Y COORD
]MASK EQU VARTAB+3 ; MASK FOR DETERMINING COLOR CODE
]FULLCHAR EQU VARTAB+4 ; THE FULL CHAR A POS HALFX,Y
*
LRGETPIX
*
LDY BPAR1 ; {3C2B} LOAD X POSITION
STY ]FULLX ; {4C3B}
TYA ; {2C1B} TRANSFER T .A
ASL ; {2C1B} SHIFT LEFT TO DIVIDE IN HALF
STA ]HALFX ; {4C3B} STORE AS HALFX
LDA BPAR2 ; {3C2B} GET Y POSITION
STA ]FULLY ; {4C3B}
LDY ]HALFX ; {4C3B} LOAD HALF-X POSITION
LDA ]FULLY ; {4C3B} LOAD Y POSITION
JSR LRGBCALC ; {?C?B} GET CHARACTER AT COORDINATES
LDA (GBASLO),Y ; {6C2B} GET FULL CHAR FROM SCREEN ADDR
STA ]FULLCHAR ; {4C3B} AND STORE IN FULLCHAR
LDA ]FULLX ; {4C3B} LOAD THE LORES FULL X COORD
LSR ; {2C1B} SHIFT LEAST BYTE INTO CARRY
BCC :EVEN ; {3C2B} IF THAT BYTE IS 0, THEN GOTO EVEN
The `LRCHAR` subroutine plots a character to the low resolution screen at the given X,Y coordinate and color. Each character has a 4x6 aspect ratio, allowing for a total of 64 characters on a full low resolution screen (allowing for space between characters).
`LISTING 8.24: The LRCHAR Subroutine Source`
```assembly
*``````````````````````````````*
* LRCHAR (NATHAN RIGGS) *
* *
* THIS SUBROUTINE PLACES A *
* LORES CHARACTER AT A GIVEN *
* POSITION AND COLOR. ALL OF *
* THE CHARACTERS ARE 4*6 IN *
* ORDER TO ALLOW EIGHT LETTERS *
* BOTH HORIZONTALLY AND ALSO *
* VERTICALLY. *
* *
* INPUT: *
* *
* BPAR1 = X POSITION OF CHAR *
* BPAR2 = Y POSITION OF CHAR *
* WPAR1 = ADDRESS OF CHAR DEF *
* *
* DESTROY: NZCIDV *
* ^^^ ^ *
* *
* CYCLES: 397+ *
* SIZE: 409 BYTES *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
]ORGX EQU BPAR1 ; X POSITION OF CHAR
]ORGY EQU BPAR2 ; Y POSITION OF CHAR
]CADDR EQU WPAR1 ; ADDRESS OF 3-BYTE CHAR DEFINITION
]CBYTE1 EQU VARTAB ; COPY OF 1ST BYTE
]CBYTE2 EQU VARTAB+1 ; COPY OF SECOND
]CBYTE3 EQU VARTAB+2 ; COPY OF THIRD
]CX EQU ADDR1 ; PLOTTING X POSITION
]CY EQU ADDR2 ; PLOTTING Y POSITION
]CNT EQU VARTAB+5 ; COUNTER
]COLOR EQU BPAR3 ; CHARACTER COLOR
]TMPBYTE EQU VARTAB+11 ; WORKING BYTE TO READ
]OFFSET EQU VARTAB+12 ; CHARACTER BYTE OFFSET
]NIBBLE EQU VARTAB+13 ; FLAG TO INDICATE 1ST OR 2ND NIBBLE
*
LRCHAR
LDA #0 ; {4C3B} RESET NIBBLE AND OFFSET
STA ]NIBBLE ; {4C3B}
STA ]OFFSET ; {4C3B}
*
LDA ]ORGX ; {4C3B} COPY ORGX TO X TO START
STA ]CX ; {4C3B} PLOTTING CHAR FROM LEFT TOP
LDA ]ORGY ; {4C3B} DO THE SAME WITH ORGY AND Y
STA ]CY ; {4C3B}
LDA ]CX ; {4C3B}
LDY #0 ; {3C2B} RESET BYTE INDEX
LDA (]CADDR),Y ; {6C2B} GET APPROPRIATE BYTE
STA ]CBYTE1 ; {4C3B} STORE IN DEDICATED VAR
INY ; {2C1B} NOW DO SECOND BYTE
LDA (]CADDR),Y ; {6C2B}
STA ]CBYTE2 ; {4C3B}
INY ; {2C1B} AND THE THIRD
LDA (]CADDR),Y ; {6C2B}
STA ]CBYTE3 ; {4C3B}
*
LDA #0 ; {3C2B} RESET COUNTER
STA ]CNT ; {4C3B} FOR BITS
:PRELOOP
LDY ]OFFSET
*LDA ]OFFSET ; {4C3B} GET CHAR BYTE OFFSET
LDA ]CBYTE1,Y ; {5C3B} LOAD APPROPRIATE BYTE
STA ]TMPBYTE ; {4C3B} STORE IN WORKING EMORY
:LP1
SEC ; {2C1B} SET CARRY
LDA ]TMPBYTE ; {4C3B} LOAD WORKING BYTE
ASL ; {2C1B} SHIFT LEFT BYTE INTO CARRY
STA ]TMPBYTE ; {4C3B} STORE NEW WORKING BYTE
BCC :NOPLOT ; {3C2B} IF CARRY HOLDS A 0, DON'T PLOT
LDA ]COLOR ; {4C3B} OTHERWISE, PLOT
LDY ]CY ; {4C3B}
LDX ]CX ; {4C3B}
JSR LOCPLOT ; {174C112B}
:NOPLOT
INC ]CX ; {5C2B} INCREASE X, WHETHER PLOTTED
LDA ]CNT ; {4C3B} OR NOT
CMP #3 ; {3C2B} IF # OF BITS = 4, THEN
BEQ :NEXTLP ; {3C2B} WE'RE DONE WITH THIS NIBBLE
INC ]CNT ; {5C2B} INCREASE THE BIT COUNTER
JMP :LP1 ; {3C3B} LOOP AGAIN UNTIL NIBBLE DONE
:NEXTLP
INC ]NIBBLE ; {5C2B} NOW INCREASE TO 2ND NIBBLE
INC ]CY ; {5C2B} INCREASE Y PLOT POS, SINCE
LDA #0 ; {3C2B} EACH LINE IS 4 BITS LONG
STA ]CNT ; {4C3B} RESET COUNTER
LDA ]ORGX ; {4C3B} RESET X POSITION
STA ]CX ; {4C3B}
LDA ]NIBBLE ; {4C3B} CHECK IF NIBBLE 2 IS DONE
CMP #2 ; {3C2B} AND IF SO,
BEQ :NEXTLP2 ; {3C2B} GET OUT OF ANOTHER LOOP
JMP :LP1 ; {3C3B} ELSE, LOOP FOR 2ND NIBBLE
:NEXTLP2
INC ]OFFSET ; {5C2B} NOW INC CHAR BYTE OFFSET
LDA #0 ; {3C2B} RESET NIBBLE TO FIRST NIBBLE
STA ]NIBBLE ; {4C3B}
LDA ]ORGX ; {4C3B} RESET X POSITION
STA ]CX ; {4C3B}
LDA #0 ; {3C2B} RESET THE BIT COUNTER
STA ]CNT ; {4C3B}
LDA ]OFFSET ; {4C3B} IF OFFSET IS MORE THAN 2,
CMP #3 ; {3C2B} THEN DONE WITH THIS LOOP
BEQ :NEXT3 ; {3C2B} ELSE START OVER FOR NEXT BYTE
JMP :PRELOOP ; {3C3B}
*
:NEXT3
RTS ; {6C1B}
*
** WHAT FOLLOWS ARE THE BINARY REPRESENTATIONS OF EACH
** CHARACTER AVAILABLE.
*
LR_A DFB %01101001 ; {OC1B} ".XX."
; "X..X"
DFB %11111001 ; {OC1B} "XXXX"
; "X..X"
DFB %10010000 ; {0C1B} "X..X"
; "...."
LR_B
DFB %11101001 ; {0C1B} "XXX."
; "X..X"
DFB %11101001 ; {0C1B} "XXX."
; "X..X"
DFB %11100000 ; {0C1B} "XXX."
; "...."
LR_C
DFB %11111000 ; {0C1B} "XXXX"
; "X..."
DFB %10001000 ; {0C1B} "X..."
; "X..."
DFB %11110000 ; {0C1B} "XXXX"
; "...."
LR_D
DFB %11101001 ; {0C1B} "XXX."
; "X..X"
DFB %10011001 ; {0C1B} "X..X"
; "X..X"
DFB %11100000 ; {0C1B} "XXX."
; "...."
LR_E
DFB %11111000 ; {0C1B} "XXXX"
; "X..."
DFB %11101000 ; {0C1B} "XXX."
; "X..."
DFB %11110000 ; {0C1B} "XXXX"
; "...."
LR_F
DFB %11111000 ; {0C1B} "XXXX"
; "X..."
DFB %11101000 ; {0C1B} "XXX."
; "X..."
DFB %10000000 ; {0C1B} "X..."
; "...."
LR_G
DFB %11111000 ; {0C1B} "XXXX"
; "X..."
DFB %10111001 ; {0C1B} "X.XX"
; "X..X"
DFB %11110000 ; {0C1B} "XXXX"
; "...."
LR_H
DFB %10011001 ; {0C1B} "X..X"
; "X..X"
DFB %11111001 ; {0C1B} "XXXX"
; "X..X"
DFB %10010000 ; {0C1B} "X..X"
; "...."
LR_I
DFB %11110110 ; {0C1B} "XXXX"
; ".XX."
DFB %01100110 ; {0C1B} ".XX."
; ".XX."
DFB %11110000 ; {0C1B} "XXXX"
; "...."
LR_J
DFB %00010001 ; {0C1B} "...X"
; "...X"
DFB %00011001 ; {0C1B} "...X"
; "X..X"
DFB %01100000 ; {0C1B} ".XX."
; "...."
LR_K
DFB %10011010 ; {0C1B} "X..X"
; "X.X."
DFB %11001010 ; {0C1B} "XX.."
; "X.X."
DFB %10010000 ; {0C1B} "X..X"
; "...."
LR_L
DFB %10001000 ; {0C1B} "X..."
; "X..."
DFB %10001000 ; {0C1B} "X..."
; "X..."
DFB %11110000 ; {0C1B} "XXXX"
; "...."
LR_M
DFB %10111101 ; {0C1B} "X.XX"
; "XX.X"
DFB %11011001 ; {0C1B} "XX.X"
; "X..X"
DFB %10010000 ; {0C1B} "X..X"
; "...."
LR_N
DFB %10011101 ; {0C1B} "X..X"
; "XX.X"
DFB %11011011 ; {0C1B} "XX.X"
; "X.XX"
DFB %10010000 ; {0C1B} "X..X"
; "...."
LR_O
DFB %01101001 ; {0C1B} ".XX."
; "X..X"
DFB %10011001 ; {0C1B} "X..X"
; "X..X"
DFB %01100000 ; {0C1B} ".XX."
; "...."
LR_P
DFB %11101001 ; {0C1B} "XXX."
; "X..X"
DFB %11101000 ; {0C1B} "XXX."
; "X..."
DFB %10000000 ; {0C1B} "X..."
; "...."
LR_Q
DFB %01101001 ; {0C1B} ".XX."
; "X..X"
DFB %10011011 ; {0C1B} "X..X"
; "X.XX"
DFB %01100001 ; {0C1B} ".XX."
; "...X"
LR_R
DFB %11101001 ; {0C1B} "XXX."
; "X..X"
DFB %11101010 ; {0C1B} "XXX."
; "X.X."
DFB %10010000 ; {0C1B} "X..X"
; "...."
LR_S
DFB %01111000 ; {0C1B} ".XXX"
; "X..."
DFB %01100001 ; {0C1B} ".XX."
; "...X"
DFB %11100000 ; {0C1B} "XXX."
; "...."
LR_T
DFB %11110110 ; {0C1B} "XXXX"
; ".XX."
DFB %01100110 ; {0C1B} ".XX."
; ".XX."
DFB %01100000 ; {0C1B} ".XX."
; "...."
LR_U
DFB %10011001 ; {0C1B} "X..X"
; "X..X"
DFB %10011001 ; {0C1B} "X..X"
; "X..X"
DFB %11110000 ; {0C1B} "XXXX"
; "...."
LR_V
DFB %10011001 ; {0C1B} "X..X"
; "X..X"
DFB %10101010 ; {0C1B} "X.X."
; "X.X."
DFB %01000000 ; {0C1B} ".X.."
; "...."
LR_W
DFB %10011001 ; {0C1B} "X..X"
; "X..X"
DFB %10111011 ; {0C1B} "XX.X"
; "XX.X"
DFB %11010000 ; {0C1B} "X.XX"
; "...."
LR_X
DFB %10011001 ; {0C1B} "X..X"
; "X..X"
DFB %01101001 ; {0C1B} ".XX."
; "X..X"
DFB %10010000 ; {0C1B} "X..X"
; "...."
LR_Y
DFB %10011001 ; {0C1B} "X..X"
; "X..X"
DFB %01100110 ; {0C1B} ".XX."
; ".XX."
DFB %01100000 ; {0C1B} ".XX."
; "...."
LR_Z
DFB %11110001 ; {0C1B} "XXXX"
; "...X"
DFB %01101000 ; {0C1B} "..X."
; ".X.."
DFB %11110000 ; {0C1B} "XXXX"
; "...."
LR_0
DFB %11111001 ; {0C1B} "XXXX"
; "X..X"
DFB %10011001 ; {0C1B} "X..X"
; "X..X"
DFB %11110000 ; {0C1B} "XXXX"
; "...."
LR_1
DFB %01100110 ; {0C1B} ".XX."
; ".XX."
DFB %01100110 ; {0C1B} ".XX."
; ".XX."
DFB %01100000 ; {0C1B} ".XX."
; "...."
LR_2
DFB %01101001 ; {0C1B} ".XX."
; "X..X"
DFB %00100100 ; {0C1B} "..X."
; ".X.."
DFB %11110000 ; {0C1B} "XXXX"
; "...."
LR_3
DFB %11100001 ; {0C1B} "XXX."
; "...X"
DFB %01100001 ; {0C1B} ".XX."
; "...X"
DFB %11100000 ; {0C1B} "XXX."
; "...."
LR_4
DFB %10011001 ; {0C1B} "X..X"
; "X..X"
DFB %11110001 ; {0C1B} "XXXX"
; "...X"
DFB %00010000 ; {0C1B} "...X"
; "...."
LR_5
DFB %11111000 ; {0C1B} "XXXX"
; "X..."
DFB %11110001 ; {0C1B} "XXXX"
; "...X"
DFB %11110000 ; {0C1B} "XXXX"
; "...."
LR_6
DFB %01101000 ; {0C1B} ".XX."
; "X..."
DFB %11101001 ; {0C1B} "XXX."
; "X..X"
DFB %11110000 ; {0C1B} "XXXX"
; "...."
LR_7
DFB %11110001 ; {0C1B} "XXXX"
; "...X"
DFB %00100100 ; {0C1B} "..X."
; ".X.."
DFB %10000000 ; {0C1B} "X..."
; "...."
LR_8
DFB %01101001 ; {0C1B} ".XX."
; "X..X"
DFB %01101001 ; {0C1B} ".XX."
; "X..X"
DFB %01100000 ; {0C1B} ".XX."
; "...."
LR_9
DFB %01111001 ; {0C1B} ".XXX"
; "X..X"
DFB %01110001 ; {0C1B} ".XXX"
; "...X"
DFB %00010000 ; {0C1B} "...X"
; "...."
LR_EXC
DFB %01100110 ; {0C1B} ".XX."
; ".XX."
DFB %01100000 ; {0C1B} ".XX."
; "...."
DFB %01100000 ; {0C1B} ".XX."
; "...."
LR_QUEST
DFB %01101001 ; {0C1B} ".XX."
; "X..X"
DFB %00100000 ; {0C1B} "..X."
; "...."
DFB %00100000 ; {0C1B} "..X."
; "...."
LR_PRD
DFB %00000000 ; {0C1B} "...."
; "...."
DFB %00001100 ; {0C1B} "...."
; "XX.."
DFB %11000000 ; {0C1B} "XX.."
; "...."
LR_CMA
DFB %00000000 ; {0C1B} "...."
; "...."
DFB %00000100 ; {0C1B} "...."
; ".X.."
DFB %01001000 ; {0C1B} ".X.."
; "X..."
LR_APOST
DFB %00010001 ; {0C1B} "...X"
; "...X"
DFB %00100000 ; {0C1B} "..X."
; "...."
DFB %00000000 ; {0C1B} "...."
; "...."
LR_QUOT
DFB %10101010 ; {0C1B} "X.X."
; "X.X."
DFB %00000000 ; {0C1B} "...."
; "...."
DFB %00000000 ; {0C1B} "...."
; "...."
LR_COLON
DFB %00000100 ; {0C1B} "...."
; ".X.."
DFB %00000100 ; {0C1B} "...."
; ".X.."
DFB %00000000 ; {OC1B} "...."
; "...."
LR_SEMI
DFB %00000100 ; {0C1B} "...."
; ".X.."
DFB %00000100 ; {0C1B} "...."
; ".X.."
DFB %10000000 ; {0C1B} "X..."
; "...."
LR_MINUS
DFB %00000000 ; {0C1B} "...."
; "...."
DFB %11111111 ; {0C1B} "XXXX"
; "XXXX"
DFB %00000000 ; {0C1B} "...."
; "...."
LR_PLUS
DFB %00000110 ; {0C1B} "...."
; ".XX."
DFB %11111111 ; {0C1B} "XXXX"
; "XXXX"
DFB %01100000 ; {0C1B} ".XX."
; "...."
LR_EQUAL
DFB %00001111 ; {0C1B} "...."
; "XXXX"
DFB %00001111 ; {0C1B} "...."
; "XXXX"
DFB %00000000 ; {0C1B} "...."
; "...."
LR_FSLASH
DFB %00010010 ; {0C1B} "...X"
; "..X."
DFB %00100100 ; {0C1B} "..X."
; ".X.."
DFB %01001000 ; {0C1B} ".X.."
; "X..."
LR_BSLASH
DFB %10000100 ; {0C1B} "X..."
; ".X.."
DFB %01000010 ; {0C1B} ".X.."
; "..X."
DFB %00100001 ; {0C1B} "..X."
; "...X"
LR_LPAR
DFB %00010010 ; {0C1B} "...X"
; "..X."
DFB %01000100 ; {0C1B} ".X.."
; ".X.."
DFB %00100001 ; {0C1B} "..X."
; "...X"
LR_RPAR
DFB %10000100 ; {0C1B} "X..."
; ".X.."
DFB %00100010 ; {0C1B} "..X."
; "..X."
DFB %01001000 ; {0C1B} ".X.."
; "X..."
```
---
## LoRes Collection Demo
Listing 8.25 contains demonstrations of how the low resolution macro collection works.
`LISTING 8.25: The DEMO.LORES.ASM Source`
```assembly
*
*``````````````````````````````*
* DEMO.LORES *
* *
* A DEMO OF THE MACROS AND *
* SUBROUTINES FOR USING LORES *
* GRAPHICS. *
* *
* AUTHOR: NATHAN RIGGS *
* CONTACT: NATHAN.RIGGS@ *
* OUTLOOK.COM *
* *
* DATE: 03-OCT-2019 *
* ASSEMBLER: MERLIN 8 PRO *
* OS: DOS 3.3 *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
** ASSEMBLER DIRECTIVES
*
CYC AVE
EXP OFF
TR ON
DSK DEMO.LORES
OBJ $BFE0
ORG $6000
*
*``````````````````````````````*
* TOP INCLUDES (PUTS, MACROS) *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
PUT MIN.HEAD.REQUIRED.ASM
PUT MIN.HEAD.LORES.ASM
USE MIN.MAC.REQUIRED.ASM
USE MIN.MAC.LORES.ASM
*
*``````````````````````````````*
* PROGRAM MAIN BODY *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
]COLOR EQU VARTAB+16
]HOME EQU $FC58
*
*``````````````````````````````*
* LO-RES GRAPHICS COLLECTION *
*,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,*
*
** THIS DEMO ILLUSTRATES HOW TO USE THE MACROS DEDICATED
** TO CREATING LOW RESOLUTION GRAPHICS. THESE MACROS
** LARGELY CONSIST OF THE MOST BASIC FUNCTIONS NECESSARY
** TO BUILD MORE COMPLICATED ROUTINES, SUCH AS ANIMATION,
** SPRITES, AND SO ON. CURRENTLY, THE MACROS AVAILABLE ARE: