Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
aplib decompressor for ZX Basic.
#1
1. Download the compressor -> <!-- m --><a class="postlink" href="http://www.mojontwins.com/warehouse/apack.zip">http://www.mojontwins.com/warehouse/apack.zip</a><!-- m -->
2. Pack your binaries using it:
Code:
> apack.exe input.bin output.bin
3. Include your packed binaries in your program
Code:
packed:
Asm
   Binary "output.bin"
End Asm
4. Include the aplib decompressor (by dwedit/metalbrain/utopian) in your program
Code:
#include once "aplib.bas"
5. Call the depacker to decompress your binary to somewhere else (source, destination):
Code:
aplibUnpack (@packed, 16384)

Here's aplib.bas:
Code:
'' aplib.bas

Sub aplibDummyContainer
    asm
    
    ; aPPack decompressor
    ; original source by dwedit
    ; very slightly adapted by utopian
    ; optimized by Metalbrain
    ; Adapted for ZX Basic by na_th_an
    
    ;hl = source
    ;de = dest

    depack:    
            ld    ixl,128
    apbranch1:    
            ldi
    aploop0:    
            ld    ixh,1        ;LWM = 0
    aploop:        
            call     ap_getbit
            jr     nc,apbranch1
            call     ap_getbit
            jr     nc,apbranch2
            ld     b,0
            call     ap_getbit
            jr     nc,apbranch3
            ld    c,16        ;get an offset
    apget4bits:    
            call     ap_getbit
            rl     c
            jr    nc,apget4bits
            jr     nz,apbranch4
            ld     a,b
    apwritebyte:
            ld     (de),a        ;write a 0
            inc     de
            jr    aploop0
    apbranch4:
            and    a
            ex     de,hl         ;write a previous byte (1-15 away from dest)
            sbc     hl,bc
            ld     a,(hl)
            add    hl,bc
            ex     de,hl
            jr    apwritebyte
    apbranch3:
            ld     c,(hl)        ;use 7 bit offset, length = 2 or 3
            inc     hl
            rr     c
            ret     z        ;if a zero is encountered here, it is EOF
            ld    a,2
            adc    a,b
            push     hl
            ld    iyh,b
            ld    iyl,c
            ld     h,d
            ld     l,e
            sbc     hl,bc
            ld     c,a
            jr    ap_finishup2
    apbranch2:
            call     ap_getgamma    ;use a gamma code * 256 for offset, another gamma code for length
            dec     c
            ld    a,c
            sub    ixh
            jr     z,ap_r0_gamma        ;if gamma code is 2, use old r0 offset,
            dec     a
            ;do I even need this code?
            ;bc=bc*256+(hl), lazy 16bit way
            ld     b,a
            ld     c,(hl)
            inc     hl
            ld    iyh,b
            ld    iyl,c
    
            push     bc
            
            call     ap_getgamma
    
            ex     (sp),hl        ;bc = len, hl=offs
            push     de
            ex     de,hl
    
            ld    a,4
            cp    d
            jr     nc,apskip2
            inc     bc
            or    a
    apskip2:
            ld     hl,127
            sbc     hl,de
            jr     c,apskip3
            inc     bc
            inc     bc
    apskip3:
            pop     hl        ;bc = len, de = offs, hl=junk
            push     hl
            or     a
    ap_finishup:
            sbc     hl,de
            pop     de        ;hl=dest-offs, bc=len, de = dest
    ap_finishup2:
            ldir
            pop     hl
            ld    ixh,b
            jr     aploop
    
    ap_r0_gamma:
            call     ap_getgamma        ;and a new gamma code for length
            push     hl
            push     de
            ex    de,hl
    
            ld    d,iyh
            ld    e,iyl
            jr     ap_finishup
    
    
    ap_getbit:
            ld    a,ixl
            add    a,a
            ld    ixl,a
            ret    nz
            ld    a,(hl)
            inc    hl
            rla
            ld    ixl,a
            ret
    
    ap_getgamma:
            ld     bc,1
    ap_getgammaloop:
            call     ap_getbit
            rl     c
            rl     b
            call     ap_getbit
            jr     c,ap_getgammaloop
            ret
    End Asm
apDataPool:
    Asm
    ap__source:
            defw 0
    ap__destination:
            defw 0
    End Asm
End Sub

Sub aplibUnpack (source as uInteger, destination as uInteger)
    Poke uInteger @apDataPool, source
    Poke uInteger 2 + @apDataPool, destination
    Asm
        ld hl, (ap__source)
        ld de, (ap__destination)
        di
        push ix
        push iy
        call depack
        pop iy
        pop ix
        ei
    End Asm
End Sub

Happy coding!
Reply
#2
do you have an example?

What kind of data can be packed? (bytes,ints,strings?)
Reply
#3
This will be in the ZX Library. May I bundle it with the compiler? :?:
If so, in the Mojon Twins directory?
Reply
#4
how does someone know where to unpack a bin?
How do I know where there is empty space in RAM?
Reply
#5
You can pack whatever binary data.

how does someone know where to unpack a bin? - You unpack it where you need it to be.

For example, you can pack a .scr picture (6912 bytes usually compress to under 3 Kb, and even less if the screen is not very complex: I've gotten ~500 bytes for a logo or a frame) and then unpack it to 16384 to display it. You can pack your map data, and have several maps stored in memory, and then unpack the current level to your reserved space.

For example, say that you are using rectangular maps for 4x4 screens of 15x10 tiles each. Your map would be a 4x4x15x10=2400 bytes binary. You have to store somewhere, and have several compressed maps (depending on map complexity, you can save quite a bunch of bytes:

Code:
Sub mapContainer ()
mapdata:
   Asm
      mymap: defs 2400, 0
   End Asm
level1:
   Asm
         binary "level1c.bin"
   End Asm
level2:
   Asm
         binary "level2c.bin"
   End Asm
level3:
   Asm
         binary "level3c.bin"
   End Asm
End Sub

To unpack level1 and use it, just...

Code:
' unpack level 1:
aplibUnpack (@level1, @mapdata)

Then your engine reads the current level map data from @mapdata. When the player finished level 1 and level 2 is needed, you just unpack from @level2 to @mapdata and you have a brand new map.

Stuff like that. I use it all the time for almost everything.


As for examples, I have to clean up the source code of this game, which I hope to be sharing with you all very soon - and you'll have a working example (the logo and the backdrop are compressed images).

@Boriel: do as you wish - but the code is not mine, I just interfaced it. I'm releasing a 128K version soon - an easy way to use the extra RAM pages to store data - like some kind of "virtual storage". We use this for our 128K games in C: several levels, tilesets, and spritesets are stored compressed in the extra RAM. Mapdata, tileset and spriteset for the current level are decompressed from there to low ram buffers when entering a level. Afterwards, the game behaves like a 48K game. It's a good solution which works great and helps you avoid multi-loads Wink
Reply
#6
thanks for the explanation,

how is @mapdata first defined? is it an array,a memory address?

and how do you turn all those bytes into a BIN file?
Reply
#7
I've used the compressor in the zx basic library to do the same thing. ( <!-- m --><a class="postlink" href="http://www.boriel.com/wiki/en/index.php/ZX_BASIC:MegaLZ.bas">http://www.boriel.com/wiki/en/index.php ... MegaLZ.bas</a><!-- m --> ) - it works exactly the same way. I'll have to compare and see if this one squishes better, or runs faster Smile

Slenkar:

What you do is compress the data outside an emulator. For example, one game I'm working on (it may even get finished one day) puts up 1/3 of the screen banner graphics by decompressing to the screen memory. 1/3 of the screen is a handy size, because 2K of data fits there neatly, so it's just like doing a full screen in effect.

How do I do that? Well, I design the screen in a graphics package, and when it's together I test it on an emulated spectrum to make sure it looks right. Then, in spin, I export the data from 16384 (the screen memory) for 2K to a file.

I then compress this file with megalz using a command prompt on my PC. Na_th_an's aplib works the same way, but obviously it's different code.

Then you can #include the compressed code inside an asm context, and add in the decompressor code, and voila - zipped up graphics.
Reply
#8
na_th_an Wrote:1. Download the compressor -> <!-- m --><a class="postlink" href="http://www.mojontwins.com/warehouse/apack.exe">http://www.mojontwins.com/warehouse/apack.exe</a><!-- m -->

I don't think this link is working, Na_th_an?
Reply
#9
britlion Wrote:I've used the compressor in the zx basic library to do the same thing. ( <!-- m --><a class="postlink" href="http://www.boriel.com/wiki/en/index.php/ZX_BASIC:MegaLZ.bas">http://www.boriel.com/wiki/en/index.php ... MegaLZ.bas</a><!-- m --> ) - it works exactly the same way. I'll have to compare and see if this one squishes better, or runs faster Smile

Slenkar:

What you do is compress the data outside an emulator. For example, one game I'm working on (it may even get finished one day) puts up 1/3 of the screen banner graphics by decompressing to the screen memory. 1/3 of the screen is a handy size, because 2K of data fits there neatly, so it's just like doing a full screen in effect.

How do I do that? Well, I design the screen in a graphics package, and when it's together I test it on an emulated spectrum to make sure it looks right. Then, in spin, I export the data from 16384 (the screen memory) for 2K to a file.

I then compress this file with megalz using a command prompt on my PC. Na_th_an's aplib works the same way, but obviously it's different code.

Then you can #include the compressed code inside an asm context, and add in the decompressor code, and voila - zipped up graphics.

yes graphics packages export to BIN thankfully, but like what about some level data like a bunch of bytes
how do I get the BIN file?
Reply
#10
slenkar Wrote:yes graphics packages export to BIN thankfully, but like what about some level data like a bunch of bytes
how do I get the BIN file?
What do you use to create levels? Does it have binary export?
------------------------------------------------------------
http://lcd-one.da.ru redirector is dead
Visit my http://members.inode.at/838331/index.html home page!
Reply
#11
I would probably input the numbers manually or make a tool myself
Reply
#12
slenkar Wrote:I would probably input the numbers manually or make a tool myself
Then you can use:
Code:
label:
asm
  defb 0,0,0,0,0,0,0,0,0,0 ;' your binary data
  defb 1,2,4,4,5,2,0,0,0,0 ;' your further binary data
end asm
As for decompression address you can make a buffer with a label in similar fashion, and re-use it for decompressing all levels one by one. I used similar method in "U-Boot hunt" to decompress all frames of the explosion in real time (I used the MegaLZ compression, because BorIDE can compress selected DEFB's with MegaLZ).
------------------------------------------------------------
http://lcd-one.da.ru redirector is dead
Visit my http://members.inode.at/838331/index.html home page!
Reply
#13
If I input the number into the .bas file like this
Code:
label:
asm
  defb 0,0,0,0,0,0,0,0,0,0 ;' your binary data
  defb 1,2,4,4,5,2,0,0,0,0 ;' your further binary data
end asm

it wont be compressed, I have to somehow make a BIN file out of these numbers to run through the compressor
Reply
#14
slenkar Wrote:If I input the number into the .bas file like this
Code:
label:
asm
  defb 0,0,0,0,0,0,0,0,0,0 ;' your binary data
  defb 1,2,4,4,5,2,0,0,0,0 ;' your further binary data
end asm

it wont be compressed, I have to somehow make a BIN file out of these numbers to run through the compressor
Not if you use the BorIDE's build in MegaLZ compressor...
After you enter these and are happy with level design, select all the DEFB Statements and select "Edit" -> "DEFB Modificaton" -> "MegaLZ Compression". This will replace all DEFB with compressed version.
I will add ApLib compression later too.
------------------------------------------------------------
http://lcd-one.da.ru redirector is dead
Visit my http://members.inode.at/838331/index.html home page!
Reply
#15
Boride gets better and better. Going to add in aplib support too? Smile

Slenkar - you can still do it by hand. Compile the defb statements in, run spin, load the file, export the bin file out from the right address. You can use the debugger to find out where it is if you can't work that out. Done.
Reply


Forum Jump:


Users browsing this thread: 10 Guest(s)