A better interface
Perhaps you've noticed that all these drawing routines we've developed require a fair amount of memory to do anything useful. Just look at this code snippet:
*Draw a line from (0,10) to (20,25) LDA #$00 STA X0 LDA #$0A STA Y0 LDA #$14 STA X1 LDA #$19 STA Y1 JSR NXTLINEEach LDA and STA costs us two bytes - that sixteen in total! Add in the JSR and we are up to nineteen bytes just to draw a single line! Our previous demo programs hid this expense by drawing only simple shapes (filling the screen with horizontal lines) and by using loops but if we ever want to make something more complex we are going to need a better approach.
Penguin had the right idea
The Graphics Magician, despite it's flaws in the speed department solved one problem well. People needed a better way to store Hi-res pictures and storing them as a series of line drawing commands is an idea that definitely saves on memory. So as any great artist does with any great idea - we're going to swipe it!
While we're in a larcenous mood let's steal another memory saving idea used by the ProDOS MLI (machine language interface) - storing our parameters in a data block located after we call our routine. Here's an example of what such a system would look like:
While we're in a larcenous mood let's steal another memory saving idea used by the ProDOS MLI (machine language interface) - storing our parameters in a data block located after we call our routine. Here's an example of what such a system would look like:
JSR DHDRAWAPI DB 10 10 10 20 ;Draw a line from (16,16) to (16,32) DB 10 20 20 20 ;Draw a line from (16,32) to (32,32) DB 20 20 20 10 ;Draw a line from (32,32) to (32,16) DB 20 10 10 10 ;Draw a line from (32,16) to (16,16) DB 255 ;End of data...and like magic we just cut our memory usage by 75%!
There's still room for improvement though! For example, notice how each line starts where the previous line left off? We can save more memory by creating a mode where we automatically treat the previous end of line (X1,Y1) as the beginning of the next (X0,Y0) leaving us only having to define our new endpoint.
To accomplish this we will add a "command" byte at the beginning of each line draw. If the byte is $00 then we are drawing a line from X0,Y0 to X1,Y1 and the next four bytes define the co-ordinates. If the byte is $01, then we are drawing a line from the previous X1,Y1 to the co-ordinate we provide. So our code will look something like this:
JSR DHDRAWAPI DB 00 10 10 10 20 ;Draw a line from (10,10) to (10,20) DB 01 20 20 ;Continue line to (20,20) DB 01 20 10 ;Continue line to (20,10) DB 01 10 10 ;Continue line to (10,10) DB 255 ;End of dataFinally, let's add a way of changing the drawing colour in the same block of data. The Graphics Magician uses single byte codes to accomplish this which again seems like a prime idea to appropriate! We will implement it int the following way:
Command Byte | Colour Name | Bitpattern |
---|---|---|
$10 | Black | 0000 |
$11 | Magenta | 0001 |
$12 | Brown | 0010 |
$13 | Orange | 0011 |
$14 | Dark Green | 0100 |
$15 | Grey 1 | 0101 |
$16 | Yellow | 0110 |
$17 | Green | 0111 |
$18 | Dark Blue | 1000 |
$19 | Violet | 1001 |
$1A | Grey 2 | 1010 |
$1B | Pink | 1011 |
$1C | Medium Blue | 1100 |
$1D | Light Blue | 1101 |
$1E | Aqua | 1110 |
$1F | White | 1111 |
...and our image data will look like this:
JSR DHDRAWAPI DB E1 ;Set colour to magenta DB 00 10 10 10 20 ;Draw a line from (10,10) to (10,20) DB E6 ;Set colour to green DB 01 20 20 ;Continue line to (20,20) DB EB ;Set colour to medium blue DB 01 20 10 ;Continue line to (20,10) DB EF ;Set colour to white DB 01 10 10 ;Continue line to (10,10) DB 255 ;End of dataNow we're talking! Drawing four lines, in four different colours would have cost us eighty-eight bytes! Using our new API we can do it all in just nineteen! Not only that but we can save and load our pictures as binary files — just like the Graphics Magician!
In fact, all we would need to do to achieve most of its functionality is add a few more commands such as plotting single points and performing flood fills.
So let's implement this!
Doing this magic is easier than you think. Every time we do a JSR the address of the very next byte is stored on the stack. The stack, in case you're not familiar with it is 256 bytes of memory from $100-$1FF. Located just above the zero page. Bytes are put on to the stack starting at the bottom ($100) and new data is added growing upward toward $1FF. The most common way to put data into this are of memory is by using a 6502 instruction like PHA. This takes the byte in the accumulator and puts in the next available stack location. Putting information on to the stack is called "pushing". The 6502 keeps track of which stack location we used last through a register called the stack pointer (SP). When you push something on the stack, it increments the SP and then stores the data in this new spot. When you tell the CPU to do a JSR it stores the address you made the call from by pushing both bytes of it onto the stack. Later on, when we do an RTS these bytes are retrieved — or "popped" — from the stack. The is one of the reasons that a JSR/RTS consumes so many clock cycles.
You can't read the stack pointer directly but you can copy it into the X register by using the TSX instruction. Armed with this knowledge we can start building our API by doing the following.
DHDRAWAPI TSX ;Move stack pointer to X LDA $101,X ;Load high-byte and low-byte of the STA CP ;return address at the top of the stack LDA $102,X ;Store it in a ZP location which we STA CP+1 ;will call CP (command pointer)Here we simply copy the address pushed onto the stack by a JSR DHDRAWAPI into a couple of zero page locations which we will call the Command Pointer or CP. As we move through our block of drawing commands, we will keep moving CP to point to the address of the next byte. Then, when we're finished and want to get back to our program all we need to do is copy the address in CP back to the stack — overwriting our original address — and then perform an RTS. Like so!
ENDCMD TSX CLC LDA CP ;Add one to the CP and overwrite ADC #$01 ;the return address in the STA $101,X ;stack. LDA CP+1 ;Now when we RTS the CPU will ADC #$00 ;start executing just after our STA $102,X ;block of data RTS
Before we put this all together to make our DHDRAWAPI we need to first do some more code management but before we get into that here's just a taste of how you can roll your own MLI style API. This one has exactly two commands. The first one, $00 will take the next byte and output it on the text screen. The second command $01 will stop processing and return to the calling program.
*API.TEST *Simple MLI-style API *Jonathan Graham/Battlestations *Free for non-commercial use with attribution * XC ORG $6000 CP EQU $F6 JSR TEXTAPI ;Call our API *Data bytes which just display the numbers from 0-5 DB $00,$01,$00,$02,$00,$03,$00,$04,$00,$05 DB $01 RTS TEXTAPI TSX ;Move stack pointer to X LDA $101,X ;Load high-byte and low-byte of the STA CP ;return address at the top of the stack LDA $102,X ;Store it in a ZP location which we STA CP+1 ;will call CP (command pointer) NXTCMD LDY #$01 ;Grab the next byte which LDA (CP),Y ;should be our first command TAX ;Lookup the distance between LDA CMDTAB,X ;our jump point and the routine STA CMDJMP+1 ;Modify the BRA to go to our routine CMDJMP BRA ENDCMD ;Do our routine PRINTCHR INY ;CMD 00 - print byte LDA (CP),Y JSR $FDDA CLC LDA #$02 ;Length of command ADC CP ;Move the CP to the next STA CP ;command LDA CP+1 ADC #$00 STA CP+1 BRA NXTCMD ENDCMD TSX ;CMD 01 - return to program CLC LDA CP ;Add one to the CP and overwrite ADC #$01 ;the return address in the STA $101,X ;stack. LDA CP+1 ;Now when we RTS the CPU will ADC #$00 ;start executing just after our STA $102,X ;block of data RTS CMDTAB DB PRINTCHR-PRINTCHR,ENDCMD-PRINTCHR
For efficiency, we've implemented each command as part of a jump table. This is a data structure where a number of different routines can be called from the same position using the value in a register. This avoids the cumbersome way we often have to implement a series of "IF...THEN" statements in assembly by doing a series of compares and branches such as...
LDA DATA ;Grab some piece of data CMP #$01 ;Is it a one? BEQ DOFIRST ;Yes, do the first routine CMP #$02 ;Is it a two? BEQ DOSECOND ;Yes, do the second routine CMP #$03 ;Is it a three? BEQ DOTHIRD ;Yes, do third routine BNE DEFAULT ;It's none of these, do something else
As you can see in our API demo. We use self-modifying code to alter the parameter of a BRA instruction. Since BRA requires a parameter telling us the distance to the instruction we want to branch to. We create a table which contains these distances by telling the assembler to subtract the memory location we are starting at (CMDJMP) from the memory location we want to jump to (PRINTCHR or ENDCMD).
It's worth noting that this approach has one important limitation. Branch instructions can only move us 127 locations forward or 128 locations backward. So we will never be able to jump to a label that's more than 127 bytes away. That said, we could always switch to using self-modifying code to alter the destination of a JMP instruction or even use the 65C02 instruction JMP (-some address-,X) which is designed to implement exactly this kind of system.
Our current implementation is faster than either of those two approaches, so we'll stick with it for now. Oh...and here's a binary version of the API demo you can paste into an emulator
Our current implementation is faster than either of those two approaches, so we'll stick with it for now. Oh...and here's a binary version of the API demo you can paste into an emulator
CALL -151
6000: 20 0F 60 00 01 00 02 00 03 00 04 00 05 01 60 BA
6010: BD 01 01 85 AA BD 02 01 85 AB A0 01 B1 AA AA BD
6020: 4C 60 8D 26 60 80 15 C8 B1 AA 20 DA FD 18 A9 02
6030: 65 AA 85 AA A5 AB 69 00 85 AB 80 DE BA A5 AA 69
6040: 01 9D 01 01 A5 AB 69 00 9D 02 01 60 00 15
6000G
More code management
We've been using the pseudo op-code PUT to make our source code easier to read and to allow us the option of re-using parts of it in other projects. Our line drawing routine is now sufficiently large that it deserves a module of it's own. However the Merlin assembler won't let us PUT files that have PUT statements in them already. Since our line drawing algorithm uses PUT to insert our plotting routine we're going to have to make some changes.
There is more than one way to handle this problem (especially if you count using an assembler without this limitation). For today we're going to take the easiest path and simply combine the line drawing routine and the plotting routine into a single file called DH.LINE.
*DH.LINE *8 bit Bresenham DHR line drawing algorithim *Requires: DH.TABLES *Jonathan Graham/Battlestations *Free for non-commercial use with attribution * LDX X0 LDY Y0 STY KEEPY ;Initialize Y preserving spot LDA Y1 ;Calculate DY as Y1-Y0 SEC SBC Y0 BCC Y0BIGGER STA DY LDA #$C8 ;SMC: Insert INY at CHGYA/CHGYB BRA CHGY Y0BIGGER EOR #$FF STA DY LDA #$88 ;SMC: Insert DEY at CHGYA/CHGYB CHGY STA CHGYA STA CHGYB LDA X1 ;Calculate DX as X1-X0 SEC SBC X0 BCC X0BIGGER STA DX LDA #$E8 ;SMC: Insert INX at CHGXA/CHGXB BRA CHGX X0BIGGER EOR #$FF STA DX LDA #$CA ;SMC: Insert DEX at CHGXA/CHGXB CHGX STA CHGXA STA CHGXB LDA DX CMP DY BCS DXLINE DYLINE LDA DY ;Set EPSILON to 255-(DY/2) LSR EOR #$FF STA EPSILON *DH.ROWSET Begins here DYHORZ 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 STY KEEPY *DH.PLOT Begins here PLOTDYL 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 LDY KEEPY CPY Y1 ;Are we done? BEQ ENDLINE CHGYA INY ;Move along major axis LDA EPSILON ;Epsilon = Epsilon + DX CLC ADC DX STA EPSILON BCC DYHORZ ;NOTE: we've changed Y so we need to call DH.ROWSET SEC ;If epsilon has rolled over subtract DX SBC DY STA EPSILON CHGXA INX ;Move along minor axis BRA DYHORZ DXLINE LDA DX ;Set EPSILON to 255-(DX/2) LSR EOR #$FF STA EPSILON *DH.ROWSET Begins here DXVERT 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 *DH.PLOT Begins here DXHORZ 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 CPX X1 ;Are we done? BEQ ENDLINE CHGXB INX ;Move along major axis LDA EPSILON ;Epsilon = Epsilon + DY CLC ADC DY STA EPSILON BCC DXHORZ ;If Epsilon hasn't rolled over move to next point SEC ;If epsilon has rolled over subtract DX SBC DX STA EPSILON LDY KEEPY CHGYB INY ;Move along minor axis STY KEEPY BRA DXVERT ENDLINE RTS
Clearing things up
One more thing we need before we start writing some actually useful DHR programs. We need an efficient way to clear the screen. There are many ways to do this, all of which make the classic trade off between speed and memory. I'm going to select one of my favorites since it's virtually instantaneous ( < 0.05s ), consumes a mere 113 bytes, and as a bonus you can clear the screen black, white or grey by setting the accumulator to $00,$FF or $55 respectively prior to calling it. Create a new file in your assembler, paste in the following source code and save it as DH.CLEAR.
* DH.CLEAR *Jonathan Graham/Battlestations *Free for non-commercial use with attribution * STA PAGE1 ;Select MAIN memory LDY #$02 ;Counter for MAIN/AUX ]LOOPA LDX #$00 ;Start at byte 0 ]LOOPB STA $2000,X Cycle through STA $2100,X ;each of the 32 - 256 byte STA $2200,X ;blocks which make up STA $2300,X ;Hi-res page 1 STA $2400,X STA $2500,X STA $2600,X STA $2700,X STA $2800,X STA $2900,X STA $2A00,X STA $2B00,X STA $2C00,X STA $2D00,X STA $2E00,X STA $2F00,X STA $3000,X STA $3100,X STA $3200,X STA $3300,X STA $3400,X STA $3500,X STA $3600,X STA $3700,X STA $3800,X STA $3900,X STA $3A00,X STA $3B00,X STA $3C00,X STA $3D00,X STA $3E00,X STA $3F00,X INX BNE ]LOOPB LSR ;Turn 55 into 2A otherwise do nothing DEY STA PAGE2 ;Now do it all over again BNE ]LOOPA ;in AUX memory
Making our API
All right, now that we have that sorted out. It's a relatively simple matter to put everything we've learned together to make our DHDRAWAPI routine a reality. The source code below is pretty self-explanatory and includes an example drawing of a triangle.
*DH.API *DHLINE/SETDCOLOR using MLI-style API *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 CP EQU $F5 X0 EQU $F7 Y0 EQU $F8 X1 EQU $F9 Y1 EQU $FA DX EQU $FB DY EQU $FC EPSILON EQU $FD KEEPY EQU $FE PUT DH.INIT LDA #$00 ;Clear screen to black PUT DH.CLEAR JSR DHDRAWAPI ;Call our API DB $11 ;Draw with Magenta DB $00,5,181,70,10 ;Draw from (4,181) to (70,10) DB $01,134,181 ;Continue drawing to (134,181) DB $01,4,181 ;Continue drawing to (4,181) DB $02 ;End of data RTS DHDRAWAPI TSX ;Move stack pointer to X LDA $101,X ;Load high-byte and low-byte of the STA CP ;return address at the top of the stack LDA $102,X ;Store it in a ZP location which we STA CP+1 ;will call CP (command pointer) NXTCMD LDY #$01 ;Grab the next byte which LDA (CP),Y ;should be our first command TAX ;Lookup the distance between LDA CMDTAB,X ;our jump point and the routine STA CMDJMP+1 ;Modify the BRA to go to our routine CMDJMP BRA ENDCMD ;Do our routine DRAWLIN INY ;Load each parameter LDA (CP),Y ;and store it in the variables STA X0 ; X0,Y0,X1,Y1 for DHLINE to use. INY LDA (CP),Y STA Y0 INY LDA (CP),Y STA X1 INY LDA (CP),Y STA Y1 JSR DHLINE CLC LDA #$05 ;Length of command ADC CP ;Move the CP to the next STA CP ;command LDA CP+1 ADC #$00 STA CP+1 BRA NXTCMD CONTLIN LDA X1 ;Copy X1 to X0 STA X0 ;and Y1 to Y0. LDA Y1 ;Then get the other two STA Y0 ;parameters and store INY ;them as X1 and Y1 LDA (CP),Y STA X1 INY LDA (CP),Y STA Y1 JSR DHLINE CLC LDA #$03 ;Length of command ADC CP ;Move the CP to the next STA CP ;command LDA CP+1 ADC #$00 STA CP+1 BRA NXTCMD CHNGCLR LDA (CP),Y AND #001111 ;Mask the upper four bits JSR SETDCOLOR CLC LDA #$01 ;Length of command ADC CP ;Move the CP to the next STA CP ;command LDA CP+1 ADC #$00 STA CP+1 BRA NXTCMD ENDCMD TSX CLC LDA CP ;Add one to the CP and overwrite ADC #$01 ;the return address in the STA $101,X ;stack. LDA CP+1 ;Now when we RTS the CPU will ADC #$00 ;start executing just after our STA $102,X ;block of data RTS CMDTAB DB DRAWLIN-DRAWLIN,CONTLIN-DRAWLIN LUP 14 DB ENDCMD-DRAWLIN --^ LUP 16 DB CHNGCLR-DRAWLIN --^ DHLINE PUT DH.LINE SETDCOLOR TAY PUT DH.COLOUR ]ORMAIN EQU PLOTDYL+13 ]ORAUX EQU PLOTDYL+31 PUT DH.COLOUR RTS PUT DH.TABLES
So what can we do with all that? Quite a bit actually! Use it as the basis of a graphical adventure game in the tradition of Transylvania! Write 3D RPGs like Wizardry! These are all feasible. Just to show what can be done I've bundled the API with a drawing of moderate complexity. You can get it here:
The package is about 7.2K and renders in about 0.72 seconds. The drawing takes up about 1K of that. Which, in all honesty is still a little on the high side for the purposes of developing graphical adventures but I outline some strategies for getting these sizes down even further later on.
CALL-151
6000: 8D 50 C0 8D 57 C0 8D 52 C0 8D 5E C0 8D 0D C0 8D
6010: 01 C0 A9 00 8D 54 C0 A0 02 A2 00 9D 00 20 9D 00
6020: 21 9D 00 22 9D 00 23 9D 00 24 9D 00 25 9D 00 26
6030: 9D 00 27 9D 00 28 9D 00 29 9D 00 2A 9D 00 2B 9D
6040: 00 2C 9D 00 2D 9D 00 2E 9D 00 2F 9D 00 30 9D 00
6050: 31 9D 00 32 9D 00 33 9D 00 34 9D 00 35 9D 00 36
6060: 9D 00 37 9D 00 38 9D 00 39 9D 00 3A 9D 00 3B 9D
6070: 00 3C 9D 00 3D 9D 00 3E 9D 00 3F E8 D0 9D 4A 88
6080: 8D 55 C0 D0 94 20 15 65 11 00 69 00 8B 00 01 8B
6090: BF 01 69 BF 01 69 00 17 00 7A 20 7A 8F 00 79 21
60A0: 79 8F 00 7B 21 7B 8F 00 78 22 78 8F 00 7C 22 7C
60B0: 8F 15 00 74 8A 74 8F 00 80 8A 80 8F 00 75 8C 75
60C0: 8F 00 7F 8C 7F 8F 00 76 8E 76 8F 00 7E 8E 7E 8F
60D0: 00 74 90 80 90 00 74 91 80 91 00 7A 92 7A 9B 00
60E0: 7B 92 7B 9B 00 79 92 79 9B 00 78 9C 7C 9C 18 00
60F0: 6B 05 6B 14 00 6B 18 6B 1C 00 6C 04 6C 13 00 6C
6100: 19 6C 1D 00 6D 03 6D 05 00 6D 0F 6D 12 00 6D 1B
6110: 6D 1E 00 6E 02 6E 07 00 6E 0E 6E 1F 00 6F 02 6F
6120: 07 00 6F 0D 6F 1F 00 71 02 71 1A 00 72 03 72 1B
6130: 00 73 19 73 1B 00 74 03 74 1B 00 75 03 75 1B 00
6140: 76 19 76 1B 00 77 03 77 1A 00 78 02 78 1A 00 7A
6150: 03 7A 1A 00 7B 02 7B 1B 00 7C 02 7C 03 00 7C 19
6160: 7C 1B 00 7D 02 7D 1B 00 7E 03 7E 1A 00 80 02 80
6170: 1B 00 81 02 81 1B 00 82 02 82 03 00 82 0C 82 0F
6180: 00 83 02 83 0C 00 83 0E 83 1B 00 84 03 84 0B 00
6190: 84 0F 84 1B 00 86 02 86 1F 00 87 02 87 1F 00 88
61A0: 03 88 05 00 88 1B 88 1E 00 89 04 89 1D 00 8A 05
61B0: 8A 1C 00 6C A3 6C BD 00 6D A2 6D BD 00 6E A1 6E
61C0: A3 00 6E AD 6E AF 00 6F A0 6F A5 00 6F AC 6F B0
61D0: 00 70 A0 70 A5 00 70 AB 70 B1 00 72 A5 72 BC 00
61E0: 73 A4 73 BD 00 74 A4 74 A5 00 74 BB 74 BD 00 75
61F0: A4 75 BD 00 76 A5 76 BC 00 78 A4 78 BD 00 79 A4
6200: 79 BD 00 7A A4 7A A5 00 7A AE 7A B1 00 7B A4 7B
6210: AE 00 7B B0 7B BD 00 7C A5 7C AD 00 7C B1 7C BD
6220: 00 7E A5 7E BC 00 7F A4 7F BD 00 80 A4 80 A5 00
6230: 80 BB 80 BD 00 81 A4 81 AA 00 81 AF 81 BD 00 82
6240: A5 82 AA 00 82 AF 82 BC 00 83 AF 83 B1 00 85 A0
6250: 85 BD 00 86 A0 86 BD 00 87 A1 87 A3 00 87 AD 87
6260: AF 00 87 B9 87 BC 00 88 A2 88 A4 00 88 AC 88 B0
6270: 00 88 B8 88 BB 00 89 A3 89 A5 00 89 AB 89 B1 00
6280: 89 B7 89 BA 1F 00 00 00 10 1F 01 10 A3 01 00 BF
6290: 00 69 1F 59 1F 01 59 A3 01 69 A3 00 10 3C 20 3C
62A0: 01 20 84 01 10 84 00 59 1F 49 3C 01 49 84 01 59
62B0: A3 00 20 3C 29 4D 01 29 73 01 20 84 00 49 4C 40
62C0: 4C 01 40 73 01 49 73 15 00 2A 59 3F 59 00 2A 65
62D0: 3F 65 00 2E 59 2E 65 00 3A 59 3A 65 17 00 35 68
62E0: 39 68 00 33 69 3B 69 00 32 6A 3C 6A 00 31 6B 3D
62F0: 6B 00 30 6C 3E 6C 00 2F 6D 3F 6D 00 2E 6E 40 6E
6300: 00 2D 6F 41 6F 00 2D 70 41 70 00 2C 71 42 71 00
6310: 2C 72 42 72 00 2B 73 43 73 00 2B 74 43 74 00 2A
6320: 75 44 75 00 2A 76 44 76 00 2A 77 44 77 00 2A 78
6330: 44 78 00 2A 79 44 79 00 2A 7A 44 79 00 2A 7B 44
6340: 7B 00 2A 7C 44 7C 00 2A 7D 44 7D 00 2A 7E 44 7E
6350: 00 2A 7F 44 7F 00 2A 80 44 80 00 2A 81 44 81 00
6360: 2A 82 44 82 00 2B 83 43 83 00 2B 84 43 84 00 2B
6370: 85 43 85 00 2C 86 42 86 00 2C 87 42 87 00 2D 88
6380: 41 88 00 2D 89 41 89 00 2E 8A 40 8A 00 2F 8B 3F
6390: 8B 00 30 8C 3E 8C 00 30 8D 3E 8D 00 31 8E 3D 8E
63A0: 00 32 8F 3C 8F 00 33 90 3B 90 00 33 91 3B 91 00
63B0: 34 92 3A 92 00 35 93 39 93 00 35 94 39 94 11 00
63C0: 30 95 3E 95 00 31 96 3D 96 00 32 97 3C 97 00 33
63D0: 98 3B 98 00 34 99 3A 99 00 35 9A 39 9A 00 36 9B
63E0: 38 9B 00 37 9C 37 9C 00 2D BA 41 BA 00 2D BC 41
63F0: BC 00 34 8C 3A 8C 00 37 8D 37 8D 1F 00 35 8D 36
6400: 8D 00 38 8D 39 8D 00 36 8E 36 8E 00 38 8E 38 8E
6410: 12 00 2E 96 2E A7 00 2F 96 2F A8 00 30 96 30 A9
6420: 00 31 97 31 9D 00 32 98 32 B1 00 33 99 33 B1 00
6430: 34 9A 34 B1 00 35 9B 35 B1 00 36 9C 36 B1 00 37
6440: 9D 37 B1 00 38 9C 38 B1 00 39 9B 39 B1 00 3A 9A
6450: 3A B1 00 3B 99 3B B1 00 3C 98 3C B1 00 3D 97 3D
6460: 9D 00 3E 96 3E A9 00 3F 96 3F A8 00 40 97 40 A7
6470: 00 31 B2 3D B2 00 31 B3 3D B3 00 30 B4 3E B4 00
6480: 30 B5 3E B5 00 2F B6 3F B6 00 2E B7 40 B7 00 2E
6490: B8 40 B8 00 2D B9 41 B9 00 2D BB 41 BB 00 2D BD
64A0: 41 BD 00 2D BE 41 BE 00 2D BF 41 BF 16 00 36 84
64B0: 38 84 00 35 85 39 85 00 35 86 39 86 00 35 87 39
64C0: 87 00 36 88 38 88 10 00 36 86 38 86 00 37 85 37
64D0: 87 1C 00 33 83 36 80 00 36 80 38 80 01 3B 83 1B
64E0: 00 3B 6D 36 72 01 36 75 00 34 7C 2F 78 01 2D 74
64F0: 00 2F 78 2C 77 00 3C 76 40 72 1D 00 3B 72 3B 7C
6500: 01 40 7C 01 43 79 01 43 77 00 35 74 33 70 00 2F
6510: 72 33 73 02 60 BA BD 01 01 85 F5 BD 02 01 85 F6
6520: A0 01 B1 F5 AA BD 9E 65 8D 2C 65 80 60 C8 B1 F5
6530: 85 F7 C8 B1 F5 85 F8 C8 B1 F5 85 F9 C8 B1 F5 85
6540: FA 20 BE 65 18 A9 05 65 F5 85 F5 A5 F6 69 00 85
6550: F6 80 CD A5 F9 85 F7 A5 FA 85 F8 C8 B1 F5 85 F9
6560: C8 B1 F5 85 FA 20 BE 65 18 A9 03 65 F5 85 F5 A5
6570: F6 69 00 85 F6 80 A9 B1 F5 29 0F 20 9B 66 18 A9
6580: 01 65 F5 85 F5 A5 F6 69 00 85 F6 80 93 BA 18 A5
6590: F5 69 01 9D 01 01 A5 F6 69 00 9D 02 01 60 00 26
65A0: 60 60 60 60 60 60 60 60 60 60 60 60 60 60 4A 4A
65B0: 4A 4A 4A 4A 4A 4A 4A 4A 4A 4A 4A 4A 4A 4A A6 F7
65C0: A4 F8 84 FE A5 FA 38 E5 F8 90 06 85 FC A9 C8 80
65D0: 06 49 FF 85 FC A9 88 8D 39 66 8D 95 66 A5 F9 38
65E0: E5 F7 90 06 85 FB A9 E8 80 06 49 FF 85 FB A9 CA
65F0: 8D 48 66 8D 84 66 A5 FB C5 FC B0 4F A5 FC 4A 49
6600: FF 85 FD B9 BD 7A 85 1D B9 7D 7B 85 1E 84 FE BC
6610: CD 66 30 0D 8D 54 C0 B1 1D 3D E5 67 1D 8D 6F 91
6620: 1D BC 59 67 30 0D 8D 55 C0 B1 1D 3D 71 68 1D 19
6630: 70 91 1D A4 FE C4 FA F0 61 C8 A5 FD 18 65 FB 85
6640: FD 90 C0 38 E5 FC 85 FD E8 80 B8 A5 FB 4A 49 FF
6650: 85 FD B9 BD 7A 85 1D B9 7D 7B 85 1E BC CD 66 30
6660: 0D 8D 54 C0 B1 1D 3D E5 67 1D 8D 6F 91 1D BC 59
6670: 67 30 0D 8D 55 C0 B1 1D 3D 71 68 1D 19 70 91 1D
6680: E4 F9 F0 16 E8 A5 FD 18 65 FC 85 FD 90 CE 38 E5
6690: FB 85 FD A4 FE C8 84 FE 80 B8 60 A8 B9 7D 7A 8D
66A0: 6A 66 B9 8D 7A 8D 6B 66 B9 9D 7A 8D 7C 66 B9 AD
66B0: 7A 8D 7D 66 B9 7D 7A 8D 1D 66 B9 8D 7A 8D 1E 66
66C0: B9 9D 7A 8D 2F 66 B9 AD 7A 8D 30 66 60 FF 00 00
66D0: 00 FF 01 01 FF 02 02 02 FF 03 03 FF 04 04 04 FF
66E0: 05 05 FF 06 06 06 FF 07 07 FF 08 08 08 FF 09 09
66F0: FF 0A 0A 0A FF 0B 0B FF 0C 0C 0C FF 0D 0D FF 0E
6700: 0E 0E FF 0F 0F FF 10 10 10 FF 11 11 FF 12 12 12
6710: FF 13 13 FF 14 14 14 FF 15 15 FF 16 16 16 FF 17
6720: 17 FF 18 18 18 FF 19 19 FF 1A 1A 1A FF 1B 1B FF
6730: 1C 1C 1C FF 1D 1D FF 1E 1E 1E FF 1F 1F FF 20 20
6740: 20 FF 21 21 FF 22 22 22 FF 23 23 FF 24 24 24 FF
6750: 25 25 FF 26 26 26 FF 27 27 00 00 FF 01 01 01 FF
6760: 02 02 FF 03 03 03 FF 04 04 FF 05 05 05 FF 06 06
6770: FF 07 07 07 FF 08 08 FF 09 09 09 FF 0A 0A FF 0B
6780: 0B 0B FF 0C 0C FF 0D 0D 0D FF 0E 0E FF 0F 0F 0F
6790: FF 10 10 FF 11 11 11 FF 12 12 FF 13 13 13 FF 14
67A0: 14 FF 15 15 15 FF 16 16 FF 17 17 17 FF 18 18 FF
67B0: 19 19 19 FF 1A 1A FF 1B 1B 1B FF 1C 1C FF 1D 1D
67C0: 1D FF 1E 1E FF 1F 1F 1F FF 20 20 FF 21 21 21 FF
67D0: 22 22 FF 23 23 23 FF 24 24 F4 25 25 25 FF 26 26
67E0: FF 27 27 27 FF 7F 7E 61 1F 7F 78 07 7F 7E 61 1F
67F0: 7F 78 07 7F 7E 61 1F 7F 78 07 7F 7E 61 1F 7F 78
6800: 07 7F 7E 61 1F 7F 78 07 7F 7E 61 1F 7F 78 07 7F
6810: 7E 61 1F 7F 78 07 7F 7E 61 1F 7F 78 07 7F 7E 61
6820: 1F 7F 78 07 7F 7E 61 1F 7F 78 07 7F 7E 61 1F 7F
6830: 78 07 7F 7E 61 1F 7F 78 07 7F 7E 61 1F 7F 78 07
6840: 7F 7E 61 1F 7F 78 07 7F 7E 61 1F 7F 78 07 7F 7E
6850: 61 1F 7F 78 07 7F 7E 61 1F 7F 78 07 7F 7E 61 1F
6860: 7F 78 07 7F 7E 61 1F 7F 78 07 7F 7E 61 1F 7F 78
6870: 07 70 0F 7F 7C 43 3F 7F 70 0F 7F 7C 43 3F 7F 70
6880: 0F 7F 7C 43 3F 7F 70 0F 7F 7C 43 3F 7F 70 0F 7F
6890: 7C 43 3F 7F 70 0F 7F 7C 43 3F 7F 70 0F 7F 7C 43
68A0: 3F 7F 70 0F 7F 7C 43 3F 7F 70 0F 7F 7C 43 3F 7F
68B0: 70 0F 7F 7C 43 3F 7F 70 0F 7F 7C 43 3F 7F 70 0F
68C0: 7F 7C 43 3F 7F 70 0F 7F 7C 43 3F 7F 70 0F 7F 7C
68D0: 43 3F 7F 70 0F 7F 7C 43 3F 7F 70 0F 7F 7C 43 3F
68E0: 7F 70 0F 7F 7C 43 3F 7F 70 0F 7F 7C 43 3F 7F 70
68F0: 0F 7F 7C 43 3F 7F 70 0F 7F 7C 43 3F 7F 00 00 00
6900: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
6910: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
6920: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
6930: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
6940: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
6950: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
6960: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
6970: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
6980: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
6990: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
69A0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
69B0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
69C0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
69D0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
69E0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
69F0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
6A00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
6A10: 00 00 00 00 00 00 01 10 00 00 04 40 00 01 10 00
6A20: 00 04 40 00 01 10 00 00 04 40 00 01 10 00 00 04
6A30: 40 00 01 10 00 00 04 40 00 01 10 00 00 04 40 00
6A40: 01 10 00 00 04 40 00 01 10 00 00 04 40 00 01 10
6A50: 00 00 04 40 00 01 10 00 00 04 40 00 01 10 00 00
6A60: 04 40 00 01 10 00 00 04 40 00 01 10 00 00 04 40
6A70: 00 01 10 00 00 04 40 00 01 10 00 00 04 40 00 01
6A80: 10 00 00 04 40 00 01 10 00 00 04 40 00 01 10 00
6A90: 00 04 40 00 01 10 00 00 04 40 00 01 10 00 00 04
6AA0: 40 08 00 00 02 20 00 00 08 00 00 02 20 00 00 08
6AB0: 00 00 02 20 00 00 08 00 00 02 20 00 00 08 00 00
6AC0: 02 20 00 00 08 00 00 02 20 00 00 08 00 00 02 20
6AD0: 00 00 08 00 00 02 20 00 00 08 00 00 02 20 00 00
6AE0: 08 00 00 02 20 00 00 08 00 00 02 20 00 00 08 00
6AF0: 00 02 20 00 00 08 00 00 02 20 00 00 08 00 00 02
6B00: 20 00 00 08 00 00 02 20 00 00 08 00 00 02 20 00
6B10: 00 08 00 00 02 20 00 00 08 00 00 02 20 00 00 08
6B20: 00 00 02 20 00 00 08 00 00 02 20 00 00 00 00 08
6B30: 00 00 02 20 00 00 08 00 00 02 20 00 00 08 00 00
6B40: 02 20 00 00 08 00 00 02 20 00 00 08 00 00 02 20
6B50: 00 00 08 00 00 02 20 00 00 08 00 00 02 20 00 00
6B60: 08 00 00 02 20 00 00 08 00 00 02 20 00 00 08 00
6B70: 00 02 20 00 00 08 00 00 02 20 00 00 08 00 00 02
6B80: 20 00 00 08 00 00 02 20 00 00 08 00 00 02 20 00
6B90: 00 08 00 00 02 20 00 00 08 00 00 02 20 00 00 08
6BA0: 00 00 02 20 00 00 08 00 00 02 20 00 00 08 00 00
6BB0: 02 20 00 00 08 00 00 02 20 04 40 00 01 10 00 00
6BC0: 04 40 00 01 10 00 00 04 40 00 01 10 00 00 04 40
6BD0: 00 01 10 00 00 04 40 00 01 10 00 00 04 40 00 01
6BE0: 10 00 00 04 40 00 01 10 00 00 04 40 00 01 10 00
6BF0: 00 04 40 00 01 10 00 00 04 40 00 01 10 00 00 04
6C00: 40 00 01 10 00 00 04 40 00 01 10 00 00 04 40 00
6C10: 01 10 00 00 04 40 00 01 10 00 00 04 40 00 01 10
6C20: 00 00 04 40 00 01 10 00 00 04 40 00 01 10 00 00
6C30: 04 40 00 01 10 00 00 04 40 00 01 10 00 00 04 40
6C40: 00 01 10 00 00 00 01 18 00 00 06 60 00 01 18 00
6C50: 00 06 60 00 01 18 00 00 06 60 00 01 18 00 00 06
6C60: 60 00 01 18 00 00 06 60 00 01 18 00 00 06 60 00
6C70: 01 18 00 00 06 60 00 01 18 00 00 06 60 00 01 18
6C80: 00 00 06 60 00 01 18 00 00 06 60 00 01 18 00 00
6C90: 06 60 00 01 18 00 00 06 60 00 01 18 00 00 06 60
6CA0: 00 01 18 00 00 06 60 00 01 18 00 00 06 60 00 01
6CB0: 18 00 00 06 60 00 01 18 00 00 06 60 00 01 18 00
6CC0: 00 06 60 00 01 18 00 00 06 60 00 01 18 00 00 06
6CD0: 60 0C 40 00 03 30 00 00 0C 40 00 03 30 00 00 0C
6CE0: 40 00 03 30 00 00 0C 40 00 03 30 00 00 0C 40 00
6CF0: 03 30 00 00 0C 40 00 03 30 00 00 0C 40 00 03 30
6D00: 00 00 0C 40 00 03 30 00 00 0C 40 00 03 30 00 00
6D10: 0C 40 00 03 30 00 00 0C 40 00 03 30 00 00 0C 40
6D20: 00 03 30 00 00 0C 40 00 03 30 00 00 0C 40 00 03
6D30: 30 00 00 0C 40 00 03 30 00 00 0C 40 00 03 30 00
6D40: 00 0C 40 00 03 30 00 00 0C 40 00 03 30 00 00 0C
6D50: 40 00 03 30 00 00 0C 40 00 03 30 00 00 00 00 04
6D60: 40 00 01 10 00 00 04 40 00 01 10 00 00 04 40 00
6D70: 01 10 00 00 04 40 00 01 10 00 00 04 40 00 01 10
6D80: 00 00 04 40 00 01 10 00 00 04 40 00 01 10 00 00
6D90: 04 40 00 01 10 00 00 04 40 00 01 10 00 00 04 40
6DA0: 00 01 10 00 00 04 40 00 01 10 00 00 04 40 00 01
6DB0: 10 00 00 04 40 00 01 10 00 00 04 40 00 01 10 00
6DC0: 00 04 40 00 01 10 00 00 04 40 00 01 10 00 00 04
6DD0: 40 00 01 10 00 00 04 40 00 01 10 00 00 04 40 00
6DE0: 01 10 00 00 04 40 00 01 10 02 20 00 00 08 00 00
6DF0: 02 20 00 00 08 00 00 02 20 00 00 08 00 00 02 20
6E00: 00 00 08 00 00 02 20 00 00 08 00 00 02 20 00 00
6E10: 08 00 00 02 20 00 00 08 00 00 02 20 00 00 08 00
6E20: 00 02 20 00 00 08 00 00 02 20 00 00 08 00 00 02
6E30: 20 00 00 08 00 00 02 20 00 00 08 00 00 02 20 00
6E40: 00 08 00 00 02 20 00 00 08 00 00 02 20 00 00 08
6E50: 00 00 02 20 00 00 08 00 00 02 20 00 00 08 00 00
6E60: 02 20 00 00 08 00 00 02 20 00 00 08 00 00 02 20
6E70: 00 00 08 00 00 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 05 50 00 01 14 40 00 05 50 00 01 14 40 00
6EC0: 05 50 00 01 14 40 00 05 50 00 01 14 40 00 05 50
6ED0: 00 01 14 40 00 05 50 00 01 14 40 00 05 50 00 01
6EE0: 14 40 00 05 50 00 01 14 40 00 05 50 00 01 14 40
6EF0: 00 05 50 00 01 14 40 00 05 50 00 01 14 40 00 05
6F00: 50 0A 20 00 02 28 00 00 0A 20 00 02 28 00 00 0A
6F10: 20 00 02 28 00 00 0A 20 00 02 28 00 00 0A 20 00
6F20: 02 28 00 00 0A 20 00 02 28 00 00 0A 20 00 02 28
6F30: 00 00 0A 20 00 02 28 00 00 0A 20 00 02 28 00 00
6F40: 0A 20 00 02 28 00 00 0A 20 00 02 28 00 00 0A 20
6F50: 00 02 28 00 00 0A 20 00 02 28 00 00 0A 20 00 02
6F60: 28 00 00 0A 20 00 02 28 00 00 0A 20 00 02 28 00
6F70: 00 0A 20 00 02 28 00 00 0A 20 00 02 28 00 00 0A
6F80: 20 00 02 28 00 00 0A 20 00 02 28 00 00 00 00 0C
6F90: 40 00 03 30 00 00 0C 40 00 03 30 00 00 0C 40 00
6FA0: 03 30 00 00 0C 40 00 03 30 00 00 0C 40 00 03 30
6FB0: 00 00 0C 40 00 03 30 00 00 0C 40 00 03 30 00 00
6FC0: 0C 40 00 03 30 00 00 0C 40 00 03 30 00 00 0C 40
6FD0: 00 03 30 00 00 0C 40 00 03 30 00 00 0C 40 00 03
6FE0: 30 00 00 0C 40 00 03 30 00 00 0C 40 00 03 30 00
6FF0: 00 0C 40 00 03 30 00 00 0C 40 00 03 30 00 00 0C
7000: 40 00 03 30 00 00 0C 40 00 03 30 00 00 0C 40 00
7010: 03 30 00 00 0C 40 00 03 30 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 00 00 06 60 00 01 18 00 00 06
7060: 60 00 01 18 00 00 06 60 00 01 18 00 00 06 60 00
7070: 01 18 00 00 06 60 00 01 18 00 00 06 60 00 01 18
7080: 00 00 06 60 00 01 18 00 00 06 60 00 01 18 00 00
7090: 06 60 00 01 18 00 00 06 60 00 01 18 00 00 06 60
70A0: 00 01 18 00 00 00 01 1C 40 00 07 70 00 01 1C 40
70B0: 00 07 70 00 01 1C 40 00 07 70 00 01 1C 40 00 07
70C0: 70 00 01 1C 40 00 07 70 00 01 1C 40 00 07 70 00
70D0: 01 1C 40 00 07 70 00 01 1C 40 00 07 70 00 01 1C
70E0: 40 00 07 70 00 01 1C 40 00 07 70 00 01 1C 40 00
70F0: 07 70 00 01 1C 40 00 07 70 00 01 1C 40 00 07 70
7100: 00 01 1C 40 00 07 70 00 01 1C 40 00 07 70 00 01
7110: 1C 40 00 07 70 00 01 1C 40 00 07 70 00 01 1C 40
7120: 00 07 70 00 01 1C 40 00 07 70 00 01 1C 40 00 07
7130: 70 0E 60 00 03 38 00 00 0E 60 00 03 38 00 00 0E
7140: 60 00 03 38 00 00 0E 60 00 03 38 00 00 0E 60 00
7150: 03 38 00 00 0E 60 00 03 38 00 00 0E 60 00 03 38
7160: 00 00 0E 60 00 03 38 00 00 0E 60 00 03 38 00 00
7170: 0E 60 00 03 38 00 00 0E 60 00 03 38 00 00 0E 60
7180: 00 03 38 00 00 0E 60 00 03 38 00 00 0E 60 00 03
7190: 38 00 00 0E 60 00 03 38 00 00 0E 60 00 03 38 00
71A0: 00 0E 60 00 03 38 00 00 0E 60 00 03 38 00 00 0E
71B0: 60 00 03 38 00 00 0E 60 00 03 38 00 00 00 00 02
71C0: 20 00 00 08 00 00 02 20 00 00 08 00 00 02 20 00
71D0: 00 08 00 00 02 20 00 00 08 00 00 02 20 00 00 08
71E0: 00 00 02 20 00 00 08 00 00 02 20 00 00 08 00 00
71F0: 02 20 00 00 08 00 00 02 20 00 00 08 00 00 02 20
7200: 00 00 08 00 00 02 20 00 00 08 00 00 02 20 00 00
7210: 08 00 00 02 20 00 00 08 00 00 02 20 00 00 08 00
7220: 00 02 20 00 00 08 00 00 02 20 00 00 08 00 00 02
7230: 20 00 00 08 00 00 02 20 00 00 08 00 00 02 20 00
7240: 00 08 00 00 02 20 00 00 08 01 10 00 00 04 40 00
7250: 01 10 00 00 04 40 00 01 10 00 00 04 40 00 01 10
7260: 00 00 04 40 00 01 10 00 00 04 40 00 01 10 00 00
7270: 04 40 00 01 10 00 00 04 40 00 01 10 00 00 04 40
7280: 00 01 10 00 00 04 40 00 01 10 00 00 04 40 00 01
7290: 10 00 00 04 40 00 01 10 00 00 04 40 00 01 10 00
72A0: 00 04 40 00 01 10 00 00 04 40 00 01 10 00 00 04
72B0: 40 00 01 10 00 00 04 40 00 01 10 00 00 04 40 00
72C0: 01 10 00 00 04 40 00 01 10 00 00 04 40 00 01 10
72D0: 00 00 04 40 00 00 01 12 20 00 04 48 00 01 12 20
72E0: 00 04 48 00 01 12 20 00 04 48 00 01 12 20 00 04
72F0: 48 00 01 12 20 00 04 48 00 01 12 20 00 04 48 00
7300: 01 12 20 00 04 48 00 01 12 20 00 04 48 00 01 12
7310: 20 00 04 48 00 01 12 20 00 04 48 00 01 12 20 00
7320: 04 48 00 01 12 20 00 04 48 00 01 12 20 00 04 48
7330: 00 01 12 20 00 04 48 00 01 12 20 00 04 48 00 01
7340: 12 20 00 04 48 00 01 12 20 00 04 48 00 01 12 20
7350: 00 04 48 00 01 12 20 00 04 48 00 01 12 20 00 04
7360: 48 09 10 00 02 24 40 00 09 10 00 02 24 40 00 09
7370: 10 00 02 24 40 00 09 10 00 02 24 40 00 09 10 00
7380: 02 24 40 00 09 10 00 02 24 40 00 09 10 00 02 24
7390: 40 00 09 10 00 02 24 40 00 09 10 00 02 24 40 00
73A0: 09 10 00 02 24 40 00 09 10 00 02 24 40 00 09 10
73B0: 00 02 24 40 00 09 10 00 02 24 40 00 09 10 00 02
73C0: 24 40 00 09 10 00 02 24 40 00 09 10 00 02 24 40
73D0: 00 09 10 00 02 24 40 00 09 10 00 02 24 40 00 09
73E0: 10 00 02 24 40 00 09 10 00 02 24 40 00 00 00 0A
73F0: 20 00 02 28 00 00 0A 20 00 02 28 00 00 0A 20 00
7400: 02 28 00 00 0A 20 00 02 28 00 00 0A 20 00 02 28
7410: 00 00 0A 20 00 02 28 00 00 0A 20 00 02 28 00 00
7420: 0A 20 00 02 28 00 00 0A 20 00 02 28 00 00 0A 20
7430: 00 02 28 00 00 0A 20 00 02 28 00 00 0A 20 00 02
7440: 28 00 00 0A 20 00 02 28 00 00 0A 20 00 02 28 00
7450: 00 0A 20 00 02 28 00 00 0A 20 00 02 28 00 00 0A
7460: 20 00 02 28 00 00 0A 20 00 02 28 00 00 0A 20 00
7470: 02 28 00 00 0A 20 00 02 28 05 50 00 01 14 40 00
7480: 05 50 00 01 14 40 00 05 50 00 01 14 40 00 05 50
7490: 00 01 14 40 00 05 50 00 01 14 40 00 05 50 00 01
74A0: 14 40 00 05 50 00 01 14 40 00 05 50 00 01 14 40
74B0: 00 05 50 00 01 14 40 00 05 50 00 01 14 40 00 05
74C0: 50 00 01 14 40 00 05 50 00 01 14 40 00 05 50 00
74D0: 01 14 40 00 05 50 00 01 14 40 00 05 50 00 01 14
74E0: 40 00 05 50 00 01 14 40 00 05 50 00 01 14 40 00
74F0: 05 50 00 01 14 40 00 05 50 00 01 14 40 00 05 50
7500: 00 01 14 40 00 00 01 1A 20 00 06 68 00 01 1A 20
7510: 00 06 68 00 01 1A 20 00 06 68 00 01 1A 20 00 06
7520: 68 00 01 1A 20 00 06 68 00 01 1A 20 00 06 68 00
7530: 01 1A 20 00 06 68 00 01 1A 20 00 06 68 00 01 1A
7540: 20 00 06 68 00 01 1A 20 00 06 68 00 01 1A 20 00
7550: 06 68 00 01 1A 20 00 06 68 00 01 1A 20 00 06 68
7560: 00 01 1A 20 00 06 68 00 01 1A 20 00 06 68 00 01
7570: 1A 20 00 06 68 00 01 1A 20 00 06 68 00 01 1A 20
7580: 00 06 68 00 01 1A 20 00 06 68 00 01 1A 20 00 06
7590: 68 0D 50 00 03 34 40 00 0D 50 00 03 34 40 00 0D
75A0: 50 00 03 34 40 00 0D 50 00 03 34 40 00 0D 50 00
75B0: 03 34 40 00 0D 50 00 03 34 40 00 0D 50 00 03 34
75C0: 40 00 0D 50 00 03 34 40 00 0D 50 00 03 34 40 00
75D0: 0D 50 00 03 34 40 00 0D 50 00 03 34 40 00 0D 50
75E0: 00 03 34 40 00 0D 50 00 03 34 40 00 0D 50 00 03
75F0: 34 40 00 0D 50 00 03 34 40 00 0D 50 00 03 34 40
7600: 00 0D 50 00 03 34 40 00 0D 50 00 03 34 40 00 0D
7610: 50 00 03 34 40 00 0D 50 00 03 34 40 00 00 00 06
7620: 60 00 01 18 00 00 06 60 00 01 18 00 00 06 60 00
7630: 01 18 00 00 06 60 00 01 18 00 00 06 60 00 01 18
7640: 00 00 06 60 00 01 18 00 00 06 60 00 01 18 00 00
7650: 06 60 00 01 18 00 00 06 60 00 01 18 00 00 06 60
7660: 00 01 18 00 00 06 60 00 01 18 00 00 06 60 00 01
7670: 18 00 00 06 60 00 01 18 00 00 06 60 00 01 18 00
7680: 00 06 60 00 01 18 00 00 06 60 00 01 18 00 00 06
7690: 60 00 01 18 00 00 06 60 00 01 18 00 00 06 60 00
76A0: 01 18 00 00 06 60 00 01 18 03 30 00 00 0C 40 00
76B0: 03 30 00 00 0C 40 00 03 30 00 00 0C 40 00 03 30
76C0: 00 00 0C 40 00 03 30 00 00 0C 40 00 03 30 00 00
76D0: 0C 40 00 03 30 00 00 0C 40 00 03 30 00 00 0C 40
76E0: 00 03 30 00 00 0C 40 00 03 30 00 00 0C 40 00 03
76F0: 30 00 00 0C 40 00 03 30 00 00 0C 40 00 03 30 00
7700: 00 0C 40 00 03 30 00 00 0C 40 00 03 30 00 00 0C
7710: 40 00 03 30 00 00 0C 40 00 03 30 00 00 0C 40 00
7720: 03 30 00 00 0C 40 00 03 30 00 00 0C 40 00 03 30
7730: 00 00 0C 40 00 00 01 16 60 00 05 58 00 01 16 60
7740: 00 05 58 00 01 16 60 00 05 58 00 01 16 60 00 05
7750: 58 00 01 16 60 00 05 58 00 01 16 60 00 05 58 00
7760: 01 16 60 00 05 58 00 01 16 60 00 05 58 00 01 16
7770: 60 00 05 58 00 01 16 60 00 05 58 00 01 16 60 00
7780: 05 58 00 01 16 60 00 05 58 00 01 16 60 00 05 58
7790: 00 01 16 60 00 05 58 00 01 16 60 00 05 58 00 01
77A0: 16 60 00 05 58 00 01 16 60 00 05 58 00 01 16 60
77B0: 00 05 58 00 01 16 60 00 05 58 00 01 16 60 00 05
77C0: 58 0B 30 00 02 2C 40 00 0B 30 00 02 2C 40 00 0B
77D0: 30 00 02 2C 40 00 0B 30 00 02 2C 40 00 0B 30 00
77E0: 02 2C 40 00 0B 30 00 02 2C 40 00 0B 30 00 02 2C
77F0: 40 00 0B 30 00 02 2C 40 00 0B 30 00 02 2C 40 00
7800: 0B 30 00 02 2C 40 00 0B 30 00 02 2C 40 00 0B 30
7810: 00 02 2C 40 00 0B 30 00 02 2C 40 00 0B 30 00 02
7820: 2C 40 00 0B 30 00 02 2C 40 00 0B 30 00 02 2C 40
7830: 00 0B 30 00 02 2C 40 00 0B 30 00 02 2C 40 00 0B
7840: 30 00 02 2C 40 00 0B 30 00 02 2C 40 00 00 00 0E
7850: 60 00 03 38 00 00 0E 60 00 03 38 00 00 0E 60 00
7860: 03 38 00 00 0E 60 00 03 38 00 00 0E 60 00 03 38
7870: 00 00 0E 60 00 03 38 00 00 0E 60 00 03 38 00 00
7880: 0E 60 00 03 38 00 00 0E 60 00 03 38 00 00 0E 60
7890: 00 03 38 00 00 0E 60 00 03 38 00 00 0E 60 00 03
78A0: 38 00 00 0E 60 00 03 38 00 00 0E 60 00 03 38 00
78B0: 00 0E 60 00 03 38 00 00 0E 60 00 03 38 00 00 0E
78C0: 60 00 03 38 00 00 0E 60 00 03 38 00 00 0E 60 00
78D0: 03 38 00 00 0E 60 00 03 38 07 70 00 01 1C 40 00
78E0: 07 70 00 01 1C 40 00 07 70 00 01 1C 40 00 07 70
78F0: 00 01 1C 40 00 07 70 00 01 1C 40 00 07 70 00 01
7900: 1C 40 00 07 70 00 01 1C 40 00 07 70 00 01 1C 40
7910: 00 07 70 00 01 1C 40 00 07 70 00 01 1C 40 00 07
7920: 70 00 01 1C 40 00 07 70 00 01 1C 40 00 07 70 00
7930: 01 1C 40 00 07 70 00 01 1C 40 00 07 70 00 01 1C
7940: 40 00 07 70 00 01 1C 40 00 07 70 00 01 1C 40 00
7950: 07 70 00 01 1C 40 00 07 70 00 01 1C 40 00 07 70
7960: 00 01 1C 40 00 00 01 1E 60 00 07 78 00 01 1E 60
7970: 00 07 78 00 01 1E 60 00 07 78 00 01 1E 60 00 07
7980: 78 00 01 1E 60 00 07 78 00 01 1E 60 00 07 78 00
7990: 01 1E 60 00 07 78 00 01 1E 60 00 07 78 00 01 1E
79A0: 60 00 07 78 00 01 1E 60 00 07 78 00 01 1E 60 00
79B0: 07 78 00 01 1E 60 00 07 78 00 01 1E 60 00 07 78
79C0: 00 01 1E 60 00 07 78 00 01 1E 60 00 07 78 00 01
79D0: 1E 60 00 07 78 00 01 1E 60 00 07 78 00 01 1E 60
79E0: 00 07 78 00 01 1E 60 00 07 78 00 01 1E 60 00 07
79F0: 78 0F 70 00 03 3C 40 00 0F 70 00 03 3C 40 00 0F
7A00: 70 00 03 3C 40 00 0F 70 00 03 3C 40 00 0F 70 00
7A10: 03 3C 40 00 0F 70 00 03 3C 40 00 0F 70 00 03 3C
7A20: 40 00 0F 70 00 03 3C 40 00 0F 70 00 03 3C 40 00
7A30: 0F 70 00 03 3C 40 00 0F 70 00 03 3C 40 00 0F 70
7A40: 00 03 3C 40 00 0F 70 00 03 3C 40 00 0F 70 00 03
7A50: 3C 40 00 0F 70 00 03 3C 40 00 0F 70 00 03 3C 40
7A60: 00 0F 70 00 03 3C 40 00 0F 70 00 03 3C 40 00 0F
7A70: 70 00 03 3C 40 00 0F 70 00 03 3C 40 00 FD 15 2D
7A80: 45 5D 75 8D A5 BD D5 ED 05 1D 35 4D 65 68 6A 6B
7A90: 6C 6D 6E 6F 70 71 72 73 75 76 77 78 79 89 A1 B9
7AA0: D1 E9 01 19 31 49 61 79 91 A9 C1 D9 F1 69 6A 6B
7AB0: 6C 6D 6F 70 71 72 73 74 75 76 77 78 79 00 00 00
7AC0: 00 00 00 00 00 80 80 80 80 80 80 80 80 00 00 00
7AD0: 00 00 00 00 00 80 80 80 80 80 80 80 80 00 00 00
7AE0: 00 00 00 00 00 80 80 80 80 80 80 80 80 00 00 00
7AF0: 00 00 00 00 00 80 80 80 80 80 80 80 80 28 28 28
7B00: 28 28 28 28 28 A8 A8 A8 A8 A8 A8 A8 A8 28 28 28
7B10: 28 28 28 28 28 A8 A8 A8 A8 A8 A8 A8 A8 28 28 28
7B20: 28 28 28 28 28 A8 A8 A8 A8 A8 A8 A8 A8 28 28 28
7B30: 28 28 28 28 28 A8 A8 A8 A8 A8 A8 A8 A8 50 50 50
7B40: 50 50 50 50 50 D0 D0 D0 D0 D0 D0 D0 D0 50 50 50
7B50: 50 50 50 50 50 D0 D0 D0 D0 D0 D0 D0 D0 50 50 50
7B60: 50 50 50 50 50 D0 D0 D0 D0 D0 D0 D0 D0 50 50 50
7B70: 50 50 50 50 50 D0 D0 D0 D0 D0 D0 D0 D0 20 24 28
7B80: 2C 30 34 38 3C 20 24 28 2C 30 34 38 3C 21 25 29
7B90: 2D 31 35 39 3D 21 25 29 2D 31 35 39 3D 22 26 2A
7BA0: 2E 32 36 3A 3E 22 26 2A 2E 32 36 3A 3E 23 27 2B
7BB0: 2F 33 37 3B 3F 23 27 2B 2F 33 37 3B 3F 20 24 28
7BC0: 2C 30 34 38 3C 20 24 28 2C 30 34 38 3C 21 25 29
7BD0: 2D 31 35 39 3D 21 25 29 2D 31 35 39 3D 22 26 2A
7BE0: 2E 32 36 3A 3E 22 26 2A 2E 32 36 3A 3E 23 27 2B
7BF0: 2F 33 37 3B 3F 23 27 2B 2F 33 37 3B 3F 20 24 28
7C00: 2C 30 34 38 3C 20 24 28 2C 30 34 38 3C 21 25 29
7C10: 2D 31 35 39 3D 21 25 29 2D 31 35 39 3D 22 26 2A
7C20: 2E 32 36 3A 3E 22 26 2A 2E 32 36 3A 3E 23 27 2B
7C30: 2F 33 37 3B 3F 23 27 2B 2F 33 37 3B 3F
6000G
The results speak for themselves I think.The package is about 7.2K and renders in about 0.72 seconds. The drawing takes up about 1K of that. Which, in all honesty is still a little on the high side for the purposes of developing graphical adventures but I outline some strategies for getting these sizes down even further later on.
Even without these modifications it shouldn't be difficult to get 40-70 images on a standard ProDOS floppy. Which gets us pretty close to a game like The Wizard and the Princess which fits 116 areas on a single sided disk
For those who want to develop this further Here's a list of ideas that most of you who have been following along could easily implement:Idea | Difficulty | Description |
---|---|---|
Plot a single point | Easy | It takes five bytes to draw a single point. Adding a three-byte command to plot a single point would allow us to make more detailed drawings without wasting memory. |
Draw a solid rectangle | Easy | The monster in our example takes more drawing commands than everything else put together. Being able to draw a solid rectangle would have compressed our code by about 200 bytes or 15%. |
Relative Draw | Easy | Games like The Coveted Mirror represent objects on-screen. To accomplish this you may want to have a library of smaller images which you can reposition. |
Filled Polygon or Flood Fill | Intermediate to Advanced | A flood fill is the most heavily used tool in the Graphics Magician. Writing one of our own would yield even smaller images and while it might be complicated to implement efficiently. You could probably get similar amounts of savings with a command which would take a series of points and create a filled polygon from them. |
Fast plot | Advanced | There is still a significant amount of room for improvement here, just in small scale optimizations I could probably get us up to 25% of our theoretical maximum. Changing over to run-slicing or some other algorithm which plots more than one byte could easily double that. |
Where to now?
My next post will deal with double-hires character generators. Not only is this an important tool for the implementation of graphical adventures and role-playing games. It's also a nice jumping off point for developing tile-based games which include another popular RPG genre – top-down third-person games like Ultima. As well as just about every arcade game ever made!
See you then!
See you then!