diff --git a/arm9/Makefile b/arm9/Makefile
index 3684baf..5b99398 100644
--- a/arm9/Makefile
+++ b/arm9/Makefile
@@ -130,7 +130,7 @@
@$(bin2o)
#---------------------------------------------------------------------------------
-%.ppm.lz.o : %.ppm.lz
+%.spla.o : %.spla
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(bin2o)
diff --git a/arm9/data/banner.ppm.lz b/arm9/data/banner.ppm.lz
deleted file mode 100644
index 2e195dd..0000000
--- a/arm9/data/banner.ppm.lz
+++ /dev/null
Binary files differ
diff --git a/arm9/data/banner.spla b/arm9/data/banner.spla
new file mode 100644
index 0000000..d87a545
--- /dev/null
+++ b/arm9/data/banner.spla
Binary files differ
diff --git a/arm9/data/bootfail.ppm.lz b/arm9/data/bootfail.ppm.lz
deleted file mode 100644
index 1554a90..0000000
--- a/arm9/data/bootfail.ppm.lz
+++ /dev/null
Binary files differ
diff --git a/arm9/data/bootfail.spla b/arm9/data/bootfail.spla
new file mode 100644
index 0000000..3d65f84
--- /dev/null
+++ b/arm9/data/bootfail.spla
Binary files differ
diff --git a/arm9/data/bootwarning.ppm.lz b/arm9/data/bootwarning.ppm.lz
deleted file mode 100644
index 521391d..0000000
--- a/arm9/data/bootwarning.ppm.lz
+++ /dev/null
Binary files differ
diff --git a/arm9/data/bootwarning.spla b/arm9/data/bootwarning.spla
new file mode 100644
index 0000000..e5fb5ff
--- /dev/null
+++ b/arm9/data/bootwarning.spla
Binary files differ
diff --git a/include/arm9/splash.h b/include/arm9/splash.h
new file mode 100644
index 0000000..0879f57
--- /dev/null
+++ b/include/arm9/splash.h
@@ -0,0 +1,47 @@
+#pragma once
+
+/*
+ * This file is part of fastboot 3DS
+ * Copyright (C) 2017 derrek, profi200
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "types.h"
+
+
+#define FLAG_ROTATED (1u<<3)
+#define FLAG_COMPRESSED (1u<<4)
+#define FLAG_SWAPPED (1u<<5)
+
+
+enum
+{
+ FORMAT_RGB565 = 0,
+ FORMAT_RGB8 = 1,
+ FORMAT_RGBA8 = 2,
+ FORMAT_INVALID = 7
+};
+
+typedef struct
+{
+ u32 magic;
+ u16 width;
+ u16 height;
+ u32 flags;
+} SplashHeader;
+
+
+
+bool drawSplashscreen(const void *const data);
diff --git a/source/arm9/lz11.s b/source/arm9/lz11.s
new file mode 100644
index 0000000..3b82f12
--- /dev/null
+++ b/source/arm9/lz11.s
@@ -0,0 +1,90 @@
+@ Code by mtheall
+
+#include "asmfunc.h"
+
+.arm
+.cpu arm946e-s
+.fpu softvfp
+
+
+
+ASM_FUNC lz11Decompress
+ push {r4-r6}
+ ldr r3, =(0x01010101)
+
+.Lloop:
+ cmp r2, #0 @ if(size <= 0)
+ pople {r4-r6} @ pop stack
+ bxle lr @ return
+
+ rors r3, r3, #1 @ r3 = (r3<<31) | (r3>>1)
+ ldrcsb r12, [r0], #1 @ if(r3 & (1<<31)) flags = *in++
+ tst r12, r3 @ if(flags & r3 == 0)
+ beq .Lcopy_uncompressed @ goto copy_uncompressed
+
+ ldrb r4, [r0], #1 @ r4 = *in++
+ and r5, r4, #0xF0 @ r5 = r4 & 0xF0
+ cmp r5, #0x00 @ if(r5 == 0x00)
+ beq .Lextended @ goto extended
+ cmp r5, #0x10 @ if(r5 == 0x10)
+ beq .LXextended @ goto Xextended
+
+ lsr r6, r4, #4 @ len = r4>>4
+ add r6, r6, #1 @ len++
+ b .L1
+
+.Lextended:
+ lsl r6, r4, #4 @ len = r4<<4
+ ldrb r4, [r0], #1 @ r4 = *in++
+ orr r6, r6, r4, lsr #4 @ len = len | (r4>>4)
+ add r6, r6, #0x11 @ len += 0x11
+ b .L1
+
+.LXextended:
+ and r4, r4, #0x0F @ r4 &= 0x0F
+ lsl r6, r4, #12 @ len = r4<<12
+ ldrb r4, [r0], #1 @ r4 = *in++
+ orr r6, r6, r4, lsl #4 @ len |= r4<<4
+ ldrb r4, [r0], #1 @ r4 = *in++
+ orr r6, r6, r4, lsr #4 @ len |= r4>>4
+ add r6, r6, #0x011 @ len += 0x011
+ add r6, r6, #0x100 @ len += 0x100
+
+.L1:
+ and r5, r4, #0x0F @ disp = r4 & 0x0F note: disp is in r5
+ ldrb r4, [r0], #1 @ r4 = *in++
+ orr r4, r4, r5, lsl #8 @ disp = r4 | (disp<<8) note: disp changes to r4
+ add r4, r4, #1 @ disp++
+ sub r2, r2, r6 @ size -= len
+ tst r4, #1 @ if(r4 & 1 == 0) // aligned displacement
+ beq .Lcopy_aligned @ goto copy_aligned
+
+.Lcopy_compressed:
+ ldrb r5, [r1, -r4] @ r5 = *(out - disp)
+ subs r6, r6, #1 @ if(len-- == 1)
+ strb r5, [r1], #1 @ *out++ = r5
+ bne .Lcopy_compressed @ goto copy_compressed
+ b .Lloop @ goto loop
+
+.Lcopy_aligned:
+ tst r1, #0x1 @ if(r1 & 0x1 == 0) // src/dst is aligned
+ beq .Lcopy_hwords @ goto copy_hwords
+ ldrb r5, [r1, -r4] @ r5 = *(out - disp) // read a byte to align
+ strb r5, [r1], #1 @ *out++ = r5
+ sub r6, r6, #1 @ len--
+.Lcopy_hwords:
+ subs r6, r6, #2 @ len -= 2
+ ldrgeh r5, [r1, -r4] @ if(len >= 0) r5 = *(short*)(out - disp)
+ strgeh r5, [r1], #2 @ if(len >= 0) *(short*)out++ = r5
+ beq .Lloop @ if(len == 0) goto loop
+ bgt .Lcopy_hwords @ if(len > 0) goto copy_hwords
+@ extra byte
+ ldrb r5, [r1, -r4] @ r5 = *(out - disp)
+ strb r5, [r1], #1 @ *out++ = r5
+ b .Lloop @ goto loop
+
+.Lcopy_uncompressed:
+ ldrb r4, [r0], #1 @ r4 = *in++
+ sub r2, r2, #1 @ size--
+ strb r4, [r1], #1 @ *out++ = r4
+ b .Lloop @ goto loop
diff --git a/source/arm9/lzss.s b/source/arm9/lzss.s
deleted file mode 100644
index e5ff084..0000000
--- a/source/arm9/lzss.s
+++ /dev/null
@@ -1,64 +0,0 @@
-@ Code by mtheall
-
-#include "asmfunc.h"
-
-.arm
-.cpu arm946e-s
-.fpu softvfp
-
-
-
-ASM_FUNC lzssDecompress
- push {r4-r6}
- ldr r3, =(0x01010101)
-
-.Lloop:
- cmp r2, #0 @ if(size <= 0)
- pople {r4-r6} @ pop stack
- bxle lr @ return
-
- rors r3, r3, #1 @ r3 = (r3<<31) | (r3>>1)
- ldrcsb r12, [r0], #1 @ if(r3 & (1<<31)) flags = *in++
- tst r12, r3 @ if(flags & r3 == 0)
- beq .Lcopy_uncompressed @ goto copy_uncompressed
-
- ldrb r4, [r0], #1 @ r4 = *in++
- lsr r6, r4, #4 @ len = r4>>4
- add r6, r6, #3 @ len += 3
- and r5, r4, #0x0F @ disp = r4 & 0x0F note: disp is in r5
- ldrb r4, [r0], #1 @ r4 = *in++
- orr r4, r4, r5, lsl #8 @ disp = r4 | (disp<<8) note: disp changes to r4
- add r4, r4, #1 @ disp++
- sub r2, r2, r6 @ size -= len
- tst r4, #1 @ if(r4 & 1 == 0) // aligned displacement
- beq .Lcopy_aligned @ goto copy_aligned
-
-.Lcopy_compressed:
- ldrb r5, [r1, -r4] @ r5 = *(out - disp)
- subs r6, r6, #1 @ --len
- strb r5, [r1], #1 @ *out++ = r5
- bne .Lcopy_compressed @ goto copy_compressed
- b .Lloop @ if(len == 0) goto loop
-
-.Lcopy_aligned:
- tst r1, #0x1 @ if(r1 & 0x1 == 0) // src/dst is aligned
- beq .Lcopy_hwords @ goto copy_hwords
- ldrb r5, [r1, -r4] @ r5 = *(out - disp) // read a byte to align
- sub r6, r6, #1 @ len--
- strb r5, [r1], #1 @ *out++ = r5
-.Lcopy_hwords:
- subs r6, r6, #2 @ len -= 2
- ldrgeh r5, [r1, -r4] @ if(len >= 0) r5 = *(short*)(out - disp)
- strgeh r5, [r1], #2 @ if(len >= 0) *(short*)out++ = r5
- bgt .Lcopy_hwords @ if(len > 0) goto copy_hwords
- beq .Lloop @ if(len == 0) goto loop
-@ extra byte
- ldrb r5, [r1, -r4] @ r5 = *(out - disp)
- strb r5, [r1], #1 @ *out++ = r5
- b .Lloop @ goto loop
-
-.Lcopy_uncompressed:
- ldrb r4, [r0], #1 @ r4 = *in++
- sub r2, r2, #1 @ size--
- strb r4, [r1], #1 @ *out++ = r4
- b .Lloop @ goto loop
diff --git a/source/arm9/splash.c b/source/arm9/splash.c
new file mode 100644
index 0000000..dd784f3
--- /dev/null
+++ b/source/arm9/splash.c
@@ -0,0 +1,78 @@
+/*
+ * This file is part of fastboot 3DS
+ * Copyright (C) 2017 derrek, profi200
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include
+#include
+#include
+#include "types.h"
+#include "arm9/splash.h"
+#include "arm9/fmt.h"
+#include "gfx.h"
+
+
+
+void lz11Decompress(const void *in, void *out, u32 size);
+
+static bool validateSplashHeader(SplashHeader *header)
+{
+ if(memcmp(&header->magic, "SPLA", 4)) return false;
+
+ const u16 width = header->width, height = header->height;
+ if(width > SCREEN_WIDTH_TOP || height > SCREEN_HEIGHT_TOP) return false;
+
+ const u32 flags = header->flags;
+ if((flags & FORMAT_INVALID) != FORMAT_RGB565) return false;
+ if(!(flags & FLAG_ROTATED) || flags & FLAG_SWAPPED) return false;
+
+ return true;
+}
+
+bool drawSplashscreen(const void *const data)
+{
+ SplashHeader header;
+ memcpy(&header, data, sizeof(SplashHeader));
+ if(!validateSplashHeader(&header)) return false;
+
+ const u16 width = header.width, height = header.height;
+ const u32 flags = header.flags;
+ const bool isCompressed = flags & FLAG_COMPRESSED;
+
+ u16 *imgData;
+ if(isCompressed)
+ {
+ imgData = (u16*)malloc(width * height * 2);
+ if(!imgData) return false;
+ lz11Decompress(data + sizeof(SplashHeader), imgData, width * height * 2);
+ }
+ else imgData = (u16*)(data + sizeof(SplashHeader));
+
+ u16 *fb = (u16*)FRAMEBUF_TOP_A_1;
+ const u32 yy = (SCREEN_HEIGHT_TOP - height) / 2;
+ const u32 xx = (SCREEN_WIDTH_TOP - width) / 2;
+ for(u32 x = 0; x < width; x++)
+ {
+ for(u32 y = 0; y < height; y++)
+ {
+ fb[(x + xx) * SCREEN_HEIGHT_TOP + y + yy] = imgData[x * height + y];
+ }
+ }
+
+ if(isCompressed) free(imgData);
+
+ return true;
+}
diff --git a/source/arm9/ui.c b/source/arm9/ui.c
index 346f770..8cdc68c 100644
--- a/source/arm9/ui.c
+++ b/source/arm9/ui.c
@@ -29,21 +29,20 @@
#include "arm9/main.h"
#include "arm9/ui.h"
#include "arm9/console.h"
-#include "banner_ppm_lz.h"
-#include "bootwarning_ppm_lz.h"
-#include "bootfail_ppm_lz.h"
+#include "arm9/splash.h"
+#include "banner_spla.h"
+#include "bootwarning_spla.h"
+#include "bootfail_spla.h"
static u8 randomColor;
static bool verbose = false;
-static const void *bannerData = banner_ppm_lz;
-static const void *bootWarningData = bootwarning_ppm_lz;
-static const void *bootFailureData = bootfail_ppm_lz;
+static const void *bannerData = banner_spla;
+static const void *bootWarningData = bootwarning_spla;
+static const void *bootFailureData = bootfail_spla;
-static void uiGetPPMInfo(const u8 *data, unsigned *width, unsigned *height);
-static void uiDrawPPM(unsigned start_x, unsigned start_y, const u8 *data);
static void consoleMainInit()
{
@@ -59,21 +58,9 @@
consoleSelect(&con_top);
}
-void lzssDecompress(const void *in, void *out, u32 size);
-
void uiDrawSplashScreen()
{
- u8 *buf = (u8*)malloc(0x3259);
- if(!buf) return;
-
- lzssDecompress(bannerData + 4, buf, 0x3259);
- unsigned width, height;
- uiGetPPMInfo(buf, &width, &height);
-
- // centered draw
- uiDrawPPM((SCREEN_WIDTH_TOP - width) / 2, (SCREEN_HEIGHT_TOP - height) / 2, buf);
-
- free(buf);
+ drawSplashscreen(bannerData);
}
void uiInit()
@@ -364,91 +351,15 @@
}
}
-static inline void drawPixel(unsigned x, unsigned y, u16 color)
-{
- u16 *framebuf = (u16 *) FRAMEBUF_TOP_A_1;
- framebuf[x * SCREEN_HEIGHT_TOP + y] = color;
-}
-
-static void uiGetPPMInfo(const u8 *data, unsigned *width, unsigned *height)
-{
- /* get image dimensions */
- const char *ptr = (const char *) data + 3;
- while(*ptr != 0x0A) ptr++;
- ptr++;
-
- mysscanf(ptr, "%u %u", width, height);
-}
-
-static void uiDrawPPM(unsigned start_x, unsigned start_y, const u8 *data)
-{
- unsigned width, height;
-
- /* get image dimensions */
- uiGetPPMInfo(data, &width, &height);
-
- const u8 *imagedata = data + 0x26; // skip ppm header
-
- u16 color;
-
- for(unsigned x = 0; x < width; x++)
- {
- for(unsigned y = height; y > 0; y--)
- {
- const u8 *pixeldata = &imagedata[(x + (y-1) * width)*3];
- color = RGB8_to_565(pixeldata[2], pixeldata[1], pixeldata[0]);
- drawPixel(start_x + x, start_y + height - y, color);
- }
- }
-}
-
-static void clearPPM(unsigned start_x, unsigned start_y, const u8 *data)
-{
- unsigned width, height;
-
- /* get image dimensions */
- uiGetPPMInfo(data, &width, &height);
-
- u16 color = 0;
-
- for(unsigned x = 0; x < width; x++)
- {
- for(unsigned y = height; y > 0; y--)
- {
- drawPixel(start_x + x, start_y + height - y, color);
- }
- }
-}
-
void uiPrintBootWarning()
{
- u8 *buf = (u8*)malloc(0x39CD);
- if(!buf) return;
-
- lzssDecompress(bootWarningData + 4, buf, 0x39CD);
- unsigned width, height;
- uiGetPPMInfo(buf, &width, &height);
- uiDrawPPM((SCREEN_WIDTH_TOP - width) / 2, SCREEN_HEIGHT_TOP + 10, buf);
-
- free(buf);
+ drawSplashscreen(bootWarningData);
TIMER_sleep(400);
}
void uiPrintBootFailure()
{
- u8 *buf = (u8*)malloc(0x39CD);
- if(!buf) return;
-
- lzssDecompress(bootWarningData + 4, buf, 0x39CD);
- unsigned width, height;
- uiGetPPMInfo(buf, &width, &height);
- clearPPM((SCREEN_WIDTH_TOP - width) / 2, SCREEN_HEIGHT_TOP + 10, buf);
-
- lzssDecompress(bootFailureData + 4, buf, 0x304F);
- uiGetPPMInfo(buf, &width, &height);
- uiDrawPPM((SCREEN_WIDTH_TOP - width) / 2, SCREEN_HEIGHT_TOP + 10, buf);
-
- free(buf);
+ drawSplashscreen(bootFailureData);
TIMER_sleep(400);
}