The story so far...
We've finally developed a routine which plots anywhere on the DHR screen in any colour. Unfortunately plotting single dots does not a game make. The next logical step is to explore the world of vector graphics by learning to draw lines.
But first a word about code management...
Most developers will, to a point re-use their code. Often repurposing snippets, functions or whole programs from project to project. There is an adage in software development which is well known if not well agreed upon: "old code is good code". The idea being that something that has been used and reused has stood the test of time.
Code reuse is even more important to the machine language programmer as it often takes a lot of work to get a routine which accomplishes very little. For example, we just spent seven blog posts to draw a single dot on the screen! Because of this, assembly programmers often keep a library of short, tightly coded routines called macros which they can drop into any program.
Most assemblers have some kind of code reuse features baked-in. Today were going to discuss just one for the Merlin Pro assembler: the PUT command. Check this out:
LDX #$0A
LDY #$0A
PUT PLOT.ROUTINE
RTS
All this does is tell the assembler to find a file on the local disk called PLOT.ROUTINE and insert the source code from it into our code. Just as if someone had typed it in between line 02 and line 04. For even a novice programmer this can be pretty powerful.
To start we are going to break our program up into four pieces:
Filename | Line # Range | Description |
DH.INIT | 03-18 | DHR Initialization code, variables used by other DH modules. |
DH.PLOT | 23-40 | DHR Plot routine, requires DH.INIT and DH.TABLES |
DH.COLOUR | 43-50 | Set DHR Plot colour, requires DH.PLOT |
DH.TABLES | 52-277 | DHR Table data |
If you're using Merlin Pro then all you need to do is create a new file in the editor (Hit "E" from the main menu and then type "NEW" to clear out any old code), paste in the code snippet and save it with the appropriate name.
Note, that you do not need to assemble it! In the interests of increasing our ability to use this code in later projects we will need to make a few changes to the labels as well. Below are the files we will be using and some commentary on our changes:
*DH.INIT
*DHR Initialization code, variables used by other DH modules.
*Jonathan Graham/Battlestations
*Free for non-commercial use with attribution
*
GRAPHON EQU $C050
HIRESON EQU $C057
FULLON EQU $C052
DHRON EQU $C05E
ON80STOR EQU $C001
ON80COL EQU $C00D
PAGE1 EQU $C054
PAGE2 EQU $C055
SCRN_LO EQU $1D ;Zero page location for low byte of our screen row
SCRN_HI EQU $1E ;Zero page location for high byte of our screen row
INIT STA GRAPHON ;Turn on graphics
STA HIRESON ;Turn on hi-res mode
STA FULLON ;Turn on fullscreen mode
STA DHRON ;Turn on Double hi-res
STA ON80COL ;Turn on 80 Column mode
STA ON80STOR ;Use PAGE1/PAGE2 to switch between MAIN and AUX memory
No real changes here. I'll point out that some people might decide to put the SCRN_LO/SCRN_HI variables into the next file. This is kind of a personal taste thing. On one hand it encapsulates the variables related to the plot routine in the same source file. On the other hand if you PUT DH.PLOT file multiple times in the same source file you'll get an error.
Another approach is to keep all the variables in the main source file. This approach means you need to remember to create two variables SCRN_LO/SCRN_HI pointing to two consecutive zero page locations whenever you PUT DH.PLOT. A good way to do that is to document the dependency in the source file. However in this case we've put them together in a single file because we just want those lines out of the way so we can concentrate on other things.
*DH.PLOT
*DHR plotting routine, requires DH.INIT and DH.TABLES.
*Jonathan Graham/Battlestations
*Free for non-commercial use with attribution
*
LDA HTAB_LO,Y ;Find the low byte of the row address
STA SCRN_LO
LDA HTAB_HI,Y ;Find the high byte of the row address
STA SCRN_HI
LDY MBOFFSET,X ;Find what byte if any in MAIN we are working in
BMI :AUX ;If pixel has no bits in MAIN memory - go to aux routine
STA PAGE1 ;Map $2000 to MAIN memory
LDA (SCRN_LO),Y ;Load screen data
AND MAINAND,X ;Erase pixel bits
]ORMAIN ORA MAINGR,X ;Draw coloured bits
STA (SCRN_LO),Y ;Write back to screen
:AUX LDY ABOFFSET,X ;Find what byte if any in AUX we are working in
BMI :END ;If no part of the pixel is in AUX - end the program
STA PAGE2 ;Map $2000 to AUX memory
LDA (SCRN_LO),Y ;Load screen data
AND AUXAND,X ;Erase pixel bits
]ORAUX ORA AUXGR,X ;Draw coloured bits
STA (SCRN_LO),Y ;Write back to screen
:END
The only differences here are that we've removed the RTS and added an empty label called :END. The assembler will assign this to whatever memory location is next in whatever source file this macro is PUT into. We also removed the DPLOT label since if we were to PUT this file multiple times in a program we would get an error due to a duplicate label name.
This is the same reason we changed the ORMAIN/ORAUX labels to have a square bracket in front. The ']' character turns those labels into a variable, each time a ]LABEL appears in the first column the assembler will assign it the next memory location. Subsequent references to it will be translated into the assigned address until the same ]LABEL is used again in the first column. At which point the ]LABEL takes on the current memory location and any subsequent reference will now point to this spot, and so on... The upshot is that we can now PUT DH.PLOT multiple times in a file without worry of generating an error.
*DH.COLOUR
*Sets colour for DH.PLOT routine. Requires DH.PLOT.
*Jonathan Graham/Battlestations
*Free for non-commercial use with attribution
*
LDA CLOM,Y ;Lookup low byte of MAIN memory colour table
STA ]ORMAIN+1 ;Update the ORA instruction
LDA CHIM,Y ;Lookup high byte of MAIN memory colour table
STA ]ORMAIN+2 ;Update the ORA instruction
LDA CLOA,Y ;Lookup low byte of AUX memory colour table
STA ]ORAUX+1 ;Update the ORA instruction
LDA CHIA,Y ;Lookup high byte of AUX memory colour table
STA ]ORAUX+2 ;Update the ORA instruction
Again we've removed the RTS and the initial SETDCOLOR label. We also changed the labels for ORMAIN/ORAUX to match our changes in DH.PLOT.
*DH.TABLES
*Tables for all the DH routines
*Jonathan Graham/Battlestations
*Free for non-commercial use with attribution
*
MBOFFSET DB 255,0,0,0,255,1,1,255,2,2,2,255,3,3
DB 255,4,4,4,255,5,5,255,6,6,6,255,7,7
DB 255,8,8,8,255,9,9,255,10,10,10,255,11,11
DB 255,12,12,12,255,13,13,255,14,14,14,255,15,15
DB 255,16,16,16,255,17,17,255,18,18,18,255,19,19
DB 255,20,20,20,255,21,21,255,22,22,22,255,23,23
DB 255,24,24,24,255,25,25,255,26,26,26,255,27,27
DB 255,28,28,28,255,29,29,255,30,30,30,255,31,31
DB 255,32,32,32,255,33,33,255,34,34,34,255,35,35
DB 255,36,36,36,255,37,37,255,38,38,38,255,39,39
ABOFFSET DB 0,0,255,1,1,1,255,2,2,255,3,3,3,255
DB 4,4,255,5,5,5,255,6,6,255,7,7,7,255
DB 8,8,255,9,9,9,255,10,10,255,11,11,11,255
DB 12,12,255,13,13,13,255,14,14,255,15,15,15,255
DB 16,16,255,17,17,17,255,18,18,255,19,19,19,255
DB 20,20,255,21,21,21,255,22,22,255,23,23,23,255
DB 24,24,255,25,25,25,255,26,26,255,27,27,27,255
DB 28,28,255,29,29,29,255,30,30,255,31,31,31,255
DB 32,32,255,33,33,33,255,34,34,255,35,35,35,255
DB 36,36,244,37,37,37,255,38,38,255,39,39,39,255
MAINAND
LUP 20
DB %01111111,%01111110,%01100001,%00011111
DB %01111111,%01111000,%00000111
--^
AUXAND
LUP 20
DB %01110000,%00001111,%01111111,%01111100
DB %01000011,%00111111,%01111111
--^
MAINBL
LUP 20
DB %00000000,%00000000,%00000000,%00000000
DB %00000000,%00000000,%00000000
--^
AUXBL
LUP 20
DB %00000000,%00000000,%00000000,%00000000
DB %00000000,%00000000,%00000000
--^
MAINMG
LUP 20
DB %00000000,%00000001,%00010000,%00000000
DB %00000000,%00000100,%01000000
--^
AUXMG
LUP 20
DB %00001000,%00000000,%00000000,%00000010
DB %00100000,%00000000,%00000000
--^
MAINBR
LUP 20
DB %00000000,%00000000,%00001000,%00000000
DB %00000000,%00000010,%00100000
--^
AUXBR
LUP 20
DB %00000100,%01000000,%00000000,%00000001
DB %00010000,%00000000,%00000000
--^
MAINOR
LUP 20
DB %00000000,%00000001,%00011000,%00000000
DB %00000000,%00000110,%01100000
--^
AUXOR
LUP 20
DB %00001100,%01000000,%00000000,%00000011
DB %00110000,%00000000,%00000000
--^
MAINDG
LUP 20
DB %00000000,%00000000,%00000100,%01000000
DB %00000000,%00000001,%00010000
--^
AUXDG
LUP 20
DB %00000010,%00100000,%00000000,%00000000
DB %00001000,%00000000,%00000000
--^
MAING1
LUP 20
DB %00000000,%00000001,%00010100,%01000000
DB %00000000,%00000101,%01010000
--^
AUXG1
LUP 20
DB %00001010,%00100000,%00000000,%00000010
DB %00101000,%00000000,%00000000
--^
MAINGR
LUP 20
DB %00000000,%00000000,%00001100,%01000000
DB %00000000,%00000011,%00110000
--^
AUXGR
LUP 20
DB %00000110,%01100000,%00000000,%000000001
DB %00011000,%00000000,%00000000
--^
MAINYE
LUP 20
DB %00000000,%00000001,%00011100,%01000000
DB %00000000,%00000111,%01110000
--^
AUXYE
LUP 20
DB %00001110,%01100000,%00000000,%00000011
DB %00111000,%00000000,%00000000
--^
MAINDB
LUP 20
DB %00000000,%00000000,%00000010,%00100000
DB %00000000,%00000000,%00001000
--^
AUXDB
LUP 20
DB %00000001,%00010000,%00000000,%00000000
DB %00000100,%01000000,%00000000
--^
MAINVI
LUP 20
DB %00000000,%00000001,%00010010,%00100000
DB %00000000,%00000100,%01001000
--^
AUXVI
LUP 20
DB %00001001,%00010000,%00000000,%00000010
DB %00100100,%01000000,%00000000
--^
MAING2
LUP 20
DB %00000000,%00000000,%00001010,%00100000
DB %00000000,%00000010,%00101000
--^
AUXG2
LUP 20
DB %00000101,%01010000,%00000000,%00000001
DB %00010100,%01000000,%00000000
--^
MAINPI
LUP 20
DB %00000000,%00000001,%00011010,%00100000
DB %00000000,%00000110,%01101000
--^
AUXPI
LUP 20
DB %00001101,%01010000,%00000000,%00000011
DB %00110100,%01000000,%00000000
--^
MAINMB
LUP 20
DB %00000000,%00000000,%00000110,%01100000
DB %00000000,%00000001,%00011000
--^
AUXMB
LUP 20
DB %00000011,%00110000,%00000000,%00000000
DB %00001100,%01000000,%00000000
--^
MAINLB
LUP 20
DB %00000000,%00000001,%00010110,%01100000
DB %00000000,%00000101,%01011000
--^
AUXLB
LUP 20
DB %00001011,%00110000,%00000000,%00000010
DB %00101100,%01000000,%00000000
--^
MAINAQ
LUP 20
DB %00000000,%00000000,%00001110,%01100000
DB %00000000,%00000011,%00111000
--^
AUXAQ
LUP 20
DB %00000111,%01110000,%00000000,%00000001
DB %00011100,%01000000,%00000000
--^
MAINWI
LUP 20
DB %00000000,%00000001,%00011110,%01100000
DB %00000000,%00000111,%01111000
--^
AUXWI
LUP 20
DB %00001111,%01110000,%00000000,%00000011
DB %00111100,%01000000,%00000000
--^
CLOM DB <MAINBL,<MAINMG,<MAINBR,<MAINOR,<MAINDG
DB <MAING1,<MAINGR,<MAINYE,<MAINDB,<MAINVI
DB <MAING2,<MAINPI,<MAINMB,<MAINLB,<MAINAQ,<MAINWI
CHIM DB >MAINBL,>MAINMG,>MAINBR,>MAINOR,>MAINDG,>MAING1
DB >MAINGR,>MAINYE,>MAINDB,>MAINVI,>MAING2,>MAINPI
DB >MAINMB,>MAINLB,>MAINAQ,>MAINWI
CLOA DB <AUXBL,<AUXMG,<AUXBR,<AUXOR,<AUXDG
DB <AUXG1,<AUXGR,<AUXYE,<AUXDB,<AUXVI
DB <AUXG2,<AUXPI,<AUXMB,<AUXLB,<AUXAQ,<AUXWI
CHIA DB >AUXBL,>AUXMG,>AUXBR,>AUXOR,>AUXDG,>AUXG1
DB >AUXGR,>AUXYE,>AUXDB,>AUXVI,>AUXG2,>AUXPI
DB >AUXMB,>AUXLB,>AUXAQ,>AUXWI
HTAB_LO
LUP 4
DB $00,$00,$00,$00,$00,$00,$00,$00
DB $80,$80,$80,$80,$80,$80,$80,$80
--^
LUP 4
DB $28,$28,$28,$28,$28,$28,$28,$28
DB $A8,$A8,$A8,$A8,$A8,$A8,$A8,$A8
--^
LUP 4
DB $50,$50,$50,$50,$50,$50,$50,$50
DB $D0,$D0,$D0,$D0,$D0,$D0,$D0,$D0
--^
HTAB_HI
LUP 3
DB $20,$24,$28,$2C,$30,$34,$38,$3C
DB $20,$24,$28,$2C,$30,$34,$38,$3C
DB $21,$25,$29,$2D,$31,$35,$39,$3D
DB $21,$25,$29,$2D,$31,$35,$39,$3D
DB $22,$26,$2A,$2E,$32,$36,$3A,$3E
DB $22,$26,$2A,$2E,$32,$36,$3A,$3E
DB $23,$27,$2B,$2F,$33,$37,$3B,$3F
DB $23,$27,$2B,$2F,$33,$37,$3B,$3F
--^
...and since these are just data tables there are no changes here at all.
Subroutines vs. Macros:
When writing in higher level languages the most common way of reusing code is to have a separate function or subroutine. In lower level languages like C you will see both subroutines and some macro use, particularly in performance oriented code. In assembler, as you'll soon see macros are pretty pervasive. Is there a reason for this? Or is it just tradition? To explain, consider the following code:
*DEMO 0
*Use DH.PLOT to fill the screen cycling through all the colours
*Jonathan Graham/Battlestations
*Free for non-commercial use with attribution
*
XC ;Required for Merlin Pro to use 65C02 instructions
ORG $6000 ;Start assembling at memory location $6000
PUT DH.INIT ;Get everything ready for DHR
LDA #$00 ;Colour code for white
NEWCOLOR JSR SETDCOLOR
LDY #$00 ;Set Y co-ordinate to 0
NXTROW LDX #$00 ;Set X co-ordinate to 0
NXTCOL PHY ; Preseve the Y register - as DPLOT destroys it
JSR DPLOT ;Plot the point
PLY
INX
CPX #$8C
BNE NXTCOL
INY
CPY #$C0
BNE NXTROW
LDA NEWCOLOR-1
INC
AND #001111
STA NEWCOLOR-1
BRA NEWCOLOR
DPLOT PUT DH.PLOT ;Adding a label as we removed the one from the file
RTS ;Add an RTS so we can use this as a subroutine
SETDCOLOR TAY ;Adding a label as we removed the one from the file
PUT DH.COLOUR
RTS ;Add an RTS so we can use this as a subroutine
PUT DH.TABLES
If you compile this yourself and benchmark it. You should see that it draws a full screen in about 2.28 seconds (about 0.44 FPS). One of the most obvious performance issues is that every time we want to draw a pixel we have to JSR to our subroutine. The JSR costs us 12 cycles per pixel! ( Six for the JSR and another six for the RTS). Considering that the whole DPLOT routine takes 54-100 cycles. This approach represents a significant performance hit (30%!).
There is however, an easy solution:
*DEMO 1
*Use DH.PLOT to fill the screen cycling through all the colours
*Jonathan Graham/Battlestations
*Free for non-commercial use with attribution
*
XC ;Required for Merlin Pro to use 65C02 instructions
ORG $6000 ;Start assembling at memory location $6000
PUT DH.INIT ;Get everything ready for DHR
LDA #$00 ;Colour code for white
NEWCOLOR JSR SETDCOLOR
LDY #00 ;Set Y co-ordinate to 0
NXTROW LDX #$00 ;Set X co-ordinate to 0
NXTCOL PHY ; Preseve the Y register - as DPLOT destroys it
PUT DH.PLOT ;DPLOT routine is now inlined
PLY
INX
CPX #$8C
BNE NXTCOL
INY
CPY #$C0
BNE NXTROW
LDA NEWCOLOR-1
INC
AND #001111
STA NEWCOLOR-1
BRA NEWCOLOR
SETDCOLOR TAY ;Assume the desired colour is in the accumulator
PUT DH.COLOUR
RTS ;Add an RTS so we can use this as a subroutine
PUT DH.TABLES
This simple change drops us down to 1.965 seconds per screen (just over 0.5 FPS) on a 1Mhz machine. This kind of optimization is known as inlining and is one of the reasons that macros are so important to assembly language programming as they make inlining easy. An added bonus is that using drop-in code segments makes your source much easier to read.
There's one more easy optimization which we can get by splitting our code up further. If you take a look at the first few lines of the DPLOT routine you will see that we look up the horizontal address and store it in ZP locations before we plot our points. Recall that our program is drawing each line horizontally. Which means it really only has to do this lookup once every
line instead of once every pixel. We are effectively we doing this 139x times more than necessary. There are a number of solutions to this but the easiest is to simply split this lookup into it's own macro file. We will call it DH.ROWSET, as long as we remember to call it each time our Y coordinate changes we will improve our performance considerably.
DH.ROWSET would look like this:
*DH.ROWSET
*Perform the horizontal co-ordinate lookup. Requires DH.TABLES.
*Jonathan Graham/Battlestations
*Free for non-commercial with attribution
LDA HTAB_LO,Y ;Find the low byte of the row address
STA SCRN_LO
LDA HTAB_HI,Y ;Find the high byte of the row address
STA SCRN_HI
and our new DH.PLOT would look like this:
*DH.PLOT
*DHR plotting routine, requires DH.INIT and DH.TABLES.
*Jonathan Graham/Battlestations
*Free for non-commercial use with attribution
*
LDY MBOFFSET,X ;Find what byte if any in MAIN we are working in
BMI :AUX ;If pixel has no bits in MAIN memory - go to aux routine
STA PAGE1 ;Map $2000 to MAIN memory
LDA (SCRN_LO),Y ;Load screen data
AND MAINAND,X ;Erase pixel bits
]ORMAIN ORA MAINGR,X ;Draw coloured bits
STA (SCRN_LO),Y ;Write back to screen
:AUX LDY ABOFFSET,X ;Find what byte if any in AUX we are working in
BMI :END ;If no part of the pixel is in AUX - end the program
STA PAGE2 ;Map $2000 to AUX memory
LDA (SCRN_LO),Y ;Load screen data
AND AUXAND,X ;Erase pixel bits
]ORAUX ORA AUXGR,X ;Draw coloured bits
STA (SCRN_LO),Y ;Write back to screen
:END
And our new demo looks like this:
*DEMO 2
*Use DH.PLOT to fill the screen cycling through all the colours
*Jonathan Graham/Battlestations
*Free for non-commercial use with attribution
*
XC ;Required for Merlin Pro to use 65C02 instructions
ORG $6000 ;Start assembling at memory location $6000
PUT DH.INIT ;Get everything ready for DHR
LDA #$00 ;Colour code for white
NEWCOLOR JSR SETDCOLOR
LDY #00 ;Set Y co-ordinate to 0
NXTROW LDX #$00 ;Set X co-ordinate to 0
PUT DH.ROWSET
NXTCOL PHY ; Preseve the Y register - as DPLOT destroys it
PUT DH.PLOT ;DPLOT routine is now inlined
PLY
INX
CPX #$8C
BNE NXTCOL
INY
CPY #$C0
BNE NXTROW
LDA NEWCOLOR-1
INC
AND #001111
STA NEWCOLOR-1
BRA NEWCOLOR
SETDCOLOR TAY ;Assume the desired colour is in the accumulator
PUT DH.COLOUR
RTS ;Add an RTS so we can use this as a subroutine
PUT DH.TABLES
Here's a binary form for you:
CALL -151
6000: 8d 50 c0 8d 57 c0 8d 52 c0 8d 5e c0 8d 0d c0 8d
6010: 01 c0 a9 00 20 60 60 a0 00 a2 00 b9 6a 74 85 1d
6020: b9 2a 75 85 1e 5a bc 7a 60 30 0d 8d 54 c0 b1 1d
6030: 3d 92 61 1d 3a 69 91 1d bc 06 61 30 0d 8d 55 c0
6040: b1 1d 3d 1e 62 1d c6 69 91 1d 7a e8 e0 8c d0 d5
6050: c8 c0 c0 d0 c4 ad 13 60 1a 29 0f 8d 13 60 80 b4
6060: a8 b9 2a 74 8d 34 60 b9 3a 74 8d 35 60 b9 4a 74
6070: 8d 46 60 b9 5a 74 8d 47 60 60 ff 00 00 00 ff 01
6080: 01 ff 02 02 02 ff 03 03 ff 04 04 04 ff 05 05 ff
6090: 06 06 06 ff 07 07 ff 08 08 08 ff 09 09 ff 0a 0a
60a0: 0a ff 0b 0b ff 0c 0c 0c ff 0d 0d ff 0e 0e 0e ff
60b0: 0f 0f ff 10 10 10 ff 11 11 ff 12 12 12 ff 13 13
60c0: ff 14 14 14 ff 15 15 ff 16 16 16 ff 17 17 ff 18
60d0: 18 18 ff 19 19 ff 1a 1a 1a ff 1b 1b ff 1c 1c 1c
60e0: ff 1d 1d ff 1e 1e 1e ff 1f 1f ff 20 20 20 ff 21
60f0: 21 ff 22 22 22 ff 23 23 ff 24 24 24 ff 25 25 ff
6100: 26 26 26 ff 27 27 00 00 ff 01 01 01 ff 02 02 ff
6110: 03 03 03 ff 04 04 ff 05 05 05 ff 06 06 ff 07 07
6120: 07 ff 08 08 ff 09 09 09 ff 0a 0a ff 0b 0b 0b ff
6130: 0c 0c ff 0d 0d 0d ff 0e 0e ff 0f 0f 0f ff 10 10
6140: ff 11 11 11 ff 12 12 ff 13 13 13 ff 14 14 ff 15
6150: 15 15 ff 16 16 ff 17 17 17 ff 18 18 ff 19 19 19
6160: ff 1a 1a ff 1b 1b 1b ff 1c 1c ff 1d 1d 1d ff 1e
6170: 1e ff 1f 1f 1f ff 20 20 ff 21 21 21 ff 22 22 ff
6180: 23 23 23 ff 24 24 f4 25 25 25 ff 26 26 ff 27 27
6190: 27 ff 7f 7e 61 1f 7f 78 07 7f 7e 61 1f 7f 78 07
61a0: 7f 7e 61 1f 7f 78 07 7f 7e 61 1f 7f 78 07 7f 7e
61b0: 61 1f 7f 78 07 7f 7e 61 1f 7f 78 07 7f 7e 61 1f
61c0: 7f 78 07 7f 7e 61 1f 7f 78 07 7f 7e 61 1f 7f 78
61d0: 07 7f 7e 61 1f 7f 78 07 7f 7e 61 1f 7f 78 07 7f
61e0: 7e 61 1f 7f 78 07 7f 7e 61 1f 7f 78 07 7f 7e 61
61f0: 1f 7f 78 07 7f 7e 61 1f 7f 78 07 7f 7e 61 1f 7f
6200: 78 07 7f 7e 61 1f 7f 78 07 7f 7e 61 1f 7f 78 07
6210: 7f 7e 61 1f 7f 78 07 7f 7e 61 1f 7f 78 07 70 0f
6220: 7f 7c 43 3f 7f 70 0f 7f 7c 43 3f 7f 70 0f 7f 7c
6230: 43 3f 7f 70 0f 7f 7c 43 3f 7f 70 0f 7f 7c 43 3f
6240: 7f 70 0f 7f 7c 43 3f 7f 70 0f 7f 7c 43 3f 7f 70
6250: 0f 7f 7c 43 3f 7f 70 0f 7f 7c 43 3f 7f 70 0f 7f
6260: 7c 43 3f 7f 70 0f 7f 7c 43 3f 7f 70 0f 7f 7c 43
6270: 3f 7f 70 0f 7f 7c 43 3f 7f 70 0f 7f 7c 43 3f 7f
6280: 70 0f 7f 7c 43 3f 7f 70 0f 7f 7c 43 3f 7f 70 0f
6290: 7f 7c 43 3f 7f 70 0f 7f 7c 43 3f 7f 70 0f 7f 7c
62a0: 43 3f 7f 70 0f 7f 7c 43 3f 7f 00 00 00 00 00 00
62b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
62c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
62d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
62e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
62f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
6300: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
6310: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
6320: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
6330: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
6340: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
6350: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
6360: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
6370: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
6380: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
6390: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
63a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
63b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
63c0: 00 00 00 01 10 00 00 04 40 00 01 10 00 00 04 40
63d0: 00 01 10 00 00 04 40 00 01 10 00 00 04 40 00 01
63e0: 10 00 00 04 40 00 01 10 00 00 04 40 00 01 10 00
63f0: 00 04 40 00 01 10 00 00 04 40 00 01 10 00 00 04
6400: 40 00 01 10 00 00 04 40 00 01 10 00 00 04 40 00
6410: 01 10 00 00 04 40 00 01 10 00 00 04 40 00 01 10
6420: 00 00 04 40 00 01 10 00 00 04 40 00 01 10 00 00
6430: 04 40 00 01 10 00 00 04 40 00 01 10 00 00 04 40
6440: 00 01 10 00 00 04 40 00 01 10 00 00 04 40 08 00
6450: 00 02 20 00 00 08 00 00 02 20 00 00 08 00 00 02
6460: 20 00 00 08 00 00 02 20 00 00 08 00 00 02 20 00
6470: 00 08 00 00 02 20 00 00 08 00 00 02 20 00 00 08
6480: 00 00 02 20 00 00 08 00 00 02 20 00 00 08 00 00
6490: 02 20 00 00 08 00 00 02 20 00 00 08 00 00 02 20
64a0: 00 00 08 00 00 02 20 00 00 08 00 00 02 20 00 00
64b0: 08 00 00 02 20 00 00 08 00 00 02 20 00 00 08 00
64c0: 00 02 20 00 00 08 00 00 02 20 00 00 08 00 00 02
64d0: 20 00 00 08 00 00 02 20 00 00 00 00 08 00 00 02
64e0: 20 00 00 08 00 00 02 20 00 00 08 00 00 02 20 00
64f0: 00 08 00 00 02 20 00 00 08 00 00 02 20 00 00 08
6500: 00 00 02 20 00 00 08 00 00 02 20 00 00 08 00 00
6510: 02 20 00 00 08 00 00 02 20 00 00 08 00 00 02 20
6520: 00 00 08 00 00 02 20 00 00 08 00 00 02 20 00 00
6530: 08 00 00 02 20 00 00 08 00 00 02 20 00 00 08 00
6540: 00 02 20 00 00 08 00 00 02 20 00 00 08 00 00 02
6550: 20 00 00 08 00 00 02 20 00 00 08 00 00 02 20 00
6560: 00 08 00 00 02 20 04 40 00 01 10 00 00 04 40 00
6570: 01 10 00 00 04 40 00 01 10 00 00 04 40 00 01 10
6580: 00 00 04 40 00 01 10 00 00 04 40 00 01 10 00 00
6590: 04 40 00 01 10 00 00 04 40 00 01 10 00 00 04 40
65a0: 00 01 10 00 00 04 40 00 01 10 00 00 04 40 00 01
65b0: 10 00 00 04 40 00 01 10 00 00 04 40 00 01 10 00
65c0: 00 04 40 00 01 10 00 00 04 40 00 01 10 00 00 04
65d0: 40 00 01 10 00 00 04 40 00 01 10 00 00 04 40 00
65e0: 01 10 00 00 04 40 00 01 10 00 00 04 40 00 01 10
65f0: 00 00 00 01 18 00 00 06 60 00 01 18 00 00 06 60
6600: 00 01 18 00 00 06 60 00 01 18 00 00 06 60 00 01
6610: 18 00 00 06 60 00 01 18 00 00 06 60 00 01 18 00
6620: 00 06 60 00 01 18 00 00 06 60 00 01 18 00 00 06
6630: 60 00 01 18 00 00 06 60 00 01 18 00 00 06 60 00
6640: 01 18 00 00 06 60 00 01 18 00 00 06 60 00 01 18
6650: 00 00 06 60 00 01 18 00 00 06 60 00 01 18 00 00
6660: 06 60 00 01 18 00 00 06 60 00 01 18 00 00 06 60
6670: 00 01 18 00 00 06 60 00 01 18 00 00 06 60 0c 40
6680: 00 03 30 00 00 0c 40 00 03 30 00 00 0c 40 00 03
6690: 30 00 00 0c 40 00 03 30 00 00 0c 40 00 03 30 00
66a0: 00 0c 40 00 03 30 00 00 0c 40 00 03 30 00 00 0c
66b0: 40 00 03 30 00 00 0c 40 00 03 30 00 00 0c 40 00
66c0: 03 30 00 00 0c 40 00 03 30 00 00 0c 40 00 03 30
66d0: 00 00 0c 40 00 03 30 00 00 0c 40 00 03 30 00 00
66e0: 0c 40 00 03 30 00 00 0c 40 00 03 30 00 00 0c 40
66f0: 00 03 30 00 00 0c 40 00 03 30 00 00 0c 40 00 03
6700: 30 00 00 0c 40 00 03 30 00 00 00 00 04 40 00 01
6710: 10 00 00 04 40 00 01 10 00 00 04 40 00 01 10 00
6720: 00 04 40 00 01 10 00 00 04 40 00 01 10 00 00 04
6730: 40 00 01 10 00 00 04 40 00 01 10 00 00 04 40 00
6740: 01 10 00 00 04 40 00 01 10 00 00 04 40 00 01 10
6750: 00 00 04 40 00 01 10 00 00 04 40 00 01 10 00 00
6760: 04 40 00 01 10 00 00 04 40 00 01 10 00 00 04 40
6770: 00 01 10 00 00 04 40 00 01 10 00 00 04 40 00 01
6780: 10 00 00 04 40 00 01 10 00 00 04 40 00 01 10 00
6790: 00 04 40 00 01 10 02 20 00 00 08 00 00 02 20 00
67a0: 00 08 00 00 02 20 00 00 08 00 00 02 20 00 00 08
67b0: 00 00 02 20 00 00 08 00 00 02 20 00 00 08 00 00
67c0: 02 20 00 00 08 00 00 02 20 00 00 08 00 00 02 20
67d0: 00 00 08 00 00 02 20 00 00 08 00 00 02 20 00 00
67e0: 08 00 00 02 20 00 00 08 00 00 02 20 00 00 08 00
67f0: 00 02 20 00 00 08 00 00 02 20 00 00 08 00 00 02
6800: 20 00 00 08 00 00 02 20 00 00 08 00 00 02 20 00
6810: 00 08 00 00 02 20 00 00 08 00 00 02 20 00 00 08
6820: 00 00 00 01 14 40 00 05 50 00 01 14 40 00 05 50
6830: 00 01 14 40 00 05 50 00 01 14 40 00 05 50 00 01
6840: 14 40 00 05 50 00 01 14 40 00 05 50 00 01 14 40
6850: 00 05 50 00 01 14 40 00 05 50 00 01 14 40 00 05
6860: 50 00 01 14 40 00 05 50 00 01 14 40 00 05 50 00
6870: 01 14 40 00 05 50 00 01 14 40 00 05 50 00 01 14
6880: 40 00 05 50 00 01 14 40 00 05 50 00 01 14 40 00
6890: 05 50 00 01 14 40 00 05 50 00 01 14 40 00 05 50
68a0: 00 01 14 40 00 05 50 00 01 14 40 00 05 50 0a 20
68b0: 00 02 28 00 00 0a 20 00 02 28 00 00 0a 20 00 02
68c0: 28 00 00 0a 20 00 02 28 00 00 0a 20 00 02 28 00
68d0: 00 0a 20 00 02 28 00 00 0a 20 00 02 28 00 00 0a
68e0: 20 00 02 28 00 00 0a 20 00 02 28 00 00 0a 20 00
68f0: 02 28 00 00 0a 20 00 02 28 00 00 0a 20 00 02 28
6900: 00 00 0a 20 00 02 28 00 00 0a 20 00 02 28 00 00
6910: 0a 20 00 02 28 00 00 0a 20 00 02 28 00 00 0a 20
6920: 00 02 28 00 00 0a 20 00 02 28 00 00 0a 20 00 02
6930: 28 00 00 0a 20 00 02 28 00 00 00 00 0c 40 00 03
6940: 30 00 00 0c 40 00 03 30 00 00 0c 40 00 03 30 00
6950: 00 0c 40 00 03 30 00 00 0c 40 00 03 30 00 00 0c
6960: 40 00 03 30 00 00 0c 40 00 03 30 00 00 0c 40 00
6970: 03 30 00 00 0c 40 00 03 30 00 00 0c 40 00 03 30
6980: 00 00 0c 40 00 03 30 00 00 0c 40 00 03 30 00 00
6990: 0c 40 00 03 30 00 00 0c 40 00 03 30 00 00 0c 40
69a0: 00 03 30 00 00 0c 40 00 03 30 00 00 0c 40 00 03
69b0: 30 00 00 0c 40 00 03 30 00 00 0c 40 00 03 30 00
69c0: 00 0c 40 00 03 30 06 60 00 01 18 00 00 06 60 00
69d0: 01 18 00 00 06 60 00 01 18 00 00 06 60 00 01 18
69e0: 00 00 06 60 00 01 18 00 00 06 60 00 01 18 00 00
69f0: 06 60 00 01 18 00 00 06 60 00 01 18 00 00 06 60
6a00: 00 01 18 00 00 06 60 00 01 18 00 00 06 60 00 01
6a10: 18 00 00 06 60 00 01 18 00 00 06 60 00 01 18 00
6a20: 00 06 60 00 01 18 00 00 06 60 00 01 18 00 00 06
6a30: 60 00 01 18 00 00 06 60 00 01 18 00 00 06 60 00
6a40: 01 18 00 00 06 60 00 01 18 00 00 06 60 00 01 18
6a50: 00 00 00 01 1c 40 00 07 70 00 01 1c 40 00 07 70
6a60: 00 01 1c 40 00 07 70 00 01 1c 40 00 07 70 00 01
6a70: 1c 40 00 07 70 00 01 1c 40 00 07 70 00 01 1c 40
6a80: 00 07 70 00 01 1c 40 00 07 70 00 01 1c 40 00 07
6a90: 70 00 01 1c 40 00 07 70 00 01 1c 40 00 07 70 00
6aa0: 01 1c 40 00 07 70 00 01 1c 40 00 07 70 00 01 1c
6ab0: 40 00 07 70 00 01 1c 40 00 07 70 00 01 1c 40 00
6ac0: 07 70 00 01 1c 40 00 07 70 00 01 1c 40 00 07 70
6ad0: 00 01 1c 40 00 07 70 00 01 1c 40 00 07 70 0e 60
6ae0: 00 03 38 00 00 0e 60 00 03 38 00 00 0e 60 00 03
6af0: 38 00 00 0e 60 00 03 38 00 00 0e 60 00 03 38 00
6b00: 00 0e 60 00 03 38 00 00 0e 60 00 03 38 00 00 0e
6b10: 60 00 03 38 00 00 0e 60 00 03 38 00 00 0e 60 00
6b20: 03 38 00 00 0e 60 00 03 38 00 00 0e 60 00 03 38
6b30: 00 00 0e 60 00 03 38 00 00 0e 60 00 03 38 00 00
6b40: 0e 60 00 03 38 00 00 0e 60 00 03 38 00 00 0e 60
6b50: 00 03 38 00 00 0e 60 00 03 38 00 00 0e 60 00 03
6b60: 38 00 00 0e 60 00 03 38 00 00 00 00 02 20 00 00
6b70: 08 00 00 02 20 00 00 08 00 00 02 20 00 00 08 00
6b80: 00 02 20 00 00 08 00 00 02 20 00 00 08 00 00 02
6b90: 20 00 00 08 00 00 02 20 00 00 08 00 00 02 20 00
6ba0: 00 08 00 00 02 20 00 00 08 00 00 02 20 00 00 08
6bb0: 00 00 02 20 00 00 08 00 00 02 20 00 00 08 00 00
6bc0: 02 20 00 00 08 00 00 02 20 00 00 08 00 00 02 20
6bd0: 00 00 08 00 00 02 20 00 00 08 00 00 02 20 00 00
6be0: 08 00 00 02 20 00 00 08 00 00 02 20 00 00 08 00
6bf0: 00 02 20 00 00 08 01 10 00 00 04 40 00 01 10 00
6c00: 00 04 40 00 01 10 00 00 04 40 00 01 10 00 00 04
6c10: 40 00 01 10 00 00 04 40 00 01 10 00 00 04 40 00
6c20: 01 10 00 00 04 40 00 01 10 00 00 04 40 00 01 10
6c30: 00 00 04 40 00 01 10 00 00 04 40 00 01 10 00 00
6c40: 04 40 00 01 10 00 00 04 40 00 01 10 00 00 04 40
6c50: 00 01 10 00 00 04 40 00 01 10 00 00 04 40 00 01
6c60: 10 00 00 04 40 00 01 10 00 00 04 40 00 01 10 00
6c70: 00 04 40 00 01 10 00 00 04 40 00 01 10 00 00 04
6c80: 40 00 00 01 12 20 00 04 48 00 01 12 20 00 04 48
6c90: 00 01 12 20 00 04 48 00 01 12 20 00 04 48 00 01
6ca0: 12 20 00 04 48 00 01 12 20 00 04 48 00 01 12 20
6cb0: 00 04 48 00 01 12 20 00 04 48 00 01 12 20 00 04
6cc0: 48 00 01 12 20 00 04 48 00 01 12 20 00 04 48 00
6cd0: 01 12 20 00 04 48 00 01 12 20 00 04 48 00 01 12
6ce0: 20 00 04 48 00 01 12 20 00 04 48 00 01 12 20 00
6cf0: 04 48 00 01 12 20 00 04 48 00 01 12 20 00 04 48
6d00: 00 01 12 20 00 04 48 00 01 12 20 00 04 48 09 10
6d10: 00 02 24 40 00 09 10 00 02 24 40 00 09 10 00 02
6d20: 24 40 00 09 10 00 02 24 40 00 09 10 00 02 24 40
6d30: 00 09 10 00 02 24 40 00 09 10 00 02 24 40 00 09
6d40: 10 00 02 24 40 00 09 10 00 02 24 40 00 09 10 00
6d50: 02 24 40 00 09 10 00 02 24 40 00 09 10 00 02 24
6d60: 40 00 09 10 00 02 24 40 00 09 10 00 02 24 40 00
6d70: 09 10 00 02 24 40 00 09 10 00 02 24 40 00 09 10
6d80: 00 02 24 40 00 09 10 00 02 24 40 00 09 10 00 02
6d90: 24 40 00 09 10 00 02 24 40 00 00 00 0a 20 00 02
6da0: 28 00 00 0a 20 00 02 28 00 00 0a 20 00 02 28 00
6db0: 00 0a 20 00 02 28 00 00 0a 20 00 02 28 00 00 0a
6dc0: 20 00 02 28 00 00 0a 20 00 02 28 00 00 0a 20 00
6dd0: 02 28 00 00 0a 20 00 02 28 00 00 0a 20 00 02 28
6de0: 00 00 0a 20 00 02 28 00 00 0a 20 00 02 28 00 00
6df0: 0a 20 00 02 28 00 00 0a 20 00 02 28 00 00 0a 20
6e00: 00 02 28 00 00 0a 20 00 02 28 00 00 0a 20 00 02
6e10: 28 00 00 0a 20 00 02 28 00 00 0a 20 00 02 28 00
6e20: 00 0a 20 00 02 28 05 50 00 01 14 40 00 05 50 00
6e30: 01 14 40 00 05 50 00 01 14 40 00 05 50 00 01 14
6e40: 40 00 05 50 00 01 14 40 00 05 50 00 01 14 40 00
6e50: 05 50 00 01 14 40 00 05 50 00 01 14 40 00 05 50
6e60: 00 01 14 40 00 05 50 00 01 14 40 00 05 50 00 01
6e70: 14 40 00 05 50 00 01 14 40 00 05 50 00 01 14 40
6e80: 00 05 50 00 01 14 40 00 05 50 00 01 14 40 00 05
6e90: 50 00 01 14 40 00 05 50 00 01 14 40 00 05 50 00
6ea0: 01 14 40 00 05 50 00 01 14 40 00 05 50 00 01 14
6eb0: 40 00 00 01 1a 20 00 06 68 00 01 1a 20 00 06 68
6ec0: 00 01 1a 20 00 06 68 00 01 1a 20 00 06 68 00 01
6ed0: 1a 20 00 06 68 00 01 1a 20 00 06 68 00 01 1a 20
6ee0: 00 06 68 00 01 1a 20 00 06 68 00 01 1a 20 00 06
6ef0: 68 00 01 1a 20 00 06 68 00 01 1a 20 00 06 68 00
6f00: 01 1a 20 00 06 68 00 01 1a 20 00 06 68 00 01 1a
6f10: 20 00 06 68 00 01 1a 20 00 06 68 00 01 1a 20 00
6f20: 06 68 00 01 1a 20 00 06 68 00 01 1a 20 00 06 68
6f30: 00 01 1a 20 00 06 68 00 01 1a 20 00 06 68 0d 50
6f40: 00 03 34 40 00 0d 50 00 03 34 40 00 0d 50 00 03
6f50: 34 40 00 0d 50 00 03 34 40 00 0d 50 00 03 34 40
6f60: 00 0d 50 00 03 34 40 00 0d 50 00 03 34 40 00 0d
6f70: 50 00 03 34 40 00 0d 50 00 03 34 40 00 0d 50 00
6f80: 03 34 40 00 0d 50 00 03 34 40 00 0d 50 00 03 34
6f90: 40 00 0d 50 00 03 34 40 00 0d 50 00 03 34 40 00
6fa0: 0d 50 00 03 34 40 00 0d 50 00 03 34 40 00 0d 50
6fb0: 00 03 34 40 00 0d 50 00 03 34 40 00 0d 50 00 03
6fc0: 34 40 00 0d 50 00 03 34 40 00 00 00 06 60 00 01
6fd0: 18 00 00 06 60 00 01 18 00 00 06 60 00 01 18 00
6fe0: 00 06 60 00 01 18 00 00 06 60 00 01 18 00 00 06
6ff0: 60 00 01 18 00 00 06 60 00 01 18 00 00 06 60 00
7000: 01 18 00 00 06 60 00 01 18 00 00 06 60 00 01 18
7010: 00 00 06 60 00 01 18 00 00 06 60 00 01 18 00 00
7020: 06 60 00 01 18 00 00 06 60 00 01 18 00 00 06 60
7030: 00 01 18 00 00 06 60 00 01 18 00 00 06 60 00 01
7040: 18 00 00 06 60 00 01 18 00 00 06 60 00 01 18 00
7050: 00 06 60 00 01 18 03 30 00 00 0c 40 00 03 30 00
7060: 00 0c 40 00 03 30 00 00 0c 40 00 03 30 00 00 0c
7070: 40 00 03 30 00 00 0c 40 00 03 30 00 00 0c 40 00
7080: 03 30 00 00 0c 40 00 03 30 00 00 0c 40 00 03 30
7090: 00 00 0c 40 00 03 30 00 00 0c 40 00 03 30 00 00
70a0: 0c 40 00 03 30 00 00 0c 40 00 03 30 00 00 0c 40
70b0: 00 03 30 00 00 0c 40 00 03 30 00 00 0c 40 00 03
70c0: 30 00 00 0c 40 00 03 30 00 00 0c 40 00 03 30 00
70d0: 00 0c 40 00 03 30 00 00 0c 40 00 03 30 00 00 0c
70e0: 40 00 00 01 16 60 00 05 58 00 01 16 60 00 05 58
70f0: 00 01 16 60 00 05 58 00 01 16 60 00 05 58 00 01
7100: 16 60 00 05 58 00 01 16 60 00 05 58 00 01 16 60
7110: 00 05 58 00 01 16 60 00 05 58 00 01 16 60 00 05
7120: 58 00 01 16 60 00 05 58 00 01 16 60 00 05 58 00
7130: 01 16 60 00 05 58 00 01 16 60 00 05 58 00 01 16
7140: 60 00 05 58 00 01 16 60 00 05 58 00 01 16 60 00
7150: 05 58 00 01 16 60 00 05 58 00 01 16 60 00 05 58
7160: 00 01 16 60 00 05 58 00 01 16 60 00 05 58 0b 30
7170: 00 02 2c 40 00 0b 30 00 02 2c 40 00 0b 30 00 02
7180: 2c 40 00 0b 30 00 02 2c 40 00 0b 30 00 02 2c 40
7190: 00 0b 30 00 02 2c 40 00 0b 30 00 02 2c 40 00 0b
71a0: 30 00 02 2c 40 00 0b 30 00 02 2c 40 00 0b 30 00
71b0: 02 2c 40 00 0b 30 00 02 2c 40 00 0b 30 00 02 2c
71c0: 40 00 0b 30 00 02 2c 40 00 0b 30 00 02 2c 40 00
71d0: 0b 30 00 02 2c 40 00 0b 30 00 02 2c 40 00 0b 30
71e0: 00 02 2c 40 00 0b 30 00 02 2c 40 00 0b 30 00 02
71f0: 2c 40 00 0b 30 00 02 2c 40 00 00 00 0e 60 00 03
7200: 38 00 00 0e 60 00 03 38 00 00 0e 60 00 03 38 00
7210: 00 0e 60 00 03 38 00 00 0e 60 00 03 38 00 00 0e
7220: 60 00 03 38 00 00 0e 60 00 03 38 00 00 0e 60 00
7230: 03 38 00 00 0e 60 00 03 38 00 00 0e 60 00 03 38
7240: 00 00 0e 60 00 03 38 00 00 0e 60 00 03 38 00 00
7250: 0e 60 00 03 38 00 00 0e 60 00 03 38 00 00 0e 60
7260: 00 03 38 00 00 0e 60 00 03 38 00 00 0e 60 00 03
7270: 38 00 00 0e 60 00 03 38 00 00 0e 60 00 03 38 00
7280: 00 0e 60 00 03 38 07 70 00 01 1c 40 00 07 70 00
7290: 01 1c 40 00 07 70 00 01 1c 40 00 07 70 00 01 1c
72a0: 40 00 07 70 00 01 1c 40 00 07 70 00 01 1c 40 00
72b0: 07 70 00 01 1c 40 00 07 70 00 01 1c 40 00 07 70
72c0: 00 01 1c 40 00 07 70 00 01 1c 40 00 07 70 00 01
72d0: 1c 40 00 07 70 00 01 1c 40 00 07 70 00 01 1c 40
72e0: 00 07 70 00 01 1c 40 00 07 70 00 01 1c 40 00 07
72f0: 70 00 01 1c 40 00 07 70 00 01 1c 40 00 07 70 00
7300: 01 1c 40 00 07 70 00 01 1c 40 00 07 70 00 01 1c
7310: 40 00 00 01 1e 60 00 07 78 00 01 1e 60 00 07 78
7320: 00 01 1e 60 00 07 78 00 01 1e 60 00 07 78 00 01
7330: 1e 60 00 07 78 00 01 1e 60 00 07 78 00 01 1e 60
7340: 00 07 78 00 01 1e 60 00 07 78 00 01 1e 60 00 07
7350: 78 00 01 1e 60 00 07 78 00 01 1e 60 00 07 78 00
7360: 01 1e 60 00 07 78 00 01 1e 60 00 07 78 00 01 1e
7370: 60 00 07 78 00 01 1e 60 00 07 78 00 01 1e 60 00
7380: 07 78 00 01 1e 60 00 07 78 00 01 1e 60 00 07 78
7390: 00 01 1e 60 00 07 78 00 01 1e 60 00 07 78 0f 70
73a0: 00 03 3c 40 00 0f 70 00 03 3c 40 00 0f 70 00 03
73b0: 3c 40 00 0f 70 00 03 3c 40 00 0f 70 00 03 3c 40
73c0: 00 0f 70 00 03 3c 40 00 0f 70 00 03 3c 40 00 0f
73d0: 70 00 03 3c 40 00 0f 70 00 03 3c 40 00 0f 70 00
73e0: 03 3c 40 00 0f 70 00 03 3c 40 00 0f 70 00 03 3c
73f0: 40 00 0f 70 00 03 3c 40 00 0f 70 00 03 3c 40 00
7400: 0f 70 00 03 3c 40 00 0f 70 00 03 3c 40 00 0f 70
7410: 00 03 3c 40 00 0f 70 00 03 3c 40 00 0f 70 00 03
7420: 3c 40 00 0f 70 00 03 3c 40 00 aa c2 da f2 0a 22
7430: 3a 52 6a 82 9a b2 ca e2 fa 12 62 63 64 65 67 68
7440: 69 6a 6b 6c 6d 6e 6f 70 71 73 36 4e 66 7e 96 ae
7450: c6 de f6 0e 26 3e 56 6e 86 9e 63 64 65 66 67 68
7460: 69 6a 6b 6d 6e 6f 70 71 72 73 00 00 00 00 00 00
7470: 00 00 80 80 80 80 80 80 80 80 00 00 00 00 00 00
7480: 00 00 80 80 80 80 80 80 80 80 00 00 00 00 00 00
7490: 00 00 80 80 80 80 80 80 80 80 00 00 00 00 00 00
74a0: 00 00 80 80 80 80 80 80 80 80 28 28 28 28 28 28
74b0: 28 28 a8 a8 a8 a8 a8 a8 a8 a8 28 28 28 28 28 28
74c0: 28 28 a8 a8 a8 a8 a8 a8 a8 a8 28 28 28 28 28 28
74d0: 28 28 a8 a8 a8 a8 a8 a8 a8 a8 28 28 28 28 28 28
74e0: 28 28 a8 a8 a8 a8 a8 a8 a8 a8 50 50 50 50 50 50
74f0: 50 50 d0 d0 d0 d0 d0 d0 d0 d0 50 50 50 50 50 50
7500: 50 50 d0 d0 d0 d0 d0 d0 d0 d0 50 50 50 50 50 50
7510: 50 50 d0 d0 d0 d0 d0 d0 d0 d0 50 50 50 50 50 50
7520: 50 50 d0 d0 d0 d0 d0 d0 d0 d0 20 24 28 2c 30 34
7530: 38 3c 20 24 28 2c 30 34 38 3c 21 25 29 2d 31 35
7540: 39 3d 21 25 29 2d 31 35 39 3d 22 26 2a 2e 32 36
7550: 3a 3e 22 26 2a 2e 32 36 3a 3e 23 27 2b 2f 33 37
7560: 3b 3f 23 27 2b 2f 33 37 3b 3f 20 24 28 2c 30 34
7570: 38 3c 20 24 28 2c 30 34 38 3c 21 25 29 2d 31 35
7580: 39 3d 21 25 29 2d 31 35 39 3d 22 26 2a 2e 32 36
7590: 3a 3e 22 26 2a 2e 32 36 3a 3e 23 27 2b 2f 33 37
75a0: 3b 3f 23 27 2b 2f 33 37 3b 3f 20 24 28 2c 30 34
75b0: 38 3c 20 24 28 2c 30 34 38 3c 21 25 29 2d 31 35
75c0: 39 3d 21 25 29 2d 31 35 39 3d 22 26 2a 2e 32 36
75d0: 3a 3e 22 26 2a 2e 32 36 3a 3e 23 27 2b 2f 33 37
75e0: 3b 3f 23 27 2b 2f 33 37 3b 3f
6000G
Under my benchmarks this optimizaiton clocks in at 1.6s per screen or 0.62 FPS
How to (quickly) draw a line:
Our code is now sufficiently modular that we can get back to the business of line drawing. Our goal is to create a program which can take the start and end points of a line and plot all the points in between. Many of us might be look to our high-school algebra for the answer. Many of us were taught that the formula for a line is written like so:
Where "m" is the slope - how steep the line is and "b" is the point where the line intercepts with the Y axis. So if we had a line between (4,2) and (16,2) we could figure out the lines formula like in the following way:
Once we had that we could just run through all the X co-ordinates between 4 and 16 and round up to the nearest whole number to find all the points on this line.
X | Y (1/3X+2/3) | Y (rounded) | Point |
4 | 2 | 2 | (4,2) |
5 | 2.3333 | 2 | (5,2) |
6 | 2.6666 | 3 | (6,3) |
7 | 3 | 3 | (7,3) |
8 | 3.3333 | 3 | (8,3) |
9 | 3.6666 | 4 | (9,4) |
10 | 4 | 4 | (10,4) |
11 | 4.3333 | 4 | (11,4) |
12 | 4.6666 | 5 | (12,5) |
13 | 5 | 5 | (13,5) |
14 | 5.3333 | 5 | (14,5) |
15 | 5.6666 | 6 | (15,6) |
16 | 6 | 6 | (16,6) |
The problem here should be pretty clear. It takes a number of mathematical operations to get the slope of a line, more to solve for b and several to plot each point. Too many to solve even using tables. Not to mention that most of these calculations involve decimals, something the 6502 doesn't handle natively.
Enter Bresenham's Line:
Jack Elton Bresenham was a technical staff member at IBM and in 1962 he found himself with the problem of using a digital plotter to draw a line. The device could move in one of eight directions at steps as small as 1/100th of an inch. Which meant that when the plotter had to draw a long line at a particular angle. The line had to be broken up into a series of points which the plotter would then connect. While it wasn't the intent of his original article, breaking up a line into a series of points is called rasterization and is effectively what we are trying to do.
How it works:
Just like how Bresenham's plotter only moved discrete steps in a limited number of directions. Every line on a pixel display can only move in two. Either it moves one step along it's major axis, the direction (Horizontal or vertical) which our line moves farthest or it moves one step along both it's major and minor axes.
So what our algorithm really needs to answer is:
How many moves on the major access do we need to make before we move once on the minor axis?
Earlier when we talked about high school algebra you might recall that the slope of a line is not
just defined as it's "steepness" or DX/DY but is also sometimes referred to as "rise over run". The proportion of Y movements to X movements. So if we know the slope, we already have our answer and when given the start and end points of a line the slope is easy to calculate it's just X1-X0/Y1-Y0, where (X0,Y0) and (X1,Y1) are the beginning and ending points of the line respectively.
There is still one problem though. Often, as in the example above when we calculate slope we end up with a result that is a fraction or decimal, neither thing a 6502 can work with very easily.
Again, there is a simple solution. In the same way that multiplication is simply repeated addition i.e. 3 * 7 = 7 + 7 + 7. Division can be calculated by repeated subtraction. So if, as is our case here DX is larger than DY. We can store DX in a variable that we will call "epsilon" and before each plot we will subtract DY, if this variable dips below zero. Then we know we need to move down the minor axis. At which point we will add DX to epsilon and start the process all over again.
Ok, that sounds all well and good but does it work? Good question! Here's a chart using our new algorithm:
Plot # | Location | Epsilon | DX | DY |
1 | (4,2) | 12 | 12 | 4 |
2 | (5,2) | 8 | 12 | 4 |
3 | (6,2) | 4 | 12 | 4 |
4 | (7,3) | 12 | 12 | 4 |
5 | (8,3) | 8 | 12 | 4 |
6 | (9,3) | 4 | 12 | 4 |
7 | (10,4) | 12 | 12 | 4 |
8 | (11,4) | 6 | 12 | 4 |
9 | (12,4) | 3 | 12 | 4 |
10 | (13,5) | 12 | 12 | 4 |
11 | (14,5) | 6 | 12 | 4 |
12 | (15,5) | 3 | 12 | 4 |
13 | (16,6) | 12 | 12 | 4 |
As you can see it comes pretty close to matching the points we calculated using the slope of the line. The only difference is that our algorithm has three points at Y=2 and only one at Y=6. Whereas when we were rounding the calculated values of each point we had two points with Y=2 and two points with Y=6.
This comes from our initial choice for epsilon being a little too high. You can see this clearly if you attempt to plot a really shallow line like (0,0) to (138,1). Epsilon will start at 138 and it will take 138 plots before it will reach zero. This results in a line that would look identical to a line drawn from (0,0) to (138,0) up until the very last point.
To fix this, we start epsilon at DX/2 and our line matches perfectly in both cases. Not only that but the complexity has dropped dramatically since we can now calculate our points just by using
two additions.
But we can do even better. Thinking for a moment about how to implement this on the 6502. Normally to check if the value has crossed a boundary we need to do a CMP and then branch on the basis of the result. However we can avoid this comparison altogether by initially setting epsilon equal to 255-DX/2. When DX > 255 the carry flag will be set and we will know it's time to make a move on the minor axis.
With these ideas in mind we can write the following assembly:
*DEMO 3
*Use DH.PLOT to draw coloured lines from X0,Y0 to X1,Y1
*Jonathan Graham/Battlestations
*Free for non-commercial use with attribution
*
XC ;Required for Merlin Pro to use 65C02 instructions
ORG $6000 ;Start assembling at memory location $6000
COLOUR EQU $F6
X0 EQU $F7
Y0 EQU $F8
X1 EQU $F9
Y1 EQU $FA
DX EQU $FB
DY EQU $FC
EPSILON EQU $FD
PUT DH.INIT
LDA #$00 ;Start our line at (0,0)
STA X0
LDA #$00
STA Y0
LDA #$8B ;End our line at (139,138)
STA X1
:LOOP1 LDA #$8A
STA Y1
:LOOP2 LDA COLOUR ;Set the colour to whatever is in $F6
AND #$0F ;AND the four high bits to make a valid colour
JSR SETDCOLOR ;Set colour to whatever is in $F6
JSR NXTLINE ;Draw our line
DEC COLOUR ;Change the colour
LDA Y1 ;Move the end of the line up one column
DEC
CMP #$FF ;See if we're done
STA Y1
BNE :LOOP2 ;Not done draw another line
BRA :LOOP1 ;Done, reset the line and keep drawing
NXTLINE LDA Y1 ;Calculate DY as Y1-Y0
SEC
SBC Y0
STA DY
LDA X1 ;Calculate DX as X1-X0
SEC
SBC X0
STA DX
LSR ; Set epsilon to DX/2
EOR #$FF
STA EPSILON
LDX X0 ;Start plotting at (X0,Y0)
LDY Y0
NXTVERT PUT DH.ROWSET ;Calculate horizontal value
NXTHORZ PHY
PUT DH.PLOT ;Plot point
PLY
CPX X1 ;Are we done?
BEQ ENDLINE
INX ;Move along major axis
LDA EPSILON ;Epsilon = Epsilon + DY
CLC
ADC DY
STA EPSILON
BCC NXTHORZ ;If Epsilon hasn't rolled over move to next point
SEC ;If epsilon has rolled over subtract DX
SBC DX
STA EPSILON
INY ;Move along minor axis
BRA NXTVERT
ENDLINE RTS
SETDCOLOR TAY ;Assume the desired colour is in the accumulator
PUT DH.COLOUR
RTS
PUT DH.TABLES
Lest we forget a binary copy...
CALL -151
6000: 8d 50 c0 8d 57 c0 8d 52 c0 8d 5e c0 8d 0d c0 8d
6010: 01 c0 a9 00 85 f7 a9 00 85 f8 a9 8b 85 f9 a9 8a
6020: 85 fa a5 f6 29 0f 20 97 60 20 39 60 c6 f6 a5 fa
6030: 3a c9 ff 85 fa d0 eb 80 e5 a5 fa 38 e5 f8 85 fc
6040: a5 f9 38 e5 f7 85 fb 4a 49 ff 85 fd a6 f7 a4 f8
6050: b9 a1 74 85 1d b9 61 75 85 1e 5a bc b1 60 30 0d
6060: 8d 54 c0 b1 1d 3d c9 61 1d 71 69 91 1d bc 3d 61
6070: 30 0d 8d 55 c0 b1 1d 3d 55 62 1d fd 69 91 1d 7a
6080: e4 f9 f0 12 e8 a5 fd 18 65 fc 85 fd 90 cc 38 e5
6090: fb 85 fd c8 80 ba 60 a8 b9 61 74 8d 69 60 b9 71
60a0: 74 8d 6a 60 b9 81 74 8d 7b 60 b9 91 74 8d 7c 60
60b0: 60 ff 00 00 00 ff 01 01 ff 02 02 02 ff 03 03 ff
60c0: 04 04 04 ff 05 05 ff 06 06 06 ff 07 07 ff 08 08
60d0: 08 ff 09 09 ff 0a 0a 0a ff 0b 0b ff 0c 0c 0c ff
60e0: 0d 0d ff 0e 0e 0e ff 0f 0f ff 10 10 10 ff 11 11
60f0: ff 12 12 12 ff 13 13 ff 14 14 14 ff 15 15 ff 16
6100: 16 16 ff 17 17 ff 18 18 18 ff 19 19 ff 1a 1a 1a
6110: ff 1b 1b ff 1c 1c 1c ff 1d 1d ff 1e 1e 1e ff 1f
6120: 1f ff 20 20 20 ff 21 21 ff 22 22 22 ff 23 23 ff
6130: 24 24 24 ff 25 25 ff 26 26 26 ff 27 27 00 00 ff
6140: 01 01 01 ff 02 02 ff 03 03 03 ff 04 04 ff 05 05
6150: 05 ff 06 06 ff 07 07 07 ff 08 08 ff 09 09 09 ff
6160: 0a 0a ff 0b 0b 0b ff 0c 0c ff 0d 0d 0d ff 0e 0e
6170: ff 0f 0f 0f ff 10 10 ff 11 11 11 ff 12 12 ff 13
6180: 13 13 ff 14 14 ff 15 15 15 ff 16 16 ff 17 17 17
6190: ff 18 18 ff 19 19 19 ff 1a 1a ff 1b 1b 1b ff 1c
61a0: 1c ff 1d 1d 1d ff 1e 1e ff 1f 1f 1f ff 20 20 ff
61b0: 21 21 21 ff 22 22 ff 23 23 23 ff 24 24 f4 25 25
61c0: 25 ff 26 26 ff 27 27 27 ff 7f 7e 61 1f 7f 78 07
61d0: 7f 7e 61 1f 7f 78 07 7f 7e 61 1f 7f 78 07 7f 7e
61e0: 61 1f 7f 78 07 7f 7e 61 1f 7f 78 07 7f 7e 61 1f
61f0: 7f 78 07 7f 7e 61 1f 7f 78 07 7f 7e 61 1f 7f 78
6200: 07 7f 7e 61 1f 7f 78 07 7f 7e 61 1f 7f 78 07 7f
6210: 7e 61 1f 7f 78 07 7f 7e 61 1f 7f 78 07 7f 7e 61
6220: 1f 7f 78 07 7f 7e 61 1f 7f 78 07 7f 7e 61 1f 7f
6230: 78 07 7f 7e 61 1f 7f 78 07 7f 7e 61 1f 7f 78 07
6240: 7f 7e 61 1f 7f 78 07 7f 7e 61 1f 7f 78 07 7f 7e
6250: 61 1f 7f 78 07 70 0f 7f 7c 43 3f 7f 70 0f 7f 7c
6260: 43 3f 7f 70 0f 7f 7c 43 3f 7f 70 0f 7f 7c 43 3f
6270: 7f 70 0f 7f 7c 43 3f 7f 70 0f 7f 7c 43 3f 7f 70
6280: 0f 7f 7c 43 3f 7f 70 0f 7f 7c 43 3f 7f 70 0f 7f
6290: 7c 43 3f 7f 70 0f 7f 7c 43 3f 7f 70 0f 7f 7c 43
62a0: 3f 7f 70 0f 7f 7c 43 3f 7f 70 0f 7f 7c 43 3f 7f
62b0: 70 0f 7f 7c 43 3f 7f 70 0f 7f 7c 43 3f 7f 70 0f
62c0: 7f 7c 43 3f 7f 70 0f 7f 7c 43 3f 7f 70 0f 7f 7c
62d0: 43 3f 7f 70 0f 7f 7c 43 3f 7f 70 0f 7f 7c 43 3f
62e0: 7f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
62f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
6300: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
6310: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
6320: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
6330: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
6340: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
6350: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
6360: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
6370: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
6380: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
6390: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
63a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
63b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
63c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
63d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
63e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
63f0: 00 00 00 00 00 00 00 00 00 00 01 10 00 00 04 40
6400: 00 01 10 00 00 04 40 00 01 10 00 00 04 40 00 01
6410: 10 00 00 04 40 00 01 10 00 00 04 40 00 01 10 00
6420: 00 04 40 00 01 10 00 00 04 40 00 01 10 00 00 04
6430: 40 00 01 10 00 00 04 40 00 01 10 00 00 04 40 00
6440: 01 10 00 00 04 40 00 01 10 00 00 04 40 00 01 10
6450: 00 00 04 40 00 01 10 00 00 04 40 00 01 10 00 00
6460: 04 40 00 01 10 00 00 04 40 00 01 10 00 00 04 40
6470: 00 01 10 00 00 04 40 00 01 10 00 00 04 40 00 01
6480: 10 00 00 04 40 08 00 00 02 20 00 00 08 00 00 02
6490: 20 00 00 08 00 00 02 20 00 00 08 00 00 02 20 00
64a0: 00 08 00 00 02 20 00 00 08 00 00 02 20 00 00 08
64b0: 00 00 02 20 00 00 08 00 00 02 20 00 00 08 00 00
64c0: 02 20 00 00 08 00 00 02 20 00 00 08 00 00 02 20
64d0: 00 00 08 00 00 02 20 00 00 08 00 00 02 20 00 00
64e0: 08 00 00 02 20 00 00 08 00 00 02 20 00 00 08 00
64f0: 00 02 20 00 00 08 00 00 02 20 00 00 08 00 00 02
6500: 20 00 00 08 00 00 02 20 00 00 08 00 00 02 20 00
6510: 00 00 00 08 00 00 02 20 00 00 08 00 00 02 20 00
6520: 00 08 00 00 02 20 00 00 08 00 00 02 20 00 00 08
6530: 00 00 02 20 00 00 08 00 00 02 20 00 00 08 00 00
6540: 02 20 00 00 08 00 00 02 20 00 00 08 00 00 02 20
6550: 00 00 08 00 00 02 20 00 00 08 00 00 02 20 00 00
6560: 08 00 00 02 20 00 00 08 00 00 02 20 00 00 08 00
6570: 00 02 20 00 00 08 00 00 02 20 00 00 08 00 00 02
6580: 20 00 00 08 00 00 02 20 00 00 08 00 00 02 20 00
6590: 00 08 00 00 02 20 00 00 08 00 00 02 20 04 40 00
65a0: 01 10 00 00 04 40 00 01 10 00 00 04 40 00 01 10
65b0: 00 00 04 40 00 01 10 00 00 04 40 00 01 10 00 00
65c0: 04 40 00 01 10 00 00 04 40 00 01 10 00 00 04 40
65d0: 00 01 10 00 00 04 40 00 01 10 00 00 04 40 00 01
65e0: 10 00 00 04 40 00 01 10 00 00 04 40 00 01 10 00
65f0: 00 04 40 00 01 10 00 00 04 40 00 01 10 00 00 04
6600: 40 00 01 10 00 00 04 40 00 01 10 00 00 04 40 00
6610: 01 10 00 00 04 40 00 01 10 00 00 04 40 00 01 10
6620: 00 00 04 40 00 01 10 00 00 00 01 18 00 00 06 60
6630: 00 01 18 00 00 06 60 00 01 18 00 00 06 60 00 01
6640: 18 00 00 06 60 00 01 18 00 00 06 60 00 01 18 00
6650: 00 06 60 00 01 18 00 00 06 60 00 01 18 00 00 06
6660: 60 00 01 18 00 00 06 60 00 01 18 00 00 06 60 00
6670: 01 18 00 00 06 60 00 01 18 00 00 06 60 00 01 18
6680: 00 00 06 60 00 01 18 00 00 06 60 00 01 18 00 00
6690: 06 60 00 01 18 00 00 06 60 00 01 18 00 00 06 60
66a0: 00 01 18 00 00 06 60 00 01 18 00 00 06 60 00 01
66b0: 18 00 00 06 60 0c 40 00 03 30 00 00 0c 40 00 03
66c0: 30 00 00 0c 40 00 03 30 00 00 0c 40 00 03 30 00
66d0: 00 0c 40 00 03 30 00 00 0c 40 00 03 30 00 00 0c
66e0: 40 00 03 30 00 00 0c 40 00 03 30 00 00 0c 40 00
66f0: 03 30 00 00 0c 40 00 03 30 00 00 0c 40 00 03 30
6700: 00 00 0c 40 00 03 30 00 00 0c 40 00 03 30 00 00
6710: 0c 40 00 03 30 00 00 0c 40 00 03 30 00 00 0c 40
6720: 00 03 30 00 00 0c 40 00 03 30 00 00 0c 40 00 03
6730: 30 00 00 0c 40 00 03 30 00 00 0c 40 00 03 30 00
6740: 00 00 00 04 40 00 01 10 00 00 04 40 00 01 10 00
6750: 00 04 40 00 01 10 00 00 04 40 00 01 10 00 00 04
6760: 40 00 01 10 00 00 04 40 00 01 10 00 00 04 40 00
6770: 01 10 00 00 04 40 00 01 10 00 00 04 40 00 01 10
6780: 00 00 04 40 00 01 10 00 00 04 40 00 01 10 00 00
6790: 04 40 00 01 10 00 00 04 40 00 01 10 00 00 04 40
67a0: 00 01 10 00 00 04 40 00 01 10 00 00 04 40 00 01
67b0: 10 00 00 04 40 00 01 10 00 00 04 40 00 01 10 00
67c0: 00 04 40 00 01 10 00 00 04 40 00 01 10 02 20 00
67d0: 00 08 00 00 02 20 00 00 08 00 00 02 20 00 00 08
67e0: 00 00 02 20 00 00 08 00 00 02 20 00 00 08 00 00
67f0: 02 20 00 00 08 00 00 02 20 00 00 08 00 00 02 20
6800: 00 00 08 00 00 02 20 00 00 08 00 00 02 20 00 00
6810: 08 00 00 02 20 00 00 08 00 00 02 20 00 00 08 00
6820: 00 02 20 00 00 08 00 00 02 20 00 00 08 00 00 02
6830: 20 00 00 08 00 00 02 20 00 00 08 00 00 02 20 00
6840: 00 08 00 00 02 20 00 00 08 00 00 02 20 00 00 08
6850: 00 00 02 20 00 00 08 00 00 00 01 14 40 00 05 50
6860: 00 01 14 40 00 05 50 00 01 14 40 00 05 50 00 01
6870: 14 40 00 05 50 00 01 14 40 00 05 50 00 01 14 40
6880: 00 05 50 00 01 14 40 00 05 50 00 01 14 40 00 05
6890: 50 00 01 14 40 00 05 50 00 01 14 40 00 05 50 00
68a0: 01 14 40 00 05 50 00 01 14 40 00 05 50 00 01 14
68b0: 40 00 05 50 00 01 14 40 00 05 50 00 01 14 40 00
68c0: 05 50 00 01 14 40 00 05 50 00 01 14 40 00 05 50
68d0: 00 01 14 40 00 05 50 00 01 14 40 00 05 50 00 01
68e0: 14 40 00 05 50 0a 20 00 02 28 00 00 0a 20 00 02
68f0: 28 00 00 0a 20 00 02 28 00 00 0a 20 00 02 28 00
6900: 00 0a 20 00 02 28 00 00 0a 20 00 02 28 00 00 0a
6910: 20 00 02 28 00 00 0a 20 00 02 28 00 00 0a 20 00
6920: 02 28 00 00 0a 20 00 02 28 00 00 0a 20 00 02 28
6930: 00 00 0a 20 00 02 28 00 00 0a 20 00 02 28 00 00
6940: 0a 20 00 02 28 00 00 0a 20 00 02 28 00 00 0a 20
6950: 00 02 28 00 00 0a 20 00 02 28 00 00 0a 20 00 02
6960: 28 00 00 0a 20 00 02 28 00 00 0a 20 00 02 28 00
6970: 00 00 00 0c 40 00 03 30 00 00 0c 40 00 03 30 00
6980: 00 0c 40 00 03 30 00 00 0c 40 00 03 30 00 00 0c
6990: 40 00 03 30 00 00 0c 40 00 03 30 00 00 0c 40 00
69a0: 03 30 00 00 0c 40 00 03 30 00 00 0c 40 00 03 30
69b0: 00 00 0c 40 00 03 30 00 00 0c 40 00 03 30 00 00
69c0: 0c 40 00 03 30 00 00 0c 40 00 03 30 00 00 0c 40
69d0: 00 03 30 00 00 0c 40 00 03 30 00 00 0c 40 00 03
69e0: 30 00 00 0c 40 00 03 30 00 00 0c 40 00 03 30 00
69f0: 00 0c 40 00 03 30 00 00 0c 40 00 03 30 06 60 00
6a00: 01 18 00 00 06 60 00 01 18 00 00 06 60 00 01 18
6a10: 00 00 06 60 00 01 18 00 00 06 60 00 01 18 00 00
6a20: 06 60 00 01 18 00 00 06 60 00 01 18 00 00 06 60
6a30: 00 01 18 00 00 06 60 00 01 18 00 00 06 60 00 01
6a40: 18 00 00 06 60 00 01 18 00 00 06 60 00 01 18 00
6a50: 00 06 60 00 01 18 00 00 06 60 00 01 18 00 00 06
6a60: 60 00 01 18 00 00 06 60 00 01 18 00 00 06 60 00
6a70: 01 18 00 00 06 60 00 01 18 00 00 06 60 00 01 18
6a80: 00 00 06 60 00 01 18 00 00 00 01 1c 40 00 07 70
6a90: 00 01 1c 40 00 07 70 00 01 1c 40 00 07 70 00 01
6aa0: 1c 40 00 07 70 00 01 1c 40 00 07 70 00 01 1c 40
6ab0: 00 07 70 00 01 1c 40 00 07 70 00 01 1c 40 00 07
6ac0: 70 00 01 1c 40 00 07 70 00 01 1c 40 00 07 70 00
6ad0: 01 1c 40 00 07 70 00 01 1c 40 00 07 70 00 01 1c
6ae0: 40 00 07 70 00 01 1c 40 00 07 70 00 01 1c 40 00
6af0: 07 70 00 01 1c 40 00 07 70 00 01 1c 40 00 07 70
6b00: 00 01 1c 40 00 07 70 00 01 1c 40 00 07 70 00 01
6b10: 1c 40 00 07 70 0e 60 00 03 38 00 00 0e 60 00 03
6b20: 38 00 00 0e 60 00 03 38 00 00 0e 60 00 03 38 00
6b30: 00 0e 60 00 03 38 00 00 0e 60 00 03 38 00 00 0e
6b40: 60 00 03 38 00 00 0e 60 00 03 38 00 00 0e 60 00
6b50: 03 38 00 00 0e 60 00 03 38 00 00 0e 60 00 03 38
6b60: 00 00 0e 60 00 03 38 00 00 0e 60 00 03 38 00 00
6b70: 0e 60 00 03 38 00 00 0e 60 00 03 38 00 00 0e 60
6b80: 00 03 38 00 00 0e 60 00 03 38 00 00 0e 60 00 03
6b90: 38 00 00 0e 60 00 03 38 00 00 0e 60 00 03 38 00
6ba0: 00 00 00 02 20 00 00 08 00 00 02 20 00 00 08 00
6bb0: 00 02 20 00 00 08 00 00 02 20 00 00 08 00 00 02
6bc0: 20 00 00 08 00 00 02 20 00 00 08 00 00 02 20 00
6bd0: 00 08 00 00 02 20 00 00 08 00 00 02 20 00 00 08
6be0: 00 00 02 20 00 00 08 00 00 02 20 00 00 08 00 00
6bf0: 02 20 00 00 08 00 00 02 20 00 00 08 00 00 02 20
6c00: 00 00 08 00 00 02 20 00 00 08 00 00 02 20 00 00
6c10: 08 00 00 02 20 00 00 08 00 00 02 20 00 00 08 00
6c20: 00 02 20 00 00 08 00 00 02 20 00 00 08 01 10 00
6c30: 00 04 40 00 01 10 00 00 04 40 00 01 10 00 00 04
6c40: 40 00 01 10 00 00 04 40 00 01 10 00 00 04 40 00
6c50: 01 10 00 00 04 40 00 01 10 00 00 04 40 00 01 10
6c60: 00 00 04 40 00 01 10 00 00 04 40 00 01 10 00 00
6c70: 04 40 00 01 10 00 00 04 40 00 01 10 00 00 04 40
6c80: 00 01 10 00 00 04 40 00 01 10 00 00 04 40 00 01
6c90: 10 00 00 04 40 00 01 10 00 00 04 40 00 01 10 00
6ca0: 00 04 40 00 01 10 00 00 04 40 00 01 10 00 00 04
6cb0: 40 00 01 10 00 00 04 40 00 00 01 12 20 00 04 48
6cc0: 00 01 12 20 00 04 48 00 01 12 20 00 04 48 00 01
6cd0: 12 20 00 04 48 00 01 12 20 00 04 48 00 01 12 20
6ce0: 00 04 48 00 01 12 20 00 04 48 00 01 12 20 00 04
6cf0: 48 00 01 12 20 00 04 48 00 01 12 20 00 04 48 00
6d00: 01 12 20 00 04 48 00 01 12 20 00 04 48 00 01 12
6d10: 20 00 04 48 00 01 12 20 00 04 48 00 01 12 20 00
6d20: 04 48 00 01 12 20 00 04 48 00 01 12 20 00 04 48
6d30: 00 01 12 20 00 04 48 00 01 12 20 00 04 48 00 01
6d40: 12 20 00 04 48 09 10 00 02 24 40 00 09 10 00 02
6d50: 24 40 00 09 10 00 02 24 40 00 09 10 00 02 24 40
6d60: 00 09 10 00 02 24 40 00 09 10 00 02 24 40 00 09
6d70: 10 00 02 24 40 00 09 10 00 02 24 40 00 09 10 00
6d80: 02 24 40 00 09 10 00 02 24 40 00 09 10 00 02 24
6d90: 40 00 09 10 00 02 24 40 00 09 10 00 02 24 40 00
6da0: 09 10 00 02 24 40 00 09 10 00 02 24 40 00 09 10
6db0: 00 02 24 40 00 09 10 00 02 24 40 00 09 10 00 02
6dc0: 24 40 00 09 10 00 02 24 40 00 09 10 00 02 24 40
6dd0: 00 00 00 0a 20 00 02 28 00 00 0a 20 00 02 28 00
6de0: 00 0a 20 00 02 28 00 00 0a 20 00 02 28 00 00 0a
6df0: 20 00 02 28 00 00 0a 20 00 02 28 00 00 0a 20 00
6e00: 02 28 00 00 0a 20 00 02 28 00 00 0a 20 00 02 28
6e10: 00 00 0a 20 00 02 28 00 00 0a 20 00 02 28 00 00
6e20: 0a 20 00 02 28 00 00 0a 20 00 02 28 00 00 0a 20
6e30: 00 02 28 00 00 0a 20 00 02 28 00 00 0a 20 00 02
6e40: 28 00 00 0a 20 00 02 28 00 00 0a 20 00 02 28 00
6e50: 00 0a 20 00 02 28 00 00 0a 20 00 02 28 05 50 00
6e60: 01 14 40 00 05 50 00 01 14 40 00 05 50 00 01 14
6e70: 40 00 05 50 00 01 14 40 00 05 50 00 01 14 40 00
6e80: 05 50 00 01 14 40 00 05 50 00 01 14 40 00 05 50
6e90: 00 01 14 40 00 05 50 00 01 14 40 00 05 50 00 01
6ea0: 14 40 00 05 50 00 01 14 40 00 05 50 00 01 14 40
6eb0: 00 05 50 00 01 14 40 00 05 50 00 01 14 40 00 05
6ec0: 50 00 01 14 40 00 05 50 00 01 14 40 00 05 50 00
6ed0: 01 14 40 00 05 50 00 01 14 40 00 05 50 00 01 14
6ee0: 40 00 05 50 00 01 14 40 00 00 01 1a 20 00 06 68
6ef0: 00 01 1a 20 00 06 68 00 01 1a 20 00 06 68 00 01
6f00: 1a 20 00 06 68 00 01 1a 20 00 06 68 00 01 1a 20
6f10: 00 06 68 00 01 1a 20 00 06 68 00 01 1a 20 00 06
6f20: 68 00 01 1a 20 00 06 68 00 01 1a 20 00 06 68 00
6f30: 01 1a 20 00 06 68 00 01 1a 20 00 06 68 00 01 1a
6f40: 20 00 06 68 00 01 1a 20 00 06 68 00 01 1a 20 00
6f50: 06 68 00 01 1a 20 00 06 68 00 01 1a 20 00 06 68
6f60: 00 01 1a 20 00 06 68 00 01 1a 20 00 06 68 00 01
6f70: 1a 20 00 06 68 0d 50 00 03 34 40 00 0d 50 00 03
6f80: 34 40 00 0d 50 00 03 34 40 00 0d 50 00 03 34 40
6f90: 00 0d 50 00 03 34 40 00 0d 50 00 03 34 40 00 0d
6fa0: 50 00 03 34 40 00 0d 50 00 03 34 40 00 0d 50 00
6fb0: 03 34 40 00 0d 50 00 03 34 40 00 0d 50 00 03 34
6fc0: 40 00 0d 50 00 03 34 40 00 0d 50 00 03 34 40 00
6fd0: 0d 50 00 03 34 40 00 0d 50 00 03 34 40 00 0d 50
6fe0: 00 03 34 40 00 0d 50 00 03 34 40 00 0d 50 00 03
6ff0: 34 40 00 0d 50 00 03 34 40 00 0d 50 00 03 34 40
7000: 00 00 00 06 60 00 01 18 00 00 06 60 00 01 18 00
7010: 00 06 60 00 01 18 00 00 06 60 00 01 18 00 00 06
7020: 60 00 01 18 00 00 06 60 00 01 18 00 00 06 60 00
7030: 01 18 00 00 06 60 00 01 18 00 00 06 60 00 01 18
7040: 00 00 06 60 00 01 18 00 00 06 60 00 01 18 00 00
7050: 06 60 00 01 18 00 00 06 60 00 01 18 00 00 06 60
7060: 00 01 18 00 00 06 60 00 01 18 00 00 06 60 00 01
7070: 18 00 00 06 60 00 01 18 00 00 06 60 00 01 18 00
7080: 00 06 60 00 01 18 00 00 06 60 00 01 18 03 30 00
7090: 00 0c 40 00 03 30 00 00 0c 40 00 03 30 00 00 0c
70a0: 40 00 03 30 00 00 0c 40 00 03 30 00 00 0c 40 00
70b0: 03 30 00 00 0c 40 00 03 30 00 00 0c 40 00 03 30
70c0: 00 00 0c 40 00 03 30 00 00 0c 40 00 03 30 00 00
70d0: 0c 40 00 03 30 00 00 0c 40 00 03 30 00 00 0c 40
70e0: 00 03 30 00 00 0c 40 00 03 30 00 00 0c 40 00 03
70f0: 30 00 00 0c 40 00 03 30 00 00 0c 40 00 03 30 00
7100: 00 0c 40 00 03 30 00 00 0c 40 00 03 30 00 00 0c
7110: 40 00 03 30 00 00 0c 40 00 00 01 16 60 00 05 58
7120: 00 01 16 60 00 05 58 00 01 16 60 00 05 58 00 01
7130: 16 60 00 05 58 00 01 16 60 00 05 58 00 01 16 60
7140: 00 05 58 00 01 16 60 00 05 58 00 01 16 60 00 05
7150: 58 00 01 16 60 00 05 58 00 01 16 60 00 05 58 00
7160: 01 16 60 00 05 58 00 01 16 60 00 05 58 00 01 16
7170: 60 00 05 58 00 01 16 60 00 05 58 00 01 16 60 00
7180: 05 58 00 01 16 60 00 05 58 00 01 16 60 00 05 58
7190: 00 01 16 60 00 05 58 00 01 16 60 00 05 58 00 01
71a0: 16 60 00 05 58 0b 30 00 02 2c 40 00 0b 30 00 02
71b0: 2c 40 00 0b 30 00 02 2c 40 00 0b 30 00 02 2c 40
71c0: 00 0b 30 00 02 2c 40 00 0b 30 00 02 2c 40 00 0b
71d0: 30 00 02 2c 40 00 0b 30 00 02 2c 40 00 0b 30 00
71e0: 02 2c 40 00 0b 30 00 02 2c 40 00 0b 30 00 02 2c
71f0: 40 00 0b 30 00 02 2c 40 00 0b 30 00 02 2c 40 00
7200: 0b 30 00 02 2c 40 00 0b 30 00 02 2c 40 00 0b 30
7210: 00 02 2c 40 00 0b 30 00 02 2c 40 00 0b 30 00 02
7220: 2c 40 00 0b 30 00 02 2c 40 00 0b 30 00 02 2c 40
7230: 00 00 00 0e 60 00 03 38 00 00 0e 60 00 03 38 00
7240: 00 0e 60 00 03 38 00 00 0e 60 00 03 38 00 00 0e
7250: 60 00 03 38 00 00 0e 60 00 03 38 00 00 0e 60 00
7260: 03 38 00 00 0e 60 00 03 38 00 00 0e 60 00 03 38
7270: 00 00 0e 60 00 03 38 00 00 0e 60 00 03 38 00 00
7280: 0e 60 00 03 38 00 00 0e 60 00 03 38 00 00 0e 60
7290: 00 03 38 00 00 0e 60 00 03 38 00 00 0e 60 00 03
72a0: 38 00 00 0e 60 00 03 38 00 00 0e 60 00 03 38 00
72b0: 00 0e 60 00 03 38 00 00 0e 60 00 03 38 07 70 00
72c0: 01 1c 40 00 07 70 00 01 1c 40 00 07 70 00 01 1c
72d0: 40 00 07 70 00 01 1c 40 00 07 70 00 01 1c 40 00
72e0: 07 70 00 01 1c 40 00 07 70 00 01 1c 40 00 07 70
72f0: 00 01 1c 40 00 07 70 00 01 1c 40 00 07 70 00 01
7300: 1c 40 00 07 70 00 01 1c 40 00 07 70 00 01 1c 40
7310: 00 07 70 00 01 1c 40 00 07 70 00 01 1c 40 00 07
7320: 70 00 01 1c 40 00 07 70 00 01 1c 40 00 07 70 00
7330: 01 1c 40 00 07 70 00 01 1c 40 00 07 70 00 01 1c
7340: 40 00 07 70 00 01 1c 40 00 00 01 1e 60 00 07 78
7350: 00 01 1e 60 00 07 78 00 01 1e 60 00 07 78 00 01
7360: 1e 60 00 07 78 00 01 1e 60 00 07 78 00 01 1e 60
7370: 00 07 78 00 01 1e 60 00 07 78 00 01 1e 60 00 07
7380: 78 00 01 1e 60 00 07 78 00 01 1e 60 00 07 78 00
7390: 01 1e 60 00 07 78 00 01 1e 60 00 07 78 00 01 1e
73a0: 60 00 07 78 00 01 1e 60 00 07 78 00 01 1e 60 00
73b0: 07 78 00 01 1e 60 00 07 78 00 01 1e 60 00 07 78
73c0: 00 01 1e 60 00 07 78 00 01 1e 60 00 07 78 00 01
73d0: 1e 60 00 07 78 0f 70 00 03 3c 40 00 0f 70 00 03
73e0: 3c 40 00 0f 70 00 03 3c 40 00 0f 70 00 03 3c 40
73f0: 00 0f 70 00 03 3c 40 00 0f 70 00 03 3c 40 00 0f
7400: 70 00 03 3c 40 00 0f 70 00 03 3c 40 00 0f 70 00
7410: 03 3c 40 00 0f 70 00 03 3c 40 00 0f 70 00 03 3c
7420: 40 00 0f 70 00 03 3c 40 00 0f 70 00 03 3c 40 00
7430: 0f 70 00 03 3c 40 00 0f 70 00 03 3c 40 00 0f 70
7440: 00 03 3c 40 00 0f 70 00 03 3c 40 00 0f 70 00 03
7450: 3c 40 00 0f 70 00 03 3c 40 00 0f 70 00 03 3c 40
7460: 00 e1 f9 11 29 41 59 71 89 a1 b9 d1 e9 01 19 31
7470: 49 62 63 65 66 67 68 69 6a 6b 6c 6d 6e 70 71 72
7480: 73 6d 85 9d b5 cd e5 fd 15 2d 45 5d 75 8d a5 bd
7490: d5 63 64 65 66 67 68 69 6b 6c 6d 6e 6f 70 71 72
74a0: 73 00 00 00 00 00 00 00 00 80 80 80 80 80 80 80
74b0: 80 00 00 00 00 00 00 00 00 80 80 80 80 80 80 80
74c0: 80 00 00 00 00 00 00 00 00 80 80 80 80 80 80 80
74d0: 80 00 00 00 00 00 00 00 00 80 80 80 80 80 80 80
74e0: 80 28 28 28 28 28 28 28 28 a8 a8 a8 a8 a8 a8 a8
74f0: a8 28 28 28 28 28 28 28 28 a8 a8 a8 a8 a8 a8 a8
7500: a8 28 28 28 28 28 28 28 28 a8 a8 a8 a8 a8 a8 a8
7510: a8 28 28 28 28 28 28 28 28 a8 a8 a8 a8 a8 a8 a8
7520: a8 50 50 50 50 50 50 50 50 d0 d0 d0 d0 d0 d0 d0
7530: d0 50 50 50 50 50 50 50 50 d0 d0 d0 d0 d0 d0 d0
7540: d0 50 50 50 50 50 50 50 50 d0 d0 d0 d0 d0 d0 d0
7550: d0 50 50 50 50 50 50 50 50 d0 d0 d0 d0 d0 d0 d0
7560: d0 20 24 28 2c 30 34 38 3c 20 24 28 2c 30 34 38
7570: 3c 21 25 29 2d 31 35 39 3d 21 25 29 2d 31 35 39
7580: 3d 22 26 2a 2e 32 36 3a 3e 22 26 2a 2e 32 36 3a
7590: 3e 23 27 2b 2f 33 37 3b 3f 23 27 2b 2f 33 37 3b
75a0: 3f 20 24 28 2c 30 34 38 3c 20 24 28 2c 30 34 38
75b0: 3c 21 25 29 2d 31 35 39 3d 21 25 29 2d 31 35 39
75c0: 3d 22 26 2a 2e 32 36 3a 3e 22 26 2a 2e 32 36 3a
75d0: 3e 23 27 2b 2f 33 37 3b 3f 23 27 2b 2f 33 37 3b
75e0: 3f 20 24 28 2c 30 34 38 3c 20 24 28 2c 30 34 38
75f0: 3c 21 25 29 2d 31 35 39 3d 21 25 29 2d 31 35 39
7600: 3d 22 26 2a 2e 32 36 3a 3e 22 26 2a 2e 32 36 3a
7610: 3e 23 27 2b 2f 33 37 3b 3f 23 27 2b 2f 33 37 3b
7620: 3f
6000G
That gets us pretty far but in case you haven't noticed what we've written only works for cases where DX > DY
and X0 < X1
and Y0 < Y1.
Change any one of those assumptions and our line won't get where we want it to go. Some people solve this by coding eight separate cases, deciding which one is needed and then jumping to it.
We will have a slightly better solution than that but it will have to wait until my next post. While were at it we will also do some performance testing against other commercial and non-commercial DHR solutions, talk about further optimization
and do some work with pseudo-3d demos.