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); }