RLE blitter, plus RLE encoding and decoding tools
authorJohn Tsiombikas <nuclear@member.fsf.org>
Tue, 15 Dec 2020 02:13:28 +0000 (04:13 +0200)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Tue, 15 Dec 2020 02:13:28 +0000 (04:13 +0200)
.gitignore
Makefile
bootsplash.asm
rle/Makefile [new file with mode: 0644]
rle/rle.c [new file with mode: 0644]
rle/unrle.c [new file with mode: 0644]

index d9e3493..492e4f8 100644 (file)
@@ -1,3 +1,10 @@
 *.swp
+*.o
 *.bin
 *.img
+*.pgm
+*.log
+*.rle
+dis
+rle/rle
+rle/unrle
index a9d1f17..2ae07cf 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -5,9 +5,12 @@ $(img): $(bin)
        dd if=/dev/zero of=$@ bs=512 count=2880
        dd if=$< of=$@ bs=512 conv=notrunc
 
-$(bin): bootsplash.asm
+$(bin): bootsplash.asm nuclear.rle
        nasm -f bin -o $@ $<
 
+nuclear.rle: nuclear.img
+       cat $< | rle/rle >$@ 2>rle.log
+
 .PHONY: run
 run: $(img)
        qemu-system-i386 -fda $<
@@ -15,3 +18,7 @@ run: $(img)
 .PHONY: debug
 debug: $(img)
        qemu-system-i386 -S -s -fda $<
+
+.PHONY: disasm
+disasm: $(bin)
+       ndisasm -o 0x7c00 $< >dis
index e8c4cc7..a6a552a 100644 (file)
@@ -61,6 +61,7 @@ stage2_start:
 
        xor ax, ax
        mov es, ax
+       mov ds, ax
 
        mov ax, str_booting
        call printstr
@@ -69,6 +70,7 @@ stage2_start:
 .hang: hlt
        jmp .hang
 
+       ; splash screen effect
 splash:
        mov ax, 13h
        int 10h
@@ -76,14 +78,45 @@ splash:
        mov ax, 0a000h
        mov es, ax
        xor di, di
-       mov cx, 32000
-       mov ax, 0505h
-       rep stosw
+
+       mov ax, pic
+       shr ax, 4
+       mov ds, ax
+       xor si, si
+
+       mov cx, 64000
+       call decode_rle
 
        call waitkey
 
        mov ax, 3
        int 10h
+       ret
+
+       ; decode RLE from ds:si to es:di, cx: number of decoded bytes (0 means 65536)
+       ; - high bit set for the repetition count, followed by a value byte to
+       ;   be repeated N times
+       ; - high bit not set for raw data that should be copied directly
+decode_rle:
+       mov al, [si]
+       inc si
+       mov bl, 1       ; default to "copy once" for raw values
+       test al, 0x80   ; test the high bit to see if it's a count or a raw value
+       jz .copy
+       ; it's a count, clear the high bit, and read the next byte for the value
+       and al, 0x7f
+       mov bl, al
+       mov al, [si]
+       inc si
+.copy: mov [es:di], al
+       inc di
+       dec cx          ; decrement decoded bytes counter
+       jz .end         ; as soon as it reaches 0, bail
+       dec bl
+       jnz .copy
+       jmp decode_rle
+.end:  ret
+       
 
 waitkey:
        in al, 64h
@@ -92,6 +125,10 @@ waitkey:
        in al, 60h
        ret
 
+       ; data
+       align 16
+pic:   incbin "nuclear.rle"
+
 stage2_end:
 
 ; vi:set ft=nasm:
diff --git a/rle/Makefile b/rle/Makefile
new file mode 100644 (file)
index 0000000..1d50a5b
--- /dev/null
@@ -0,0 +1,13 @@
+all: rle unrle
+
+rle: rle.o
+       $(CC) -o $@ $< $(LDFLAGS)
+
+unrle: unrle.o
+       $(CC) -o $@ $< $(LDFLAGS)
+
+clean:
+       $(RM) rle.o
+       $(RM) rle
+       $(RM) unrle.o
+       $(RM) unrle
diff --git a/rle/rle.c b/rle/rle.c
new file mode 100644 (file)
index 0000000..4acb24c
--- /dev/null
+++ b/rle/rle.c
@@ -0,0 +1,42 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+void emit(int c, int count);
+
+int main(void)
+{
+       int c, lastc, count;
+
+       lastc = -1;
+       count = 0;
+
+       while((c = getchar()) != -1) {
+               if(c == lastc && count < 127) {
+                       count++;
+               } else {
+                       emit(lastc, count);
+                       count = 1;
+                       lastc = c;
+               }
+       }
+       emit(lastc, count);
+
+       return 0;
+}
+
+void emit(int c, int count)
+{
+       if(count <= 0 || c < 0) return;
+
+       fprintf(stderr, "emit(%d, %d) -> ", c, count);
+       if(count > 2 || (c & 0x80)) {
+               fprintf(stderr, "%02x %02x\n", (unsigned int)count | 0x80, (unsigned int)c);
+               putchar(count | 0x80);
+               putchar(c);
+       } else {
+               while(count--) {
+                       fprintf(stderr, "%02x\n", (unsigned int)c & 0x7f);
+                       putchar(c);
+               }
+       }
+}
diff --git a/rle/unrle.c b/rle/unrle.c
new file mode 100644 (file)
index 0000000..7f70edd
--- /dev/null
@@ -0,0 +1,26 @@
+#include <stdio.h>
+
+int main(void)
+{
+       int c, count, rawbytes = 0;
+
+       printf("P5\n320 200\n255\n");
+
+       while((c = getchar()) != -1) {
+               if(c & 0x80) {
+                       count = c & 0x7f;
+                       if((c = getchar()) == -1) {
+                               fprintf(stderr, "Unexpected EOF while decoding RLE data\n");
+                               return 1;
+                       }
+                       rawbytes += count;
+                       while(count--) putchar(c);
+               } else {
+                       rawbytes++;
+                       putchar(c);
+               }
+       }
+
+       fprintf(stderr, "decoded (raw) size: %d bytes\n", rawbytes);
+       return 0;
+}