working test frame
This commit is contained in:
parent
ee6ded0087
commit
b06d010df6
BIN
.cache/clangd/index/fastlz.c.AB543E405099E598.idx
Normal file
BIN
.cache/clangd/index/fastlz.c.AB543E405099E598.idx
Normal file
Binary file not shown.
BIN
.cache/clangd/index/fastlz.h.C7BC6D39ACDD2A48.idx
Normal file
BIN
.cache/clangd/index/fastlz.h.C7BC6D39ACDD2A48.idx
Normal file
Binary file not shown.
BIN
.cache/clangd/index/main.cpp.9457CFB944F3C5D0.idx
Normal file
BIN
.cache/clangd/index/main.cpp.9457CFB944F3C5D0.idx
Normal file
Binary file not shown.
6
.gitignore
vendored
6
.gitignore
vendored
@ -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
3
.gitmodules
vendored
Normal 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
5
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"clangd.arguments": [
|
||||||
|
"--query-driver=/opt/devkitpro/devkitARM/bin/arm-none-eabi-g++"
|
||||||
|
]
|
||||||
|
}
|
43
CMakeLists.txt
Executable file
43
CMakeLists.txt
Executable 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
21
arm7/CMakeLists.txt
Executable 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
98
arm7/src/main.cpp
Executable 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;
|
||||||
|
}
|
@ -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
0
assets/out/.keep
Normal file
22
encoder/CMakeLists.txt
Normal file
22
encoder/CMakeLists.txt
Normal 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})
|
@ -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 --*/
|
|
||||||
/*----------------------------------------------------------------------------*/
|
|
@ -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
|
|
||||||
};
|
|
||||||
}
|
|
@ -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 --*/
|
|
||||||
/*----------------------------------------------------------------------------*/
|
|
@ -1 +0,0 @@
|
|||||||
void LZS_Encode(unsigned char*data, unsigned int length);
|
|
@ -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;
|
|
||||||
}
|
|
@ -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
111
encoder/main.cpp
Normal 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);
|
||||||
|
}
|
@ -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
7985
encoder/stb_image.h
Normal file
File diff suppressed because it is too large
Load Diff
BIN
resource/image.bin
Normal file
BIN
resource/image.bin
Normal file
Binary file not shown.
BIN
resource/palette.bin
Normal file
BIN
resource/palette.bin
Normal file
Binary file not shown.
90
src/main.cpp
Executable file
90
src/main.cpp
Executable 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
1
vendor/FastLZ
vendored
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 344eb4025f9ae866ebf7a2ec48850f7113a97a42
|
Loading…
x
Reference in New Issue
Block a user