|
Example 3
|
|
In the last part I said, "So we shall, in the next part, propose a new format that will make the compression even more efficient."
So, then, how can we make the compression more efficient? Remember that our compression was good on solid areas of colour but a bit rubbish when it came down to dithered or complicated images. Consider:
HEADER: (26 bytes)-"BudgieScrn (compressed 2)"
<cr>
MODE: (1 byte)-Screen mode.
PALETTE: (16 * 6 bytes)-Bytes giving R, G & B components of
first flash colour.
Bytes giving R, G, & B components of second flash
colour.
IMAGE DATA:
If byte = 255, then loop data follows. Next byte
is the colour. Third byte is a count (0 - 254)
of how many pixels of this colour to fill in.
If byte <> 255, then byte is regular screen
memory. Just stick it straight to the screen...
Immediately, two things should be noticed:
The program is commented, so shouldn't need any further explanation. Converting it to assembler is left as an exercise for the reader.
REM >Ssaver2
REM Compress sprites using BudgieSoft compression algorithm
REM (type 2).
REM
REM by Richard Murray Winter 1997
REM
REM Downloaded from: http://www.heyrick.co.uk/assembler/
:
ON ERROR PRINT REPORT$+" at "+STR$(ERL/10) : END
:
REM Open output file (put your own path here, or read from
REM command line).
x%=OPENOUT("IDEFS::Willow.$.WWW.WWWsite.assembler.sw.screen2/raw")
:
REM Write out the identification header...
BPUT#x%, "BudgieScrn (compressed 2)"
:
REM ...and the current screenmode.
BPUT#x%, MODE
:
REM Build up palette entries, and write out.
FOR loop% = 0 TO 15
SYS "OS_ReadPalette", loop%, 16 TO ,,f%, s%
r1% = (f% >> 8) AND 255 : REM First flash colour
REM red component
g1% = (f% >> 16) AND 255 : REM First flash colour
REM green component
b1% = (f% >> 24) AND 255 : REM First flash colour
REM blue component
r2% = (s% >> 8) AND 255 : REM Second flash colour
REM red component
g2% = (s% >> 16) AND 255 : REM Second flash colour
REM green component
b2% = (s% >> 24) AND 255 : REM Second flash colour
REM blue component
BPUT#x%, r1% : BPUT#x%, g1% : BPUT#x%, b1%
BPUT#x%, r2% : BPUT#x%, g2% : BPUT#x%, b2%
NEXT
:
REM Get our screen sizes. This is not written to file. The
REM loader will have to figure out it's own screen dimensions.
REM Then switch off the cursor.
DIM b% 19
b%!0=149 : b%!4=7 : b%!8=-1
SYS "OS_ReadVduVariables", b%, b%+12
base%=b%!12 : length%=b%!16 :end%=base%+length%
SYS "XOS_RemoveCursors"
:
:
REM Now read from base% to end% (via posn%) calculating the
REM data, writing it out to file as necessary.
:
posn% = base%
REPEAT
REM Read four pixels (two bytes) at a time.
REM If they match, begin a loop.
col1% = posn%?0
col2% = posn%?1
IF col1% = col2% THEN
REM They match, so...
BPUT#x%, 255
BPUT#x%, col1%
counter% = 0
REPEAT
col1% = posn%?0
IF col1% = col2% THEN
counter%+=1
posn%+=1
ENDIF
UNTIL counter% = 255 OR (col1% <> col2%)
BPUT#x%, counter%
ELSE
REM Otherwise write out pixels.
BPUT#x%, col1%
IF col1% = 255 THEN
REM A little hack for colour 15 double (byte = 255).
BPUT#x%, col1%
BPUT#x%, 0
ENDIF
posn% += 1
ENDIF
REM Until end.
UNTIL posn% >=end%
:
REM Close file and exit.
CLOSE#x%
END
Apart from a few little changes in the loader routine, it is very similar to the existing loader.
The differences, mainly, are:
.main_loop
Read a byte.
Is it '255'?
If so, branch with link to read_loop.
Write byte (pixel pair) to screen.
Look to see if we are at the end of screen.
If not, branch to main_loop.
Close and exit etc etc.
.read_loop
Read colour byte.
Read length byte.
.loop2
Subtract 1 from length.
Write colour byte to screen.
Length is zero?
If not, branch to loop2.
End of screen?
If not, branch to main_loop.
Otherwise exit.
I'll leave you to compare the above flow with the program itself. It is commented so you
shouldn't have too many problems.
To current date there is no type 2 saver in assembler. I use the BASIC code mentioned previously. So instead I will treat you to a loader that handles all three versions.
The code is commented, but it is not split into annotated chunks as before. You should be able to follow what is going on.
REM >Sloader2 BudgieSoft screen loader (all versions)
REM Version 0.21
REM
REM by Richard Murray Winter 1997
REM
REM Downloaded from: http://www.heyrick.co.uk/assembler/
:
ON ERROR PRINT REPORT$+" at "+STR$(ERL/10) : END
:
PROCassemble
OSCLI("Save <Obey$Dir>.Loader "+STR$~(code%)+" "+STR$~(O%))
OSCLI("SetType <Obey$Dir>.Loader &FFC")
END
:
DEFPROCassemble
DIM code% &1000
FOR pass% = 4 TO 6 STEP 2
P%=0
O%=code%
[ OPT pass%
MOV R10, R14
MOV R0, #&4C
SWI "XOS_Find"
BVS exit
MOV R5, R0
; Skip header
MOV R8, #0
.skip_header
MOV R1, R5
BL read_byte
ADD R8, R8, #1
CMP R8, #23
BLT skip_header
MOV R1, R5
BL read_byte
CMP R0, #10 ; Newline - version 0.
BEQ version_zero
CMP R0, #49 ; '1' - version 1.
BEQ version_one
CMP R0, #50 ; '2' - version 2.
BEQ version_two
ADR R0, unknown_string
SWI "OS_PrettyPrint"
SWI "OS_NewLine"
SWI "OS_NewLine"
B exit
.unknown_string
EQUS "Unable to load this screen - the format"
EQUS " has not been recognised..."
EQUB 0
ALIGN
; *** VERSION ZERO HANDLER ***
.version_zero
B load_old_format
; *** VERSION ONE HANDLER ***
.version_one
MOV R1, R5
BL read_byte
BL read_byte
B load_old_format
; *** VERSION TWO HANDLER
.version_two
MOV R1, R5
BL read_byte
BL read_byte
B load_new_format
; *** OLD FORMAT LOADER ***
.load_old_format
BL switch_screen_mode
BL get_screen_info
BL load_palette
.old_loop
MOV R1, R5
BL read_byte
MOV R4, R0
BL read_byte
.old_loop2
SUB R0, R0, #1
STRB R4, [R2, #1]!
CMP R0, #0
BGT old_loop2
CMP R2, R3
BLT old_loop
B exit
; *** NEW FORMAT LOADER ***
.load_new_format
BL switch_screen_mode
BL get_screen_info
BL load_palette
.new_loop
MOV R1, R5
BL read_byte
CMP R0, #255
BLEQ read_loop
STRB R0, [R2, #1]!
CMP R2, R3
BLT new_loop
B exit
; *** RESOURCES ***
.switch_screen_mode
MOV R12, R14
MOV R0, #&87
SWI "XOS_Byte"
MOV R1, R5
BL read_byte
CMP R0, R2
SWINE &100 + 22
SWINE "OS_WriteC"
MOV PC, R12
.get_screen_info
ADR R0, vdu_block
ADD R1, R0, #12
SWI "OS_ReadVduVariables"
LDR R2, [R1]
LDR R3, [R1, #4]
ADD R3, R3, R2
SUB R2, R2, #1
MOV PC, R14
.load_palette
MOV R12, R14
MOV R4, #0
ADR R7, os_block
.col_loop
MOV R1, R5
STRB R4, [R7, #0]
MOV R0, #17
STRB R0, [R7, #1]
BL read_byte
STRB R0, [R7, #2]
BL read_byte
STRB R0, [R7, #3]
BL read_byte
STRB R0, [R7, #4]
MOV R0, #&0C
MOV R1, R7
SWI "OS_Word"
MOV R1, R5
MOV R0, #18
STRB R0, [R7, #1]
BL read_byte
STRB R0, [R7, #2]
BL read_byte
STRB R0, [R7, #3]
BL read_byte
STRB R0, [R7, #4]
MOV R0, #&0C
MOV R1, R7
SWI "OS_Word"
ADD R4, R4, #1
CMP R4, #16
BLT col_loop
MOV R0, #0
MOV PC, R12
.exit
MOV R2, R0
MOV R1, R5
MOV R0, #0
SWI "XOS_Find"
MOV PC, R10
.read_byte
SWI "XOS_BGet"
MOVVC PC, R14
.read_loop ; Read and deal with loop data.
MOV R1, R5
BL read_byte ; Read colour
MOV R4, R0
BL read_byte ; Read length
.loop2
SUB R0, R0, #1
STRB R4, [R2, #1]!
CMP R0, #0 ; More to loop?
BGT loop2
CMP R2, R3 ; End of screen?
BLT new_loop
B exit
.vdu_block
EQUD 149
EQUD 7
EQUD -1
EQUD 0
EQUD 0
.os_block
EQUD 0
EQUB 0
ALIGN
]
NEXT
ENDPROC
This concludes our series on creating compressed screen software. If you wish to write an
assembler saver for type 2 files, please do so. Likewise, bug reports and such would also be
welcomed.
By way of comparison, here is a type 1 version of the above image. It is a moderately balanced image, a textured JPEG and textured windows alongside plain windows.
The type 1 screen is 159771 bytes.
The type 2 screen is 123369 bytes.