Skip to content

Commit 26ae3ff

Browse files
committed
Add zx0 compression support
zx0 use demonstrated by compression of Background asset which is now a smaller INCBIN than the native uncompressed RAW asset. It is decompressed into a BSS bitplanes area, which is ALLOC'ed at runtime making the executable file size considerably smaller. Also improved assets workflow so that incremental updates can take place without reprocessing all assets
1 parent 33eec32 commit 26ae3ff

File tree

9 files changed

+223
-90
lines changed

9 files changed

+223
-90
lines changed

.github/workflows/amiga_demo.yml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,15 @@ jobs:
3232
cd ipng2iff
3333
cargo build -r
3434
sudo cp target/release/ipng2iff /usr/local/bin/
35+
- name: Install salvador (zx0 packer)
36+
run: |
37+
git clone https://github.com/emmanuel-marty/salvador.git
38+
cd salvador
39+
make -j$(nproc)
40+
sudo cp salvador /usr/local/bin/
3541
- name: Build ADF using make
3642
run: |
37-
make adf XDF_TOOL=venv/bin/xdftool -j$(nproc)
43+
make adf XDF_TOOL=venv/bin/xdftool
3844
- name: Upload ADF artifact(s)
3945
uses: actions/upload-artifact@v4
4046
with:

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ uae/dh0/main
55
assets/*.png
66
assets/*.iff
77
assets/*.raw
8+
assets/*.zx0
89
# src that we don't care about
910
include/*_palette.i
1011
# compiled tools

.vscode/tasks.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
"exefilename": "../uae/dh0/main",
2222
"entrypoint": "main.s",
2323
"args": [
24+
"-mrel",
2425
"-bamigahunk",
2526
"-Bstatic"
2627
]

Makefile

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ ifneq ($(DEBUG),1)
4343
LINK_ARGS += -s
4444
endif
4545

46+
# ZX0 compressor
47+
ZX0 := salvador -v
48+
4649
# Source files
4750
SRC_DIR := ./src
4851
MAIN_SRC := $(SRC_DIR)/main.s
@@ -57,20 +60,30 @@ OBJS := $(patsubst $(SRC_DIR)/%,$(BUILD_DIR)/%,$(ASM_SRCS:.s=.o))
5760
ASSETS_DIR := ./assets
5861
GIMP_ASSETS := $(wildcard $(ASSETS_DIR)/*.xcf)
5962
RAW_ASSETS := $(GIMP_ASSETS:.xcf=.raw)
63+
# ZX0 Assets are RAW_ASSETS compressed with ZX0 (salvador)
64+
ZX0_ASSETS := $(RAW_ASSETS:.raw=_raw.zx0)
6065
PALETTE_DIR := ./include
6166

6267
# The target ADF dir
6368
ADF_DIR := ./uae/dh0
6469
# The Target Binary Program
6570
TARGET := $(ADF_DIR)/main
6671

72+
# Generic rule to create a RAW asset from XCF
73+
$(ASSETS_DIR)/%.raw: $(ASSETS_DIR)/%.xcf
74+
@./scripts/convert_assets_to_raw.sh -x -p -r -s -i $(PALETTE_DIR) "$<"
75+
76+
# Generic rule to compress a RAW asset using zx0
77+
$(ASSETS_DIR)/%_raw.zx0: $(ASSETS_DIR)/%.raw
78+
$(ZX0) "$<" "$@"
79+
6780
# Generic rule to assemble a 68k asm source file (../src/*.cpp) into an object file (*.o)
6881
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.s $(ASM)
6982
# @echo '(${ASM}) Assembling source file: $<'
7083
$(ASM) $(ASM_ARGS) -o "$@" "$<"
7184

7285
# Link executable
73-
$(TARGET): $(LD) $(RAW_ASSETS) $(BUILD_DIR) $(MAIN_OBJ) $(OBJS)
86+
$(TARGET): $(LD) $(RAW_ASSETS) $(ZX0_ASSETS) $(BUILD_DIR) $(MAIN_OBJ) $(OBJS)
7487
# @echo '(${LD}) Linking target: $@'
7588
$(LD) $(LINK_ARGS) -o "$@" $(MAIN_OBJ) $(OBJS)
7689
@echo 'Finished linking target: $@'
@@ -79,10 +92,6 @@ $(TARGET): $(LD) $(RAW_ASSETS) $(BUILD_DIR) $(MAIN_OBJ) $(OBJS)
7992
$(BUILD_DIR):
8093
@mkdir -p $(BUILD_DIR)
8194

82-
# RAW assets
83-
$(RAW_ASSETS):
84-
@./scripts/convert_assets_to_raw.sh -x -p -r -s -i $(PALETTE_DIR)
85-
8695
# TOOLS - vasm
8796
$(ASM): $(VASM_DIR)
8897
@echo 'Building vasmm68k_mot in $(VASM_DIR)...'
@@ -105,7 +114,7 @@ all: $(TARGET)
105114

106115
tools: $(ASM) $(LD)
107116

108-
assets: $(RAW_ASSETS)
117+
assets: $(RAW_ASSETS) $(ZX0_ASSETS)
109118

110119
ADF_FILE := amiga_demo.adf
111120
ADF_VOLUME_NAME := 'Amiga Demo'
@@ -138,6 +147,7 @@ clean_assets:
138147
@rm -f $(ASSETS_DIR)/*.png
139148
@rm -f $(ASSETS_DIR)/*.iff
140149
@rm -f $(ASSETS_DIR)/*.raw
150+
@rm -f $(ASSETS_DIR)/*.zx0
141151

142152
# clean EVERYTHING
143153
clean_all: clean clean_tools clean_assets clean_adf

README.md

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ under [their own licenses](./tools/LICENSE.md).
1212
The following features are provided and demonstrated:
1313

1414
* Conversion of [GIMP](https://www.gimp.org/) authored image assets (*`.xcf`) into `.png`, `.iff` and `.raw` (interleaved) formats
15+
* Compression ('packing') or raw assets using the '`zx0`' format
1516
* Generation of palette (`COLORxx` register) data for image assets in copper list format
1617
* Host compilation of assembler (`vasm`) and linker (`vlink`) tools included.
1718
* Building to a [UAE](https://en.wikipedia.org/wiki/UAE_(emulator)) emulated hard drive (`dh0`) folder
@@ -24,18 +25,21 @@ for CI/CD automated building in the the cloud.
2425

2526
* Only RAW files with 'interleaved' bitplanes data are generated (no 'back-to-back' support)
2627
* Only images for low resolution (non-EHB) mode apps are supported.
27-
* No compression/packing support.
28+
* Only `zx0` compression/packing support.
2829
* No support for attached sprites palette generation
2930
* No special treatment for AGA
3031
* Bare bones 'no frills' bootable AmigaDOS ADFs. i.e. no loading messages etc.
3132

3233
## Demo App ##
3334

3435
This repo contains source code for a simple Amiga demo using Bitplanes (playfield), Blitter objects (BOBs) and Sprites.
36+
3537
This demo was made using samples of [example code](https://www.edsa.uk/blog/downloads) from the excellent book
3638
['Bare-Metal Amiga Programming'](https://www.edsa.uk/blog/bare-metal-amiga-programming)
3739
by E. Th. van den Oosterkamp, and used under his permissive license terms.
3840

41+
This demo also includes m68k asm `zx0` decompression code from [`salvador`](https://github.com/emmanuel-marty/salvador) by Emmanuel Marty, also used under permissive license terms.
42+
3943
The app was also developed in the equally excellent
4044
[Amiga Assembly](https://marketplace.visualstudio.com/items?itemName=prb28.amiga-assembly)
4145
extension for [Visual Studio Code](https://code.visualstudio.com/) (VSCode).
@@ -98,6 +102,22 @@ It is part of the [`netpbm`](https://netpbm.sourceforge.net/) toolkit.
98102
sudo apt install netpbm
99103
```
100104

105+
### salvador ###
106+
[salvador](https://github.com/emmanuel-marty/salvador) is used to compress `*.raw` images into `*_raw.zx0` packed files in the `zx0` format to help save space.
107+
108+
`salvador` has to be built from source.
109+
```sh
110+
git clone https://github.com/emmanuel-marty/salvador
111+
cd salvador
112+
make
113+
```
114+
115+
Once `salvador` has built, you need to move it to somewhere where it can be found in your `$PATH`. e.g.
116+
117+
```sh
118+
sudo cp salvador /usr/local/bin
119+
```
120+
101121
### amitools ###
102122

103123
[amitools](https://pypi.org/project/amitools/) is used to create floppy disk (`ADF`) images using
@@ -212,7 +232,7 @@ Passing `-h` (or `--help`) to the script shows usage information:
212232

213233
```none
214234
$ ./scripts/convert_assets_to_raw.sh -h
215-
usage: convert_assets_to_raw.sh [options]
235+
usage: convert_assets_to_raw.sh [options] [input file]
216236
217237
Options:
218238
@@ -236,6 +256,8 @@ Options:
236256
Include generation of PNG files from XCFs.
237257
```
238258

259+
If no `input_file` is specified, the script will works as a wildcard selecting all applicable files in the specified (or default) 'assets' directory.
260+
239261
## GitHub Actions Workflow ##
240262

241263
This repository includes a [GitHub Actions](https://docs.github.com/en/actions) (GHA)

scripts/convert_assets_to_raw.sh

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,13 @@ script_path="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )"
2626
# Get script name
2727
script_name="$(basename "$0")"
2828

29-
# Set derault input/output dirs
29+
# Set default input/output dirs
3030
asset_dir=$(realpath "$script_path/../assets")
3131
inc_dir="$asset_dir"
3232

33-
# Function to show ussage information and exit
33+
# Function to show usage information and exit
3434
show_usage() {
35-
echo "usage: ${script_name} [options]"
35+
echo "usage: ${script_name} [options] [input file]"
3636
echo -e "\nOptions:\n" \
3737
"\n -a,--asset-dir <dir name>\n" \
3838
" Use dir <dir name> to find source assets and place output assets.\n" \
@@ -102,7 +102,7 @@ while [[ $# > 0 ]]; do
102102
-r | --iff-raw) skip_raw=false ;;
103103
-s | --inc-pal) skip_palette=false ;;
104104
-x | --xcf-png) skip_png=false ;;
105-
*) echo "Unrecognized option ${1} ignored" ;;
105+
*) input_file="${1}" ;;
106106
esac
107107
shift
108108
done
@@ -112,6 +112,15 @@ if $show_usage; then
112112
exit 0
113113
fi
114114

115+
116+
if [[ -z "$input_file" ]]; then
117+
input_file="${asset_dir}/*"
118+
else
119+
input_file="$(echo ${input_file%.*})"
120+
fi
121+
122+
echo "INPUT FILE(S): ${input_file}"
123+
115124
# Check to make sure we have the tools we need available in $PATH
116125
rgb2iff_cmd="ipng2iff"
117126
ilbm_cmd="ilbmtoppm"
@@ -154,12 +163,12 @@ if [[ ! -d "$inc_dir" ]]; then
154163
fi
155164
inc_dir=$(realpath "$inc_dir")
156165

157-
# Convert all *.xcf files in assets/GIMP into PNG files in assets/PNG
166+
# Convert *.xcf files in assets/GIMP into PNG files in assets/PNG
158167
if $skip_png; then
159168
echo "XCF->PNG generation skipped. Specify --xcf-png option to include"
160169
else
161-
for xcf_file in "$asset_dir"/*.xcf; do
162-
png_file="$asset_dir/$(basename $xcf_file .xcf).png"
170+
for xcf_file in ${input_file}.xcf; do
171+
png_file="$(dirname $xcf_file)/$(basename $xcf_file .xcf).png"
163172
echo -e "\nConverting: XCF --> PNG\n<-- $xcf_file\n--> $png_file"
164173
if ! $dry_run; then
165174
# Write PNG file
@@ -168,13 +177,13 @@ else
168177
done
169178
fi
170179

171-
# Convert all *.png files in assets/PNG into IFF/ILBM *.iff files in assets/IFF
180+
# Convert *.png files in assets/PNG into IFF/ILBM *.iff files in assets/IFF
172181
if $skip_iff; then
173182
echo "PNG->IFF generation skipped. Specify --png-iff option to include"
174183
else
175-
for png_file in "$asset_dir"/*.png; do
184+
for png_file in ${input_file}.png; do
176185
png_res=$(file "$png_file" | grep -oP '([[:digit:]]+[[:blank:]]*x[[:blank:]]*[[:digit:]]+)' | sed 's/ //g')
177-
iff_file="$asset_dir/$(basename $png_file .png).iff"
186+
iff_file="$(dirname $png_file)/$(basename $png_file .png).iff"
178187
echo -e "\nConverting: PNG --> IFF\n<-- $png_file ($png_res)\n--> $iff_file"
179188
if ! $dry_run; then
180189
# Write IFF file
@@ -223,7 +232,7 @@ get_ilbm_info() {
223232
done <<<$(echo "$ilbm_cmap")
224233
}
225234

226-
# Convert all *.iff files in assets/IFF to raw (interleaved) plane data in RAW
235+
# Convert *.iff files in assets/IFF to raw (interleaved) plane data in RAW
227236
process_ilbm=false
228237
if $skip_raw; then
229238
echo "IFF->RAW conversion skipped. Specify --iff-raw option to include"
@@ -236,10 +245,10 @@ else
236245
process_ilbm=true
237246
fi
238247
if $process_ilbm; then
239-
for iff_file in "$asset_dir"/*.iff; do
248+
for iff_file in ${input_file}.iff; do
240249
# grab some metadata on the IFF file
241250
get_ilbm_info
242-
raw_file="$asset_dir/$(basename $iff_file .iff).raw"
251+
raw_file="$(dirname $iff_file)/$(basename $iff_file .iff).raw"
243252
# Only write one palette file for each sprite pair
244253
case "{$iff_file,,}" in
245254
*spr0* | *spr1*) palette_file="$inc_dir/sprites_01_palette.i" ;; # Sprites 0 & 1 palette file
@@ -278,13 +287,13 @@ fi
278287

279288
# Delete intermediary files if requested:
280289
if $delete_int_files; then
281-
for png_file in "$asset_dir"/*.png; do
290+
for png_file in ${input_file}.png; do
282291
echo "Removing $png_file"
283292
if ! $dry_run; then
284293
rm "$png_file"
285294
fi
286295
done
287-
for iff_file in "$asset_dir"/*.iff; do
296+
for iff_file in ${input_file}.iff; do
288297
echo "Removing $iff_file"
289298
if ! $dry_run; then
290299
rm "$iff_file"

src/bobs.s

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ MoveBOB::
7272
; D1.W - Y pos (vert)
7373

7474
PrepBOB::
75-
LEA.L Background(PC),a1 ; APTR interleaved playfield
75+
LEA.L Bitplanes(PC),a1 ; APTR interleaved playfield
7676
MULU #80,d1 ; Convert Y pos into offset
7777
ADD.L d1,a1 ; Add offset to destination
7878
AND.W #$FFF0,d0 ; Position without shift
@@ -104,7 +104,7 @@ PrepBOB::
104104
; D1.W - Y pos (vert)
105105

106106
PlaceBOB:
107-
LEA.L Background(PC),a2 ; APTR interleaved playfield
107+
LEA.L Bitplanes(PC),a2 ; APTR interleaved playfield
108108
MULU #80,d1 ; Convert Y pos into offset
109109
ADD.L d1,a2 ; Add offset to destination
110110
EXT.L d0 ; Clear top bits of D0
@@ -120,8 +120,8 @@ PlaceBOB:
120120

121121
MOVE.L a1,BLTAPT(a5) ; Source A = Mask
122122
MOVE.L a0,BLTBPT(a5) ; Source B = Object
123-
MOVE.L a2,BLTCPT(a5) ; Source C = Background
124-
MOVE.L a2,BLTDPT(a5) ; Destination = Background
123+
MOVE.L a2,BLTCPT(a5) ; Source C = Bitplanes
124+
MOVE.L a2,BLTDPT(a5) ; Destination = Bitplanes
125125
MOVE.W #$FFFF,BLTAFWM(a5) ; No first word masking
126126
MOVE.W #$FFFF,BLTALWM(a5) ; No last word masking
127127
MOVE.W d0,BLTCON1(a5) ; Use shift for source B
@@ -142,7 +142,7 @@ PlaceBOB:
142142
; D1.W - Y pos (vert)
143143

144144
ClearBOB:
145-
LEA.L Background(PC),a1 ; APTR interleaved playfield
145+
LEA.L Bitplanes(PC),a1 ; APTR interleaved playfield
146146
MULU #80,d1 ; Convert Y pos into offset
147147
ADD.L d1,a1 ; Add offset to destination
148148
AND.W #$FFF0,d0 ; Position without shift

0 commit comments

Comments
 (0)