working test frame

This commit is contained in:
sillysagiri 2023-12-23 12:39:40 +07:00
parent ee6ded0087
commit b06d010df6
25 changed files with 8386 additions and 1725 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

6
.gitignore vendored
View File

@ -1,6 +1,10 @@
/assets/* /assets/*.*
/assets/out/*.bmp
!/assets/convert.sh !/assets/convert.sh
/build
/build*
/NDS/nitrofiles/* /NDS/nitrofiles/*
!/NDS/nitrofiles/.gitignore !/NDS/nitrofiles/.gitignore
/NDS/cmake /NDS/cmake

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "vendor/FastLZ"]
path = vendor/FastLZ
url = ssh://git@192.168.0.100:3022/MirrorRepo/FastLZ.git

5
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,5 @@
{
"clangd.arguments": [
"--query-driver=/opt/devkitpro/devkitARM/bin/arm-none-eabi-g++"
]
}

43
CMakeLists.txt Executable file
View File

@ -0,0 +1,43 @@
cmake_minimum_required(VERSION 3.27)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(PROJECT_NAME "badapple")
set(NDSTOOL_NAME ${PROJECT_NAME} CACHE BOOL "")
set(NDSTOOL_SUBTITLE1 "Created by sillysagiri" CACHE BOOL "")
set(NDSTOOL_SUBTITLE2 "sillysagiri.my.id" CACHE BOOL "")
set(NDSTOOL_NITROFS "resource" CACHE BOOL "")
# add_subdirectory(arm9)
set(NDSTOOL_ARM7 "${CMAKE_BINARY_DIR}/arm7/arm7.elf" CACHE BOOL "")
# set(NDSTOOL_ARM9 arm9 CACHE BOOL "")
project(${PROJECT_NAME})
file(GLOB_RECURSE PROJECT_SOURCES CONFIGURE_DEPENDS "src/*.cpp")
file(GLOB VENDOR_SOURCES CONFIGURE_DEPENDS "vendor/FastLZ/fastlz.c")
set(PROJECT_INCLUDE
"src"
"vendor/FastLZ")
set(PROJECT_VENDOR
"filesystem"
"fat")
add_executable(${PROJECT_NAME} ${PROJECT_SOURCES} ${VENDOR_SOURCES})
target_include_directories(${PROJECT_NAME} PRIVATE ${PROJECT_INCLUDE})
target_link_libraries(${PROJECT_NAME} PUBLIC ${PROJECT_VENDOR})
nds_create_rom(${PROJECT_NAME})
# yeah i know its stupid, but its working!!
add_custom_command(
TARGET ${PROJECT_NAME} PRE_BUILD
COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/arm7
COMMAND ${DEVKITPRO}/portlibs/nds/bin/arm-none-eabi-cmake -S ${CMAKE_SOURCE_DIR}/arm7 ${CMAKE_BINARY_DIR}/arm7
COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR}/arm7
)

21
arm7/CMakeLists.txt Executable file
View File

@ -0,0 +1,21 @@
cmake_minimum_required(VERSION 3.10)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# armv5te arm9
# armv4t arm7
set(CMAKE_SYSTEM_PROCESSOR "armv4t")
project(arm7)
set(PROJECT_INCLUDE
"src")
file(GLOB PROJECT_SOURCES CONFIGURE_DEPENDS
"src/*.cpp"
"src/**/*.cpp")
add_executable(arm7 ${PROJECT_SOURCES})
target_include_directories(arm7 PRIVATE ${PROJECT_INCLUDE})
target_link_libraries(arm7 PUBLIC dswifi7 mm7)

98
arm7/src/main.cpp Executable file
View File

@ -0,0 +1,98 @@
/*---------------------------------------------------------------------------------
default ARM7 core
Copyright (C) 2005 - 2010
Michael Noland (joat)
Jason Rogers (dovoto)
Dave Murphy (WinterMute)
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you
must not claim that you wrote the original software. If you use
this software in a product, an acknowledgment in the product
documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
---------------------------------------------------------------------------------*/
#include <nds.h>
#include <dswifi7.h>
#include <maxmod7.h>
//---------------------------------------------------------------------------------
void VblankHandler(void) {
//---------------------------------------------------------------------------------
Wifi_Update();
}
//---------------------------------------------------------------------------------
void VcountHandler() {
//---------------------------------------------------------------------------------
inputGetAndSend();
}
volatile bool exitflag = false;
//---------------------------------------------------------------------------------
void powerButtonCB() {
//---------------------------------------------------------------------------------
exitflag = true;
}
//---------------------------------------------------------------------------------
int main() {
//---------------------------------------------------------------------------------
// clear sound registers
dmaFillWords(0, (void*)0x04000400, 0x100);
REG_SOUNDCNT |= SOUND_ENABLE;
writePowerManagement(PM_CONTROL_REG, ( readPowerManagement(PM_CONTROL_REG) & ~PM_SOUND_MUTE ) | PM_SOUND_AMP );
powerOn(POWER_SOUND);
readUserSettings();
ledBlink(0);
irqInit();
// Start the RTC tracking IRQ
initClockIRQ();
fifoInit();
touchInit();
mmInstall(FIFO_MAXMOD);
SetYtrigger(80);
installWifiFIFO();
installSoundFIFO();
installSystemFIFO();
irqSet(IRQ_VCOUNT, VcountHandler);
irqSet(IRQ_VBLANK, VblankHandler);
irqEnable( IRQ_VBLANK | IRQ_VCOUNT | IRQ_NETWORK);
setPowerButtonCB(powerButtonCB);
// Keep the ARM7 mostly idle
while (!exitflag) {
if ( 0 == (REG_KEYINPUT & (KEY_A | KEY_B))) {
exitflag = true;
}
swiWaitForVBlank();
}
return 0;
}

View File

@ -2,9 +2,9 @@
palette="palette.png" palette="palette.png"
video="video.mp4" video="video.mp4"
output="out.gif" output="out/out_%d.bmp"
filters="fps=30,scale=256x192" filters="fps=60,scale=256x192"
skip="-t 1 -ss 00:8" skip="-t 1 -ss 00:8"
# old # old

0
assets/out/.keep Normal file
View File

22
encoder/CMakeLists.txt Normal file
View File

@ -0,0 +1,22 @@
cmake_minimum_required(VERSION 3.27)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(PROJECT_NAME "encoder")
project(${PROJECT_NAME})
file(GLOB_RECURSE PROJECT_SOURCES CONFIGURE_DEPENDS "*.cpp")
file(GLOB VENDOR_SOURCES CONFIGURE_DEPENDS "../vendor/FastLZ/fastlz.c")
set(PROJECT_INCLUDE
"encoder"
"../vendor/FastLZ")
set(PROJECT_VENDOR
"")
add_executable(${PROJECT_NAME} ${PROJECT_SOURCES} ${VENDOR_SOURCES})
target_include_directories(${PROJECT_NAME} PRIVATE ${PROJECT_INCLUDE})
target_link_libraries(${PROJECT_NAME} PUBLIC ${PROJECT_VENDOR})

View File

@ -1,474 +0,0 @@
/*----------------------------------------------------------------------------*/
/*-- lzss.c - LZSS coding for Nintendo GBA/DS --*/
/*-- Copyright (C) 2011 CUE --*/
/*-- Slightly modified by Ngawung --*/
/*-- --*/
/*-- 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 <http://www.gnu.org/licenses/>. --*/
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*----------------------------------------------------------------------------*/
#define CMD_DECODE 0x00 // decode
#define CMD_CODE_10 0x10 // LZSS magic number
#define LZS_NORMAL 0x00 // normal mode, (0)
#define LZS_FAST 0x80 // fast mode, (1 << 7)
#define LZS_BEST 0x40 // best mode, (1 << 6)
#define LZS_WRAM 0x00 // VRAM not compatible (LZS_WRAM | LZS_NORMAL)
#define LZS_VRAM 0x01 // VRAM compatible (LZS_VRAM | LZS_NORMAL)
#define LZS_WFAST 0x80 // LZS_WRAM fast (LZS_WRAM | LZS_FAST)
#define LZS_VFAST 0x81 // LZS_VRAM fast (LZS_VRAM | LZS_FAST)
#define LZS_WBEST 0x40 // LZS_WRAM best (LZS_WRAM | LZS_BEST)
#define LZS_VBEST 0x41 // LZS_VRAM best (LZS_VRAM | LZS_BEST)
#define LZS_SHIFT 1 // bits to shift
#define LZS_MASK 0x80 // bits to check:
// ((((1 << LZS_SHIFT) - 1) << (8 - LZS_SHIFT)
#define LZS_THRESHOLD 2 // max number of bytes to not encode
#define LZS_N 0x1000 // max offset (1 << 12)
#define LZS_F 0x12 // max coded ((1 << 4) + LZS_THRESHOLD)
#define LZS_NIL LZS_N // index for root of binary search trees
#define RAW_MINIM 0x00000000 // empty file, 0 bytes
#define RAW_MAXIM 0x00FFFFFF // 3-bytes length, 16MB - 1
#define LZS_MINIM 0x00000004 // header only (empty RAW file)
#define LZS_MAXIM 0x01400000 // 0x01200003, padded to 20MB:
// * header, 4
// * length, RAW_MAXIM
// * flags, (RAW_MAXIM + 7) / 8
// 4 + 0x00FFFFFF + 0x00200000 + padding
/*----------------------------------------------------------------------------*/
unsigned char ring[LZS_N + LZS_F - 1];
int dad[LZS_N + 1], lson[LZS_N + 1], rson[LZS_N + 1 + 256];
int pos_ring, len_ring, lzs_vram;
/*----------------------------------------------------------------------------*/
#define BREAK(text) { printf(text); return; }
#define EXIT(text) { printf(text); exit(-1); }
/*----------------------------------------------------------------------------*/
unsigned char *Load(char *filename, unsigned int *length, int min, int max);
void Save(char *filename, unsigned char *buffer, int length);
unsigned char *Memory(int length, int size);
void LZS_Decode(char *filename);
void LZS_Encode(char *filename, int mode);
unsigned char *LZS_Code(unsigned char *raw_buffer, int raw_len, unsigned int *new_len, int best);
unsigned char *LZS_Fast(unsigned char *raw_buffer, int raw_len, unsigned int *new_len);
void LZS_InitTree(void);
void LZS_InsertNode(int r);
void LZS_DeleteNode(int p);
/*----------------------------------------------------------------------------*/
int main(int argc, char **argv) {
int cmd, mode;
int arg;
if (argc < 2) EXIT("Filename not specified\n");
// for (arg = 2; arg < argc; arg++) LZS_Decode(argv[arg]);
for (arg = 1; arg < argc; arg++) LZS_Encode(argv[arg], LZS_WFAST);
printf("\nDone\n");
return(0);
}
/*----------------------------------------------------------------------------*/
unsigned char *Load(char *filename, unsigned int *length, int min, int max) {
FILE *fp;
int fs;
unsigned char *fb;
if ((fp = fopen(filename, "rb")) == NULL) EXIT("\nFile open error\n");
// fs = filelength(fileno(fp));
fseek(fp, 0, SEEK_END);
fs = ftell(fp);
fseek(fp, 0, SEEK_SET);
if ((fs < min) || (fs > max)) EXIT("\nFile size error\n");
fb = Memory(fs + 3, sizeof(char));
if (fread(fb, 1, fs, fp) != fs) EXIT("\nFile read error\n");
if (fclose(fp) == EOF) EXIT("\nFile close error\n");
*length = fs;
return(fb);
}
/*----------------------------------------------------------------------------*/
void Save(char *filename, unsigned char *buffer, int length) {
FILE *fp;
if ((fp = fopen(filename, "wb")) == NULL) EXIT("\nFile create error\n");
u_int16_t newLength = length;
fwrite(&newLength, sizeof(newLength), 1, fp);
if (fwrite(buffer, 1, length, fp) != length) EXIT("\nFile write error\n");
if (fclose(fp) == EOF) EXIT("\nFile close error\n");
}
/*----------------------------------------------------------------------------*/
unsigned char *Memory(int length, int size) {
unsigned char *fb;
fb = (unsigned char *) calloc(length * size, size);
if (fb == NULL) EXIT("\nMemory error\n");
return(fb);
}
/*----------------------------------------------------------------------------*/
void LZS_Decode(char *filename) {
unsigned char *pak_buffer, *raw_buffer, *pak, *raw, *pak_end, *raw_end;
unsigned int pak_len, raw_len, header, len, pos;
unsigned char flags, mask;
printf("- decoding '%s'", filename);
pak_buffer = Load(filename, &pak_len, LZS_MINIM, LZS_MAXIM);
header = *pak_buffer;
if (header != CMD_CODE_10) {
free(pak_buffer);
BREAK(", WARNING: file is not LZSS encoded!\n");
}
raw_len = *(unsigned int *)pak_buffer >> 8;
raw_buffer = (unsigned char *) Memory(raw_len, sizeof(char));
pak = pak_buffer + 4;
raw = raw_buffer;
pak_end = pak_buffer + pak_len;
raw_end = raw_buffer + raw_len;
mask = 0;
while (raw < raw_end) {
if (!(mask >>= LZS_SHIFT)) {
if (pak == pak_end) break;
flags = *pak++;
mask = LZS_MASK;
}
if (!(flags & mask)) {
if (pak == pak_end) break;
*raw++ = *pak++;
} else {
if (pak + 1 >= pak_end) break;
pos = *pak++;
pos = (pos << 8) | *pak++;
len = (pos >> 12) + LZS_THRESHOLD + 1;
if (raw + len > raw_end) {
printf(", WARNING: wrong decoded length!");
len = raw_end - raw;
}
pos = (pos & 0xFFF) + 1;
while (len--) *raw++ = *(raw - pos);
}
}
raw_len = raw - raw_buffer;
if (raw != raw_end) printf(", WARNING: unexpected end of encoded file!");
Save(filename, raw_buffer, raw_len);
free(raw_buffer);
free(pak_buffer);
printf("\n");
}
/*----------------------------------------------------------------------------*/
void LZS_Encode(char *filename, int mode) {
unsigned char *raw_buffer, *pak_buffer, *new_buffer;
unsigned int raw_len, pak_len, new_len;
lzs_vram = mode & 0xF;
printf("- encoding '%s'", filename);
raw_buffer = Load(filename, &raw_len, RAW_MINIM, RAW_MAXIM);
pak_buffer = NULL;
pak_len = LZS_MAXIM + 1;
if (!(mode & LZS_FAST)) {
mode = mode & LZS_BEST ? 1 : 0;
new_buffer = LZS_Code(raw_buffer, raw_len, &new_len, mode);
} else {
new_buffer = LZS_Fast(raw_buffer, raw_len, &new_len);
}
if (new_len < pak_len) {
if (pak_buffer != NULL) free(pak_buffer);
pak_buffer = new_buffer;
pak_len = new_len;
}
Save(filename, pak_buffer, pak_len);
free(pak_buffer);
free(raw_buffer);
printf("\n");
}
/*----------------------------------------------------------------------------*/
unsigned char *LZS_Code(unsigned char *raw_buffer, int raw_len, unsigned int *new_len, int best) {
unsigned char *pak_buffer, *pak, *raw, *raw_end, *flg;
unsigned int pak_len, len, pos, len_best, pos_best;
unsigned int len_next, pos_next, len_post, pos_post;
unsigned char mask;
#define SEARCH(l,p) { \
l = LZS_THRESHOLD; \
\
pos = raw - raw_buffer >= LZS_N ? LZS_N : raw - raw_buffer; \
for ( ; pos > lzs_vram; pos--) { \
for (len = 0; len < LZS_F; len++) { \
if (raw + len == raw_end) break; \
if (*(raw + len) != *(raw + len - pos)) break; \
} \
\
if (len > l) { \
p = pos; \
if ((l = len) == LZS_F) break; \
} \
} \
}
pak_len = 4 + raw_len + ((raw_len + 7) / 8);
pak_buffer = (unsigned char *) Memory(pak_len, sizeof(char));
*(unsigned int *)pak_buffer = CMD_CODE_10 | (raw_len << 8);
pak = pak_buffer + 4;
raw = raw_buffer;
raw_end = raw_buffer + raw_len;
mask = 0;
while (raw < raw_end) {
if (!(mask >>= LZS_SHIFT)) {
*(flg = pak++) = 0;
mask = LZS_MASK;
}
SEARCH(len_best, pos_best);
// LZ-CUE optimization start
if (best) {
if (len_best > LZS_THRESHOLD) {
if (raw + len_best < raw_end) {
raw += len_best;
SEARCH(len_next, pos_next);
raw -= len_best - 1;
SEARCH(len_post, pos_post);
raw--;
if (len_next <= LZS_THRESHOLD) len_next = 1;
if (len_post <= LZS_THRESHOLD) len_post = 1;
if (len_best + len_next <= 1 + len_post) len_best = 1;
}
}
}
// LZ-CUE optimization end
if (len_best > LZS_THRESHOLD) {
raw += len_best;
*flg |= mask;
*pak++ = ((len_best - (LZS_THRESHOLD + 1)) << 4) | ((pos_best - 1) >> 8);
*pak++ = (pos_best - 1) & 0xFF;
} else {
*pak++ = *raw++;
}
}
*new_len = pak - pak_buffer;
return(pak_buffer);
}
/*----------------------------------------------------------------------------*/
unsigned char *LZS_Fast(unsigned char *raw_buffer, int raw_len, unsigned int *new_len) {
unsigned char *pak_buffer, *pak, *raw, *raw_end, *flg;
unsigned int pak_len, len, r, s, len_tmp, i;
unsigned char mask;
pak_len = 4 + raw_len + ((raw_len + 7) / 8);
pak_buffer = (unsigned char *) Memory(pak_len, sizeof(char));
*(unsigned int *)pak_buffer = CMD_CODE_10 | (raw_len << 8);
pak = pak_buffer + 4;
raw = raw_buffer;
raw_end = raw_buffer + raw_len;
LZS_InitTree();
r = s = 0;
len = raw_len < LZS_F ? raw_len : LZS_F;
while (r < LZS_N - len) ring[r++] = 0;
for (i = 0; i < len; i++) ring[r + i] = *raw++;
LZS_InsertNode(r);
mask = 0;
while (len) {
if (!(mask >>= LZS_SHIFT)) {
*(flg = pak++) = 0;
mask = LZS_MASK;
}
if (len_ring > len) len_ring = len;
if (len_ring > LZS_THRESHOLD) {
*flg |= mask;
pos_ring = ((r - pos_ring) & (LZS_N - 1)) - 1;
*pak++ = ((len_ring - LZS_THRESHOLD - 1) << 4) | (pos_ring >> 8);
*pak++ = pos_ring & 0xFF;
} else {
len_ring = 1;
*pak++ = ring[r];
}
len_tmp = len_ring;
for (i = 0; i < len_tmp; i++) {
if (raw == raw_end) break;
LZS_DeleteNode(s);
ring[s] = *raw++;
if (s < LZS_F - 1) ring[s + LZS_N] = ring[s];
s = (s + 1) & (LZS_N - 1);
r = (r + 1) & (LZS_N - 1);
LZS_InsertNode(r);
}
while (i++ < len_tmp) {
LZS_DeleteNode(s);
s = (s + 1) & (LZS_N - 1);
r = (r + 1) & (LZS_N - 1);
if (--len) LZS_InsertNode(r);
}
}
*new_len = pak - pak_buffer;
return(pak_buffer);
}
/*----------------------------------------------------------------------------*/
void LZS_InitTree(void) {
int i;
for (i = LZS_N + 1; i <= LZS_N + 256; i++)
rson[i] = LZS_NIL;
for (i = 0; i < LZS_N; i++)
dad[i] = LZS_NIL;
}
/*----------------------------------------------------------------------------*/
void LZS_InsertNode(int r) {
unsigned char *key;
int i, p, cmp, prev;
prev = (r - 1) & (LZS_N - 1);
cmp = 1;
len_ring = 0;
key = &ring[r];
p = LZS_N + 1 + key[0];
rson[r] = lson[r] = LZS_NIL;
for ( ; ; ) {
if (cmp >= 0) {
if (rson[p] != LZS_NIL) p = rson[p];
else { rson[p] = r; dad[r] = p; return; }
} else {
if (lson[p] != LZS_NIL) p = lson[p];
else { lson[p] = r; dad[r] = p; return; }
}
for (i = 1; i < LZS_F; i++)
if ((cmp = key[i] - ring[p + i])) break;
if (i > len_ring) {
if (!lzs_vram || (p != prev)) {
pos_ring = p;
if ((len_ring = i) == LZS_F) break;
}
}
}
dad[r] = dad[p]; lson[r] = lson[p]; rson[r] = rson[p];
dad[lson[p]] = r; dad[rson[p]] = r;
if (rson[dad[p]] == p) rson[dad[p]] = r;
else lson[dad[p]] = r;
dad[p] = LZS_NIL;
}
/*----------------------------------------------------------------------------*/
void LZS_DeleteNode(int p) {
int q;
if (dad[p] == LZS_NIL) return;
if (rson[p] == LZS_NIL) {
q = lson[p];
} else if (lson[p] == LZS_NIL) {
q = rson[p];
} else {
q = lson[p];
if (rson[q] != LZS_NIL) {
do {
q = rson[q];
} while (rson[q] != LZS_NIL);
rson[dad[q]] = lson[q]; dad[lson[q]] = dad[q];
lson[q] = lson[p]; dad[lson[p]] = q;
}
rson[q] = rson[p]; dad[rson[p]] = q;
}
dad[q] = dad[p];
if (rson[dad[p]] == p) rson[dad[p]] = q;
else lson[dad[p]] = q;
dad[p] = LZS_NIL;
}
/*----------------------------------------------------------------------------*/
/*-- EOF Copyright (C) 2011 CUE --*/
/*----------------------------------------------------------------------------*/

View File

@ -1,638 +0,0 @@
/*
Author: Leon Etienne
Copyright (c) 2021, Leon Etienne
https://github.com/Leonetienne
https://github.com/Leonetienne/BMPlib
License:
Don't Be a Jerk: The Open Source Software License. Last Update: Jan, 7, 2021
This software is free and open source.
Please read the full license: https://github.com/Leonetienne/BMPlib/blob/master/license.txt
#define BMPLIB_SILENT
if you want bmplib to stop writing exceptions to stderr
*/
#pragma once
#include <sstream>
#include <fstream>
#include <string.h>
#define BMPLIB_VERSION 0.602
namespace BMPlib
{
typedef unsigned char byte;
typedef unsigned short byte2;
typedef unsigned int byte4;
using bytestring = std::basic_string<byte>;
using bytestream = std::basic_stringstream<byte>;
template<typename T>
// Will convert (int)15 to 0F 00 00 00 and NOT TO 00 00 00 0F
bytestring ToBytes(T t)
{
bytestream toret;
long long sizeofT = (long long)sizeof(T); // Let's make it a signed value to keep the compiler happy with the comparison
byte* bPtr = (byte*)&t;
for (long long i = 0; i < sizeofT; i++)
toret << *(bPtr + i);
return toret.str();
}
template<typename ST, typename SO, typename T>
// Will convert 0F 00 00 00 to 15 and NOT TO 251658240
std::basic_istream<ST, SO>& FromBytes(std::basic_istream<ST, SO>& is, T& b)
{
const std::size_t sizeofT = sizeof(T);
b = 0x0;
byte buf;
for (std::size_t i = 0; i < sizeofT; i++)
{
is.read((ST*)&buf, 1);
T bbuf = buf << (i * 8);
b |= bbuf;
}
return is;
}
class BMP
{
public:
enum class COLOR_MODE
{
BW, // This is a special case, since BMP doesn't support 1 channel. It is just RGB, but with a 1-channel pixel buffer
RGB,
RGBA
};
BMP() noexcept
{
width = 0;
height = 0;
colorMode = COLOR_MODE::BW;
sizeofPxlbfr = 0;
numChannelsFile = 0;
numChannelsPXBF = 0;
pixelbfr = nullptr;
isInitialized = false;
return;
}
explicit BMP(const std::size_t& width, const std::size_t& height, const BMP::COLOR_MODE& colorMode = BMP::COLOR_MODE::RGB)
: isInitialized{false}
{
ReInitialize(width, height, colorMode);
return;
}
void ReInitialize(const std::size_t& width, const std::size_t& height, const BMP::COLOR_MODE& colorMode = BMP::COLOR_MODE::RGB)
{
if ((!width) || (!height)) ThrowException("Bad image dimensions!");
// Initialize bunch of stuff
this->width = width;
this->height = height;
this->colorMode = colorMode;
switch (colorMode)
{
case COLOR_MODE::BW:
numChannelsFile = 3;
numChannelsPXBF = 1;
break;
case COLOR_MODE::RGB:
numChannelsFile = 3;
numChannelsPXBF = 3;
break;
case COLOR_MODE::RGBA:
numChannelsFile = 4;
numChannelsPXBF = 4;
break;
}
// Delete pixelbuffer if already exists
if (isInitialized) delete[] pixelbfr;
sizeofPxlbfr = sizeof(byte) * width * height * numChannelsPXBF;
// Try to allocate memory for the pixelbuffer
try
{
pixelbfr = new byte[sizeofPxlbfr];
}
catch (std::bad_alloc& e)
{
// too bad!
ThrowException(std::string("Can't allocate memory for pixelbuffer!") + e.what());
}
// Make image black
memset(pixelbfr, 0, sizeofPxlbfr);
isInitialized = true;
return;
}
#ifdef __linux__
#pragma GCC diagnostic push
// g++ doesn't see the parameters, numPx, and curPx getting used inside the switch... we don't want these false warnings
#pragma GCC diagnostic ignored "-Wunused-variable"
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
// Will convert between color modes. Set isNonColorData to true to treat pixeldata as raw values rather than color
void ConvertTo(const BMP::COLOR_MODE& convto, bool isNonColorData = false)
{
// Damn this method is one hell of a mess
if (!isInitialized)
ThrowException("Not initialized!");
byte* tmp_pxlbfr;
try
{
tmp_pxlbfr = new byte[sizeofPxlbfr];
}
catch (std::bad_alloc&e )
{
// too bad!
ThrowException(std::string("Can't allocate memory for temporary conversion pixelbuffer!") + e.what());
return; // This won't ever be reached but it satisfies the compiler, soooo...
}
const std::size_t numPx = width * height;
const std::size_t oldPxlbfrSize = sizeofPxlbfr;
const byte* curPx; // Usage may vary on the conversion in question. It's just a pixel cache for a small performance improvement
memcpy(tmp_pxlbfr, pixelbfr, sizeofPxlbfr);
#ifdef __linux__
#pragma GCC diagnostic pop // Let's enable these warnings again
#endif
switch (colorMode)
{
case COLOR_MODE::BW:
#ifndef __linux__
#pragma region CONVERT_FROM_BW
#endif
switch (convto)
{
case COLOR_MODE::RGB:
// BW -> RGB
ReInitialize(width, height, COLOR_MODE::RGB);
for (std::size_t i = 0; i < numPx; i++)
{
curPx = tmp_pxlbfr + i;
pixelbfr[i * 3 + 0] = *curPx;
pixelbfr[i * 3 + 1] = *curPx;
pixelbfr[i * 3 + 2] = *curPx;
}
break;
case COLOR_MODE::RGBA:
// BW -> RGBA
ReInitialize(width, height, COLOR_MODE::RGBA);
for (std::size_t i = 0; i < numPx; i++)
{
curPx = tmp_pxlbfr + i;
pixelbfr[i * 4 + 0] = *curPx;
pixelbfr[i * 4 + 1] = *curPx;
pixelbfr[i * 4 + 2] = *curPx;
pixelbfr[i * 4 + 3] = 0xFF;
}
break;
default:
break;
}
#ifndef __linux__
#pragma endregion
#endif
break;
case COLOR_MODE::RGB:
#ifndef __linux__
#pragma region CONVERT_FROM_RGB
#endif
switch (convto)
{
case COLOR_MODE::BW:
// RGB -> BW
ReInitialize(width, height, COLOR_MODE::BW);
for (std::size_t i = 0; i < numPx; i++)
{
curPx = tmp_pxlbfr + i * 3;
// Don't ask me why but the compiler hates dereferencing tmp_pxlbfr/curPx via [] and throws false warnings...
if (isNonColorData)
pixelbfr[i] = (byte)((
*(curPx + 0) +
*(curPx + 1) +
*(curPx + 2)) * 0.33333333);
else
pixelbfr[i] = (byte)(
*(curPx + 0) * 0.3 +
*(curPx + 1) * 0.59 +
*(curPx + 2) * 0.11);
}
break;
case COLOR_MODE::RGBA:
// RGB -> RGBA
ReInitialize(width, height, COLOR_MODE::RGBA);
for (std::size_t i = 0; i < numPx; i++)
{
curPx = tmp_pxlbfr + i * 3;
pixelbfr[i * 4 + 0] = *(curPx + 0);
pixelbfr[i * 4 + 1] = *(curPx + 1);
pixelbfr[i * 4 + 2] = *(curPx + 2);
pixelbfr[i * 4 + 3] = 0xFF;
}
break;
default:
break;
}
#ifndef __linux__
#pragma endregion
#endif
break;
case COLOR_MODE::RGBA:
#ifndef __linux__
#pragma region CONVERT_FROM_RGBA
#endif
switch (convto)
{
case COLOR_MODE::BW:
// RGBA -> BW
ReInitialize(width, height, COLOR_MODE::BW);
for (std::size_t i = 0; i < numPx; i++)
{
curPx = tmp_pxlbfr + i * 4;
if (isNonColorData)
pixelbfr[i] = (byte)((
*(curPx + 0) +
*(curPx + 1) +
*(curPx + 2)) * 0.33333333);
else
pixelbfr[i] = (byte)(
*(curPx + 0) * 0.3 +
*(curPx + 1) * 0.59 +
*(curPx + 2) * 0.11);
}
break;
case COLOR_MODE::RGB:
// RGBA -> RGB
ReInitialize(width, height, COLOR_MODE::RGB);
for (std::size_t i = 0; i < numPx; i++)
{
curPx = tmp_pxlbfr + i * 4;
pixelbfr[i * 3 + 0] = *(curPx + 0);
pixelbfr[i * 3 + 1] = *(curPx + 1);
pixelbfr[i * 3 + 2] = *(curPx + 2);
}
break;
default:
break;
}
#ifndef __linux__
#pragma endregion
#endif
break;
}
delete[] tmp_pxlbfr;
return;
}
byte* GetPixelBuffer() noexcept
{
return pixelbfr;
}
const byte* GetPixelBuffer() const noexcept
{
return pixelbfr;
}
std::size_t GetWidth() const noexcept
{
return width;
}
std::size_t GetHeight() const noexcept
{
return height;
}
COLOR_MODE GetColorMode() const noexcept
{
return colorMode;
}
bool IsInitialized() const noexcept
{
return isInitialized;
}
std::size_t CalculatePixelIndex(const std::size_t& x, const std::size_t& y) const
{
if ((x >= width) || (y >= height)) ThrowException("Pixel coordinates out of range!");
return numChannelsPXBF * ((y * width) + x);
}
byte* GetPixel(const std::size_t& x, const std::size_t& y)
{
return pixelbfr + CalculatePixelIndex(x, y);
}
const byte* GetPixel(const std::size_t& x, const std::size_t& y) const
{
return pixelbfr + CalculatePixelIndex(x, y);
}
// Sets a pixels color
// If using RGBA, use all
// If using RGB, a gets ignored
// If using BW, use only r
void SetPixel(const std::size_t& x, const std::size_t& y, const byte& r, const byte& g = 0, const byte& b = 0, const byte& a = 0)
{
byte* px = GetPixel(x, y);
switch (colorMode)
{
case COLOR_MODE::BW:
px[0] = r;
break;
case COLOR_MODE::RGB:
px[0] = r;
px[1] = g;
px[2] = b;
break;
case COLOR_MODE::RGBA:
px[0] = r;
px[1] = g;
px[2] = b;
px[3] = a;
break;
}
return;
}
// Will write a bmp image
bool Write(const std::string& filename)
{
if (!isInitialized)
return false;
std::size_t paddingSize = (4 - ((width * numChannelsFile) % 4)) % 4; // number of padding bytes per scanline
byte paddingData[4] = { 0x69,0x69,0x69,0x69 }; // dummy-data for padding
bytestream data;
data
// BMP Header
<< ToBytes(byte2(0x4D42)) // signature
<< ToBytes(byte4(0x36 + sizeofPxlbfr + paddingSize * height)) // size of the bmp file (all bytes)
<< ToBytes(byte2(0)) // unused
<< ToBytes(byte2(0)) // unused
<< ToBytes(byte4(0x36)) // Offset where the pixel array begins (size of both headers)
// DIB Header
<< ToBytes(byte4(0x28)) // Number of bytes in DIB header (without this field)
<< ToBytes(byte4(width)) // width
<< ToBytes(byte4(height)) // height
<< ToBytes(byte2(1)) // number of planes used
<< ToBytes(byte2(numChannelsFile * 8)) // bit-depth
<< ToBytes(byte4(0)) // no compression
<< ToBytes(byte4(sizeofPxlbfr + paddingSize * height)) // Size of raw bitmap data (including padding)
<< ToBytes(byte4(0xB13)) // print resolution pixels/meter X
<< ToBytes(byte4(0xB13)) // print resolution pixels/meter Y
<< ToBytes(byte4(0)) // 0 colors in the color palette
<< ToBytes(byte4(0)); // 0 means all colors are important
// Dumbass unusual pixel order of bmp made me do this...
for (long long y = height - 1; y >= 0; y--)
{
for (std::size_t x = 0; x < width; x++)
{
std::size_t idx = CalculatePixelIndex(x, (std::size_t)y); // No precision lost here. I just need a type that can get as large as std::size_t but is also signed (because for y >= 0)
switch (colorMode)
{
case COLOR_MODE::BW:
// pixelbfr ==> R-G-B ==> B-G-R ==> bmp format
data.write((pixelbfr + idx), 1); // B
data.write((pixelbfr + idx), 1); // G
data.write((pixelbfr + idx), 1); // R
break;
case COLOR_MODE::RGB:
// pixelbfr ==> R-G-B ==> B-G-R ==> bmp format
data.write((pixelbfr + idx + 2), 1); // B
data.write((pixelbfr + idx + 1), 1); // G
data.write((pixelbfr + idx + 0), 1); // R
break;
case COLOR_MODE::RGBA:
// pixelbfr ==> R-G-B-A ==> B-G-R-A ==> bmp format
data.write((pixelbfr + idx + 2), 1); // B
data.write((pixelbfr + idx + 1), 1); // G
data.write((pixelbfr + idx + 0), 1); // R
data.write((pixelbfr + idx + 3), 1); // A
break;
}
}
if ((colorMode == COLOR_MODE::BW) || (colorMode == COLOR_MODE::RGB))
if (paddingSize > 0)
data.write(paddingData, paddingSize);
}
// write file
std::ofstream bs;
bs.open(filename, std::ofstream::binary);
if (!bs.good())
return false;
bytestring bytes = data.str();
bs.write((const char*)bytes.c_str(), bytes.length());
bs.flush();
bs.close();
return true;
}
// Will read a bmp image
bool Read(std::string filename)
{
std::ifstream bs;
bs.open(filename, std::ifstream::binary);
if (!bs.good())
return false;
// Check BMP signature
byte2 signature;
FromBytes(bs, signature);
if (signature != 0x4D42)
return false;
// Gather filesize
byte4 fileLen;
FromBytes(bs, fileLen);
byte2 unused0;
byte2 unused1;
FromBytes(bs, unused0);
FromBytes(bs, unused1);
byte4 offsetPixelArray;
FromBytes(bs, offsetPixelArray);
byte4 dibHeadLen;
FromBytes(bs, dibHeadLen);
// Gather image dimensions
byte4 imgWidth;
byte4 imgHeight;
FromBytes(bs, imgWidth);
FromBytes(bs, imgHeight);
byte2 numPlanes;
FromBytes(bs, numPlanes);
// Gather image bit-depth
byte2 bitDepth;
FromBytes(bs, bitDepth);
switch (bitDepth)
{
// BW is not supported so we can't read a bw image
case 24:
colorMode = COLOR_MODE::RGB;
break;
case 32:
colorMode = COLOR_MODE::RGBA;
}
byte4 compression;
FromBytes(bs, compression);
// Gather size of pixel buffer
byte4 sizeofPixelBuffer;
FromBytes(bs, sizeofPixelBuffer);
byte4 printresX;
byte4 printresY;
FromBytes(bs, printresX);
FromBytes(bs, printresY);
byte4 colorsInPalette;
byte4 importantColors;
FromBytes(bs, colorsInPalette);
FromBytes(bs, importantColors);
// Go to the beginning of the pixel array
bs.seekg(offsetPixelArray);
// Initialize image
ReInitialize(imgWidth, imgHeight, colorMode);
// Calculate scanline padding size
std::size_t paddingSize = (4 - ((width * numChannelsFile) % 4)) % 4;
paddingSize = paddingSize < 4 ? paddingSize : 0;
// Dumbass unusual pixel order of bmp made me do this...
for (long long y = imgHeight - 1; y >= 0; y--)
{
std::size_t byteCounter = 0;
for (std::size_t x = 0; x < imgWidth; x++)
{
std::size_t idx = CalculatePixelIndex(x, (std::size_t)y); // No precision lost here. I just need a type that can get as large as std::size_t but is also signed (because for y >= 0)
switch (colorMode)
{
case COLOR_MODE::RGB:
// bmp format ==> B-G-R ==> R-G-B ==> pixelbfr
bs.read((char*)(pixelbfr + idx + 2), 1); // Read B byte
bs.read((char*)(pixelbfr + idx + 1), 1); // Read G byte
bs.read((char*)(pixelbfr + idx + 0), 1); // Read R byte
byteCounter += 3;
break;
case COLOR_MODE::RGBA:
// bmp format ==> B-G-R-A ==> R-G-B-A ==> pixelbfr
bs.read((char*)(pixelbfr + idx + 2), 1); // Read B byte
bs.read((char*)(pixelbfr + idx + 1), 1); // Read G byte
bs.read((char*)(pixelbfr + idx + 0), 1); // Read R byte
bs.read((char*)(pixelbfr + idx + 3), 1); // Read A byte
byteCounter += 4;
break;
default:
break;
}
}
if ((colorMode == COLOR_MODE::BW) || (colorMode == COLOR_MODE::RGB)) // RGBA will always be a multiple of 4 bytes
if (byteCounter % 4) // If this scan line was not a multiple of 4 bytes long, account for padding
bs.ignore(paddingSize);
}
bs.close();
return true;
}
~BMP()
{
if (isInitialized)
{
delete[] pixelbfr;
pixelbfr = nullptr;
}
return;
}
private:
void ThrowException(const std::string msg) const
{
#ifndef BMPLIB_SILENT
#ifdef _IOSTREAM_
std::cerr << "BMPlib exception: " << msg << std::endl;
#endif
#endif
throw msg;
return;
}
std::size_t width;
std::size_t height;
std::size_t numChannelsFile; // Num channels of the file format
std::size_t numChannelsPXBF; // Num channels of the pixel buffer
COLOR_MODE colorMode;
bool isInitialized;
byte* pixelbfr;
std::size_t sizeofPxlbfr; // how many bytes the pixelbuffer is long
};
}

View File

@ -1,481 +0,0 @@
/*----------------------------------------------------------------------------*/
/*-- lzss.c - LZSS coding for Nintendo GBA/DS --*/
/*-- Copyright (C) 2011 CUE --*/
/*-- --*/
/*-- 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 <http://www.gnu.org/licenses/>. --*/
/*----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
/*----------------------------------------------------------------------------*/
#define CMD_DECODE 0x00 // decode
#define CMD_CODE_10 0x10 // LZSS magic number
#define LZS_NORMAL 0x00 // normal mode, (0)
#define LZS_FAST 0x80 // fast mode, (1 << 7)
#define LZS_BEST 0x40 // best mode, (1 << 6)
#define LZS_WRAM 0x00 // VRAM not compatible (LZS_WRAM | LZS_NORMAL)
#define LZS_VRAM 0x01 // VRAM compatible (LZS_VRAM | LZS_NORMAL)
#define LZS_WFAST 0x80 // LZS_WRAM fast (LZS_WRAM | LZS_FAST)
#define LZS_VFAST 0x81 // LZS_VRAM fast (LZS_VRAM | LZS_FAST)
#define LZS_WBEST 0x40 // LZS_WRAM best (LZS_WRAM | LZS_BEST)
#define LZS_VBEST 0x41 // LZS_VRAM best (LZS_VRAM | LZS_BEST)
#define LZS_SHIFT 1 // bits to shift
#define LZS_MASK 0x80 // bits to check:
// ((((1 << LZS_SHIFT) - 1) << (8 - LZS_SHIFT)
#define LZS_THRESHOLD 2 // max number of bytes to not encode
#define LZS_N 0x1000 // max offset (1 << 12)
#define LZS_F 0x12 // max coded ((1 << 4) + LZS_THRESHOLD)
#define LZS_NIL LZS_N // index for root of binary search trees
#define RAW_MINIM 0x00000000 // empty file, 0 bytes
#define RAW_MAXIM 0x00FFFFFF // 3-bytes length, 16MB - 1
#define LZS_MINIM 0x00000004 // header only (empty RAW file)
#define LZS_MAXIM 0x01400000 // 0x01200003, padded to 20MB:
// * header, 4
// * length, RAW_MAXIM
// * flags, (RAW_MAXIM + 7) / 8
// 4 + 0x00FFFFFF + 0x00200000 + padding
/*----------------------------------------------------------------------------*/
unsigned char ring[LZS_N + LZS_F - 1];
int dad[LZS_N + 1], lson[LZS_N + 1], rson[LZS_N + 1 + 256];
int pos_ring, len_ring, lzs_vram;
/*----------------------------------------------------------------------------*/
#define BREAK(text) { printf(text); return; }
#define EXIT(text) { printf(text); exit(-1); }
/*----------------------------------------------------------------------------*/
unsigned char *Load(char *filename, unsigned int *length, int min, int max);
void Save(char *filename, unsigned char *buffer, int length);
unsigned char *Memory(int length, int size);
unsigned char *LZS_Code(unsigned char *raw_buffer, int raw_len, unsigned int *new_len, int best);
unsigned char *LZS_Fast(unsigned char *raw_buffer, int raw_len, unsigned int *new_len);
void LZS_InitTree(void);
void LZS_InsertNode(int r);
void LZS_DeleteNode(int p);
/*----------------------------------------------------------------------------*/
// int main(int argc, char **argv) {
// int cmd, mode;
// int arg;
// if (argc < 2) EXIT("Filename not specified\n");
// // for (arg = 2; arg < argc; arg++) LZS_Decode(argv[arg]);
// for (arg = 1; arg < argc; arg++) LZS_Encode(argv[arg], LZS_WFAST);
// printf("\nDone\n");
// return(0);
// }
/*----------------------------------------------------------------------------*/
unsigned char *Load(char *filename, unsigned int *length, int min, int max) {
FILE *fp;
int fs;
unsigned char *fb;
if ((fp = fopen(filename, "rb")) == NULL) EXIT("\nFile open error\n");
// fs = filelength(fileno(fp));
fseek(fp, 0, SEEK_END);
fs = ftell(fp);
fseek(fp, 0, SEEK_SET);
if ((fs < min) || (fs > max)) EXIT("\nFile size error\n");
fb = Memory(fs + 3, sizeof(char));
if (fread(fb, 1, fs, fp) != fs) EXIT("\nFile read error\n");
if (fclose(fp) == EOF) EXIT("\nFile close error\n");
*length = fs;
return(fb);
}
/*----------------------------------------------------------------------------*/
void Save(char *filename, unsigned char *buffer, int length) {
FILE *fp;
if ((fp = fopen(filename, "wb")) == NULL) EXIT("\nFile create error\n");
u_int16_t newLength = length;
fwrite(&newLength, sizeof(newLength), 1, fp);
if (fwrite(buffer, 1, length, fp) != length) EXIT("\nFile write error\n");
if (fclose(fp) == EOF) EXIT("\nFile close error\n");
}
/*----------------------------------------------------------------------------*/
unsigned char *Memory(int length, int size) {
unsigned char *fb;
fb = (unsigned char *) calloc(length, size);
if (fb == NULL) EXIT("\nMemory error\n");
return(fb);
}
/*----------------------------------------------------------------------------*/
void LZS_Decode(char *filename) {
unsigned char *pak_buffer, *raw_buffer, *pak, *raw, *pak_end, *raw_end;
unsigned int pak_len, raw_len, header, len, pos;
unsigned char flags, mask;
printf("- decoding '%s'", filename);
pak_buffer = Load(filename, &pak_len, LZS_MINIM, LZS_MAXIM);
header = *pak_buffer;
if (header != CMD_CODE_10) {
free(pak_buffer);
BREAK(", WARNING: file is not LZSS encoded!\n");
}
raw_len = *(unsigned int *)pak_buffer >> 8;
raw_buffer = (unsigned char *) Memory(raw_len, sizeof(char));
pak = pak_buffer + 4;
raw = raw_buffer;
pak_end = pak_buffer + pak_len;
raw_end = raw_buffer + raw_len;
mask = 0;
while (raw < raw_end) {
if (!(mask >>= LZS_SHIFT)) {
if (pak == pak_end) break;
flags = *pak++;
mask = LZS_MASK;
}
if (!(flags & mask)) {
if (pak == pak_end) break;
*raw++ = *pak++;
} else {
if (pak + 1 >= pak_end) break;
pos = *pak++;
pos = (pos << 8) | *pak++;
len = (pos >> 12) + LZS_THRESHOLD + 1;
if (raw + len > raw_end) {
printf(", WARNING: wrong decoded length!");
len = raw_end - raw;
}
pos = (pos & 0xFFF) + 1;
while (len--) *raw++ = *(raw - pos);
}
}
raw_len = raw - raw_buffer;
if (raw != raw_end) printf(", WARNING: unexpected end of encoded file!");
Save(filename, raw_buffer, raw_len);
free(raw_buffer);
free(pak_buffer);
printf("\n");
}
/*----------------------------------------------------------------------------*/
// void LZS_Encode(char *filename, int mode) {
void LZS_Encode(unsigned char*data, unsigned int length) {
unsigned char *raw_buffer, *pak_buffer, *new_buffer;
unsigned int raw_len, pak_len, new_len;
int mode = LZS_WFAST;
lzs_vram = mode & 0xF;
// raw_buffer = Load(filename, &raw_len, RAW_MINIM, RAW_MAXIM);
raw_buffer = data;
raw_len = length;
pak_buffer = NULL;
pak_len = LZS_MAXIM + 1;
if (!(mode & LZS_FAST)) {
mode = mode & LZS_BEST ? 1 : 0;
new_buffer = LZS_Code(raw_buffer, raw_len, &new_len, mode);
} else {
new_buffer = LZS_Fast(raw_buffer, raw_len, &new_len);
}
if (new_len < pak_len) {
if (pak_buffer != NULL) free(pak_buffer);
pak_buffer = new_buffer;
pak_len = new_len;
}
std::cout << pak_len << "\n";
// output = pak_buffer;
// Save("output_new", pak_buffer, pak_len);
// free(pak_buffer);
// free(raw_buffer);
printf("\n");
}
/*----------------------------------------------------------------------------*/
unsigned char *LZS_Code(unsigned char *raw_buffer, int raw_len, unsigned int *new_len, int best) {
unsigned char *pak_buffer, *pak, *raw, *raw_end, *flg;
unsigned int pak_len, len, pos, len_best, pos_best;
unsigned int len_next, pos_next, len_post, pos_post;
unsigned char mask;
#define SEARCH(l,p) { \
l = LZS_THRESHOLD; \
\
pos = raw - raw_buffer >= LZS_N ? LZS_N : raw - raw_buffer; \
for ( ; pos > lzs_vram; pos--) { \
for (len = 0; len < LZS_F; len++) { \
if (raw + len == raw_end) break; \
if (*(raw + len) != *(raw + len - pos)) break; \
} \
\
if (len > l) { \
p = pos; \
if ((l = len) == LZS_F) break; \
} \
} \
}
pak_len = 4 + raw_len + ((raw_len + 7) / 8);
pak_buffer = (unsigned char *) Memory(pak_len, sizeof(char));
*(unsigned int *)pak_buffer = CMD_CODE_10 | (raw_len << 8);
pak = pak_buffer + 4;
raw = raw_buffer;
raw_end = raw_buffer + raw_len;
mask = 0;
while (raw < raw_end) {
if (!(mask >>= LZS_SHIFT)) {
*(flg = pak++) = 0;
mask = LZS_MASK;
}
SEARCH(len_best, pos_best);
// LZ-CUE optimization start
if (best) {
if (len_best > LZS_THRESHOLD) {
if (raw + len_best < raw_end) {
raw += len_best;
SEARCH(len_next, pos_next);
raw -= len_best - 1;
SEARCH(len_post, pos_post);
raw--;
if (len_next <= LZS_THRESHOLD) len_next = 1;
if (len_post <= LZS_THRESHOLD) len_post = 1;
if (len_best + len_next <= 1 + len_post) len_best = 1;
}
}
}
// LZ-CUE optimization end
if (len_best > LZS_THRESHOLD) {
raw += len_best;
*flg |= mask;
*pak++ = ((len_best - (LZS_THRESHOLD + 1)) << 4) | ((pos_best - 1) >> 8);
*pak++ = (pos_best - 1) & 0xFF;
} else {
*pak++ = *raw++;
}
}
*new_len = pak - pak_buffer;
return(pak_buffer);
}
/*----------------------------------------------------------------------------*/
unsigned char *LZS_Fast(unsigned char *raw_buffer, int raw_len, unsigned int *new_len) {
unsigned char *pak_buffer, *pak, *raw, *raw_end, *flg;
unsigned int pak_len, len, r, s, len_tmp, i;
unsigned char mask;
pak_len = 4 + raw_len + ((raw_len + 7) / 8);
pak_buffer = (unsigned char *) Memory(pak_len, sizeof(char));
*(unsigned int *)pak_buffer = CMD_CODE_10 | (raw_len << 8);
pak = pak_buffer + 4;
raw = raw_buffer;
raw_end = raw_buffer + raw_len;
LZS_InitTree();
r = s = 0;
len = raw_len < LZS_F ? raw_len : LZS_F;
while (r < LZS_N - len) ring[r++] = 0;
for (i = 0; i < len; i++) ring[r + i] = *raw++;
LZS_InsertNode(r);
mask = 0;
while (len) {
if (!(mask >>= LZS_SHIFT)) {
*(flg = pak++) = 0;
mask = LZS_MASK;
}
if (len_ring > len) len_ring = len;
if (len_ring > LZS_THRESHOLD) {
*flg |= mask;
pos_ring = ((r - pos_ring) & (LZS_N - 1)) - 1;
*pak++ = ((len_ring - LZS_THRESHOLD - 1) << 4) | (pos_ring >> 8);
*pak++ = pos_ring & 0xFF;
} else {
len_ring = 1;
*pak++ = ring[r];
}
len_tmp = len_ring;
for (i = 0; i < len_tmp; i++) {
if (raw == raw_end) break;
LZS_DeleteNode(s);
ring[s] = *raw++;
if (s < LZS_F - 1) ring[s + LZS_N] = ring[s];
s = (s + 1) & (LZS_N - 1);
r = (r + 1) & (LZS_N - 1);
LZS_InsertNode(r);
}
while (i++ < len_tmp) {
LZS_DeleteNode(s);
s = (s + 1) & (LZS_N - 1);
r = (r + 1) & (LZS_N - 1);
if (--len) LZS_InsertNode(r);
}
}
*new_len = pak - pak_buffer;
return(pak_buffer);
}
/*----------------------------------------------------------------------------*/
void LZS_InitTree(void) {
int i;
for (i = LZS_N + 1; i <= LZS_N + 256; i++)
rson[i] = LZS_NIL;
for (i = 0; i < LZS_N; i++)
dad[i] = LZS_NIL;
}
/*----------------------------------------------------------------------------*/
void LZS_InsertNode(int r) {
unsigned char *key;
int i, p, cmp, prev;
prev = (r - 1) & (LZS_N - 1);
cmp = 1;
len_ring = 0;
key = &ring[r];
p = LZS_N + 1 + key[0];
rson[r] = lson[r] = LZS_NIL;
for ( ; ; ) {
if (cmp >= 0) {
if (rson[p] != LZS_NIL) p = rson[p];
else { rson[p] = r; dad[r] = p; return; }
} else {
if (lson[p] != LZS_NIL) p = lson[p];
else { lson[p] = r; dad[r] = p; return; }
}
for (i = 1; i < LZS_F; i++)
if ((cmp = key[i] - ring[p + i])) break;
if (i > len_ring) {
if (!lzs_vram || (p != prev)) {
pos_ring = p;
if ((len_ring = i) == LZS_F) break;
}
}
}
dad[r] = dad[p]; lson[r] = lson[p]; rson[r] = rson[p];
dad[lson[p]] = r; dad[rson[p]] = r;
if (rson[dad[p]] == p) rson[dad[p]] = r;
else lson[dad[p]] = r;
dad[p] = LZS_NIL;
}
/*----------------------------------------------------------------------------*/
void LZS_DeleteNode(int p) {
int q;
if (dad[p] == LZS_NIL) return;
if (rson[p] == LZS_NIL) {
q = lson[p];
} else if (lson[p] == LZS_NIL) {
q = rson[p];
} else {
q = lson[p];
if (rson[q] != LZS_NIL) {
do {
q = rson[q];
} while (rson[q] != LZS_NIL);
rson[dad[q]] = lson[q]; dad[lson[q]] = dad[q];
lson[q] = lson[p]; dad[lson[p]] = q;
}
rson[q] = rson[p]; dad[rson[p]] = q;
}
dad[q] = dad[p];
if (rson[dad[p]] == p) rson[dad[p]] = q;
else lson[dad[p]] = q;
dad[p] = LZS_NIL;
}
/*----------------------------------------------------------------------------*/
/*-- EOF Copyright (C) 2011 CUE --*/
/*----------------------------------------------------------------------------*/

View File

@ -1 +0,0 @@
void LZS_Encode(unsigned char*data, unsigned int length);

View File

@ -1,37 +0,0 @@
#include <bits/stdint-uintn.h>
#include <iostream>
#include <fstream>
#include "BMPlib.h"
// #include "lzss.hpp"
#define RGB8(r,g,b) ((r)>>3) | (((g)>>3)<<5) | (((b)>>3)<<10)
int main() {
BMPlib::BMP bmp;
bmp.Read("../../assets/out/out_240.bmp");
unsigned char* pixel = bmp.GetPixelBuffer();
uint16_t totalSize = bmp.GetWidth()*bmp.GetHeight();
// uint16_t output[totalSize];
// uint32_t counter = 0;
std::ofstream out("output", std::ios::binary);
for (int i=0; i<totalSize*3; i+=3) {
uint16_t color = RGB8(pixel[i], pixel[i+1], pixel[i+2]);
// output[counter] = color;
// counter++;
out.write((char*)&color, sizeof(color));
}
// unsigned char* output2;
// LZS_Encode((unsigned char*)&output, totalSize);
// std::cout << sizeof(*output2) << "\n";
out.close();
return 0;
}

View File

@ -1,76 +0,0 @@
const fs = require("fs");
const omg = require("omggif");
const { execSync } = require('child_process');
execSync("rm -rf data_compress")
// load gif
const gif_raw = fs.readFileSync("../assets/out.gif");
const gif_data = new omg.GifReader(gif_raw);
const num_pixel = gif_data.width * gif_data.height;
const num_frames = gif_data.numFrames();
const pallete = [];
var maxLength = 0;
var pallete_name;
var buffer = new Uint8Array(num_pixel * 4)
var prevFrame = new Uint8Array(num_pixel * 4)
var buffer_formatted = new Uint16Array(num_pixel);
for (let i=0; i<num_frames; i++) {
// for (let i=0; i<2; i++) {
gif_data.decodeAndBlitFrameRGBA(i, buffer);
let i3 = 0
for (let i2=4; i2<buffer.length; i2 += 4) {
// remove transparent
if (buffer[i2-1] != 0) {
prevFrame[i2-1] = buffer[i2-1]
prevFrame[i2-2] = buffer[i2-2]
prevFrame[i2-3] = buffer[i2-3]
prevFrame[i2-4] = buffer[i2-4]
}
// pallete_name = `${prevFrame[i2-4]},${prevFrame[i2-3]},${prevFrame[i2-2]},${prevFrame[i2-1]}`
// quick check if there is a non opaque pallete
// if (buffer[i2-1] != 255 && buffer[i2-1] != 0) {
// // throw some error maybe? idk
// console.log(pallete_name)
// }
// add pallte if not exist
// if (pallete.indexOf(pallete_name) == -1) pallete.push(pallete_name);
buffer_formatted[i3] = rgb8(prevFrame[i2-4], prevFrame[i2-3], prevFrame[i2-2])
i3++
}
// console.log(count1, count2)
// // Write temp frame
const temp = fs.openSync('temp', "w");
fs.writeSync(temp, Buffer.from(buffer_formatted.buffer));
fs.closeSync(temp);
// // compress temp frame
execSync("./cpp/lzss temp")
const temp_new = fs.readFileSync("temp");
maxLength = Math.max(temp_new.length, maxLength);
fs.appendFileSync("data_compress", temp_new);
console.log(`Convert frames ${i+1} of ${num_frames}`);
}
// console.log(buffer_final)
// console.log(pallete)
console.log("Num pallete:", pallete.length)
console.log(maxLength);
function rgb8(r,g,b) {
return (((r)>>3)|(((g)>>3)<<5)|(((b)>>3)<<10))
}

111
encoder/main.cpp Normal file
View File

@ -0,0 +1,111 @@
#include <cstdio>
#include <iostream>
#include <filesystem>
#include <fstream>
#include <string>
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#include "fastlz.h"
unsigned short RGB15(int r, int g, int b) {
unsigned short rgb15 =
((r >> 3) << 10) | // 5 bits for red
((g >> 3) << 5) | // 5 bits for green
(b >> 3); // 5 bits for blue
// Set the alpha bit to 1
rgb15 |= 1 << 15;
return rgb15;
}
int main()
{
std::string path_out = "../assets/out/";
std::string path_palette = "../assets/palette.png";
std::string path_resource = "../resource";
std::string path_test = "../assets/out/out_3667.bmp";
int frame_total = -1;
// Find total frame
for (const auto& entry : std::filesystem::directory_iterator(path_out)) {
if (entry.is_regular_file()) {
std::string fileName = entry.path().filename().string();
if (fileName.substr(0, 4) == "out_" && fileName.substr(fileName.size() - 4) == ".bmp") {
int number = std::stoi(fileName.substr(4, fileName.size() - 8));
if (number > frame_total) {
frame_total = number;
}
}
}
}
// Generate palette
uint16_t palette[256];
int palette_w = -1;
int palette_h = -1;
int palette_n = -1;
unsigned char *palette_data = stbi_load(path_palette.c_str(), &palette_w, &palette_h, &palette_n, 3);
for (int i=0; i<256; i++)
{
int index = i*3;
unsigned char r = palette_data[index];
unsigned char g = palette_data[index + 1];
unsigned char b = palette_data[index + 2];
palette[i] = RGB15(r, g, b);
// printf("%i> %i,%i,%i (%i)\n", i, r, g, b, palette[i]);
}
std::ofstream out;
out.open(path_resource + "/palette.bin", std::ios::binary);
out.write(reinterpret_cast<const char*>(palette), sizeof(palette));
out.close();
uint8_t test[256*192];
uint8_t test_compress[(256*192)*2];
uint32_t test_compress_len = 0;
int test_w = -1;
int test_h = -1;
int test_n = -1;
unsigned char *test_data = stbi_load(path_test.c_str(), &test_w, &test_h, &test_n, 3);
for (int i=0; i<256*192; i++)
{
int index = i*3;
unsigned char r = test_data[index];
unsigned char g = test_data[index + 1];
unsigned char b = test_data[index + 2];
uint16_t current_pal = RGB15(r, g, b);
int current_index = -1;
for (int i2=0; i2<256; i2++)
{
if (palette[i2] == current_pal) {
current_index = i2;
break;
}
}
if (current_index == -1) printf("%i> %i\n", i, current_index);
else test[i] = current_index;
}
test_compress_len = fastlz_compress_level(1, test, 256*192, test_compress);
printf("len: %i\n", test_compress_len);
out.open(path_resource + "/image.bin", std::ios::binary);
out.write(reinterpret_cast<const char*>(&test_compress_len), sizeof(test_compress_len));
out.write(reinterpret_cast<const char*>(test_compress), test_compress_len);
out.close();
// Print
printf("Total Frame: %i\n", frame_total);
}

View File

@ -1,15 +0,0 @@
{
"name": "decoder",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"dependencies": {
"child-process-promise": "^2.2.1",
"gify-parse": "^1.0.7",
"lz77": "^1.1.0",
"lzma-native": "^8.0.1",
"omggif": "^1.0.10",
"rgb-hex": "^4.0.0",
"write": "^2.0.0"
}
}

7985
encoder/stb_image.h Normal file

File diff suppressed because it is too large Load Diff

BIN
resource/image.bin Normal file

Binary file not shown.

BIN
resource/palette.bin Normal file

Binary file not shown.

90
src/main.cpp Executable file
View File

@ -0,0 +1,90 @@
#include "fastlz.h"
#include <cstdlib>
#include <nds.h>
#include <filesystem.h>
#include <nds/arm9/console.h>
#include <nds/arm9/video.h>
#include <nds/debug.h>
#include <nds/ndstypes.h>
#include <stdio.h>
#include <cstdarg>
void wait_forever(const char* msg, ...);
size_t LoadFile(const char* file, unsigned char **buffer);
int main(void) {
videoSetMode(MODE_5_3D);
videoSetModeSub(MODE_0_2D);
vramSetBankA(VRAM_A_MAIN_BG);
vramSetBankB(VRAM_B_TEXTURE);
vramSetBankF(VRAM_F_TEX_PALETTE);
consoleDemoInit();
consoleDebugInit(DebugDevice_NOCASH);
nitroFSInit(NULL);
unsigned char* bmp = NULL;
unsigned char* bmp_decompress = (unsigned char*)malloc(256*192);
size_t bmp_len = LoadFile("nitro:/image.bin", &bmp);
// size_t bmp_decompress_len = bmp[0] | bmp[1] << 8;
size_t bmp_decompress_len = 0;
memcpy(&bmp_decompress_len, bmp, sizeof(uint32));
fprintf(stderr, "%i %i\n", bmp_decompress_len, bmp_len);
fastlz_decompress(&bmp[4], bmp_decompress_len, bmp_decompress, 256*192);
unsigned char* pal = NULL;
size_t pal_len = LoadFile("nitro:/palette.bin", &pal);
int bgp = bgInit(3, BgType_Bmp8, BgSize_B8_256x256, 0, 0);
// DC_FlushRange(bg, bg_len);
dmaCopy(bmp_decompress, bgGetGfxPtr(bgp), 256*192);
dmaCopy(pal, BG_PALETTE, pal_len);
nocashMessage("done\n");
while(1) {
swiWaitForVBlank();
scanKeys();
}
return 0;
}
size_t LoadFile(const char* file, unsigned char **buffer)
{
FILE *in = fopen(file, "rb");
if (in == NULL) wait_forever("cannot load %s", file);
fseek(in, 0, SEEK_END);
long file_size = ftell(in);
rewind(in);
*buffer = (unsigned char*)malloc(file_size);
if (*buffer == NULL) wait_forever("Failed to malloc %s", file);
size_t bytes_read = fread(*buffer, 1, file_size, in);
if (bytes_read != file_size)
{
fclose(in);
free(*buffer);
wait_forever("Failed to read %s", file);
}
return bytes_read;
}
void wait_forever(const char* msg, ...)
{
va_list args;
va_start(args, msg);
fprintf(stdout, msg, args);
fprintf(stderr, msg, args);
va_end(args);
while (1) swiWaitForVBlank();
}

1
vendor/FastLZ vendored Submodule

@ -0,0 +1 @@
Subproject commit 344eb4025f9ae866ebf7a2ec48850f7113a97a42