lets just commit before i break more stuff

This commit is contained in:
sillysagiri 2021-12-26 11:36:57 +07:00
commit 2315a62183
14 changed files with 1657 additions and 0 deletions

11
.gitignore vendored Normal file
View File

@ -0,0 +1,11 @@
/assets/*
!/assets/convert.sh
/NDS/nitrofiles/*
!/NDS/nitrofiles/.gitignore
/NDS/cmake
/NDS/compile_commands.json
/encoder/node_modules
/temp

38
NDS/CMakeLists.txt Normal file
View File

@ -0,0 +1,38 @@
# That file is here only to make IDE's happy so they could index all source files.
# Real building happens through Makefile.
cmake_minimum_required(VERSION 3.10)
project(myProject)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# Set to your devkitPro's installation dir if environment variable does not exist.
set(DEVKITPRO /opt/devkitpro)
include(${DEVKITPRO}/cmake/devkitARM.cmake)
include_directories(${DEVKITPRO}/libnds/lib)
include_directories(${DEVKITPRO}/libnds/include)
include_directories(${DEVKITPRO}/libnds/include/nds)
include_directories(${DEVKITPRO}/libnds/include/nds/arm9)
include_directories(${DEVKITPRO}/devkitARM)
include_directories(${DEVKITPRO}/devkitARM/arm-none-eabi/include)
include_directories(source)
include_directories(fonts)
include_directories(data)
include_directories(build)
link_directories(${DEVKITPRO}/libnds/lib)
link_directories(${DEVKITPRO}/libnds/include)
link_directories(${DEVKITPRO}/libnds/include/nds)
link_directories(${DEVKITPRO}/libnds/include/nds/arm9)
add_compile_definitions(ARM9)
add_compile_definitions(ARM7)
add_compile_definitions(iprintf=printf)
FILE(GLOB_RECURSE src *.cpp *.hpp *.c *.h)
add_executable(myProject ${src})

222
NDS/Makefile Normal file
View File

@ -0,0 +1,222 @@
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
endif
# These set the information text in the nds file
GAME_TITLE := Bad Apple DS
GAME_SUBTITLE1 := Created by Melody
GAME_SUBTITLE2 := https://melody.my.id
include $(DEVKITARM)/ds_rules
#---------------------------------------------------------------------------------
# TARGET is the name of the output
# BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code
# INCLUDES is a list of directories containing extra header files
# DATA is a list of directories containing binary files embedded using bin2o
# GRAPHICS is a list of directories containing image files to be converted with grit
# AUDIO is a list of directories containing audio to be converted by maxmod
# ICON is the image used to create the game icon, leave blank to use default rule
# NITRO is a directory that will be accessible via NitroFS
#---------------------------------------------------------------------------------
TARGET := $(shell basename $(CURDIR))
BUILD := build
DIST := dist
SOURCES := source
INCLUDES := include
DATA := data
GRAPHICS :=
AUDIO := maxmod
ICON :=
# specify a directory which contains the nitro filesystem
# this is relative to the Makefile
NITRO := nitrofiles
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
ARCH := -marm -mthumb-interwork -march=armv5te -mtune=arm946e-s
CFLAGS := -g -Wall -O3\
$(ARCH) $(INCLUDE) -DARM9
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
ASFLAGS := -g $(ARCH)
LDFLAGS = -specs=ds_arm9.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
#---------------------------------------------------------------------------------
# any extra libraries we wish to link with the project (order is important)
#---------------------------------------------------------------------------------
LIBS := -lnds9
# automatigically add libraries for NitroFS
ifneq ($(strip $(NITRO)),)
LIBS := -lfilesystem -lfat $(LIBS)
endif
# automagically add maxmod library
ifneq ($(strip $(AUDIO)),)
LIBS := -lmm9 $(LIBS)
endif
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS := $(LIBNDS) $(PORTLIBS)
#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
# rules for different file extensions
#---------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR)))
#---------------------------------------------------------------------------------
export OUTPUT := $(CURDIR)/$(DIST)/$(TARGET)
export VPATH := $(CURDIR)/$(subst /,,$(dir $(ICON)))\
$(foreach dir,$(SOURCES),$(CURDIR)/$(dir))\
$(foreach dir,$(DATA),$(CURDIR)/$(dir))\
$(foreach dir,$(GRAPHICS),$(CURDIR)/$(dir))
export DEPSDIR := $(CURDIR)/$(BUILD)
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
PNGFILES := $(foreach dir,$(GRAPHICS),$(notdir $(wildcard $(dir)/*.png)))
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
# prepare NitroFS directory
ifneq ($(strip $(NITRO)),)
export NITRO_FILES := $(CURDIR)/$(NITRO)
endif
# get audio list for maxmod
ifneq ($(strip $(AUDIO)),)
export MODFILES := $(foreach dir,$(notdir $(wildcard $(AUDIO)/*.*)),$(CURDIR)/$(AUDIO)/$(dir))
# place the soundbank file in NitroFS if using it
ifneq ($(strip $(NITRO)),)
export SOUNDBANK := $(NITRO_FILES)/soundbank.bin
# otherwise, needs to be loaded from memory
else
export SOUNDBANK := soundbank.bin
BINFILES += $(SOUNDBANK)
endif
endif
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#---------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
#---------------------------------------------------------------------------------
export LD := $(CC)
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
export LD := $(CXX)
#---------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------
export OFILES_BIN := $(addsuffix .o,$(BINFILES))
export OFILES_SOURCES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
export OFILES := $(PNGFILES:.png=.o) $(OFILES_BIN) $(OFILES_SOURCES)
export HFILES := $(PNGFILES:.png=.h) $(addsuffix .h,$(subst .,_,$(BINFILES)))
export INCLUDE := $(foreach dir,$(INCLUDES),-iquote $(CURDIR)/$(dir))\
$(foreach dir,$(LIBDIRS),-I$(dir)/include)\
-I$(CURDIR)/$(BUILD)
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
ifeq ($(strip $(ICON)),)
icons := $(wildcard *.bmp)
ifneq (,$(findstring $(TARGET).bmp,$(icons)))
export GAME_ICON := $(CURDIR)/$(TARGET).bmp
else
ifneq (,$(findstring icon.bmp,$(icons)))
export GAME_ICON := $(CURDIR)/icon.bmp
endif
endif
else
ifeq ($(suffix $(ICON)), .grf)
export GAME_ICON := $(CURDIR)/$(ICON)
else
export GAME_ICON := $(CURDIR)/$(BUILD)/$(notdir $(basename $(ICON))).grf
endif
endif
.PHONY: $(BUILD) clean
#---------------------------------------------------------------------------------
$(BUILD):
@mkdir -p $@
@mkdir -p $(DIST)
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@rm -fr $(BUILD) $(TARGET).elf $(TARGET).nds $(SOUNDBANK) $(DIST)
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
$(OUTPUT).nds: $(OUTPUT).elf $(NITRO_FILES) $(GAME_ICON)
$(OUTPUT).elf: $(OFILES)
# source files depend on generated headers
$(OFILES_SOURCES) : $(HFILES)
# need to build soundbank first
$(OFILES): $(SOUNDBANK)
#---------------------------------------------------------------------------------
# rule to build solution from music files
#---------------------------------------------------------------------------------
$(SOUNDBANK) : $(MODFILES)
#---------------------------------------------------------------------------------
mmutil $^ -d -o$@ -hsoundbank.h
#---------------------------------------------------------------------------------
%.bin.o %_bin.h : %.bin
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(bin2o)
#---------------------------------------------------------------------------------
# This rule creates assembly source files using grit
# grit takes an image file and a .grit describing how the file is to be processed
# add additional rules like this for each image extension
# you use in the graphics folders
#---------------------------------------------------------------------------------
%.s %.h: %.png %.grit
#---------------------------------------------------------------------------------
grit $< -fts -o$*
#---------------------------------------------------------------------------------
# Convert non-GRF game icon to GRF if needed
#---------------------------------------------------------------------------------
$(GAME_ICON): $(notdir $(ICON))
#---------------------------------------------------------------------------------
@echo convert $(notdir $<)
@grit $< -g -gt -gB4 -gT FF00FF -m! -p -pe 16 -fh! -ftr
-include $(DEPSDIR)/*.d
#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------

0
NDS/nitrofiles/.gitignore vendored Normal file
View File

114
NDS/source/main.cpp Normal file
View File

@ -0,0 +1,114 @@
#include <nds.h>
#include <filesystem.h>
#include <iostream>
#include <fstream>
#include <maxmod9.h>
#include <vector>
#define TIMER_SPEED (BUS_CLOCK/1024)
FILE* file = 0;
std::ifstream in;
uint16_t blockSize;
char buffer[256*192*2];
char buffer2[256*256*2];
void VBlankProc() {
in.read((char*)&blockSize, sizeof(blockSize));
in.read(buffer, blockSize);
}
mm_word on_stream_request( mm_word length, mm_addr dest, mm_stream_formats format ) {
if(file){
size_t samplesize = 1;
switch(format){
case MM_STREAM_8BIT_MONO: samplesize = 1; break;
case MM_STREAM_8BIT_STEREO: samplesize = 2; break;
case MM_STREAM_16BIT_MONO: samplesize = 2; break;
case MM_STREAM_16BIT_STEREO: samplesize = 4; break;
}
int res = fread(dest,samplesize,length,file);
if(res){
length = res;
} else {
mmStreamClose();
fclose(file);
length = 0;
}
}
return length;
}
int main(void) {
consoleDebugInit(DebugDevice_NOCASH);
videoSetMode(MODE_FB0);
vramSetBankA(VRAM_A_LCD);
std::cerr << "<=== init ===>" << std::endl;
// nitrofiles initialization
if (nitroFSInit(NULL)) {
chdir("nitro:/");
std::cerr << "nitrofs init success" << std::endl;
} else {
consoleDemoInit();
std::cout << "cannot init nitrofs" << std::endl;
while(1) {
// freezee
}
}
in.open("output", std::ios::binary);
uint16_t totalsize;
char buf[256*192*2];
char buf2[256*256*2];
in.read((char*)&totalsize, sizeof(totalsize));
in.read(buf, totalsize);
swiDecompressLZSSWram(buf, buf2);
dmaCopyWordsAsynch(3, buf2, VRAM_A, 256*192*2);
// for (int i=0; i<192*256; i++) {
// VRAM_A[i] = buf[i];
// }
while(1) {
// loop
}
mmInitDefault((char*)"soundbank.bin");
file = fopen("music.raw","rb");
mm_stream mystream;
mystream.sampling_rate = 22050; // sampling rate = 25khz
mystream.buffer_length = 1200; // buffer length = 1200 samples
mystream.callback = on_stream_request; // set callback function
mystream.format = MM_STREAM_16BIT_MONO; // format = stereo 16-bit
mystream.timer = MM_TIMER0; // use hardware timer 0
mystream.manual = false; // use manual filling
mmStreamOpen( &mystream );
irqSet(IRQ_VBLANK, VBlankProc);
while(1) {
// loop
}
in.open("data_compress", std::ios::in | std::ios::binary);
while(1) {
swiDecompressLZSSWram(buffer, buffer2);
dmaCopyWordsAsynch(3, buffer2, VRAM_A, 256*192*2);
swiWaitForVBlank();
}
// crashh
return 0;
}

4
README.MD Normal file
View File

@ -0,0 +1,4 @@
# my really crappy bad apple port
contain voodoo and black magic...
check the workflow... im to lazy to explain

18
assets/convert.sh Normal file
View File

@ -0,0 +1,18 @@
#!/bin/sh
palette="palette.png"
video="video.mp4"
output="out.gif"
filters="fps=30,scale=256x192"
skip="-t 1 -ss 00:8"
# old
ffmpeg -i $video -vf "$filters,palettegen=max_colors=256:reserve_transparent=" -y $palette
ffmpeg -i $video -i $palette -lavfi "$filters [x]; [x][1:v] paletteuse=dither=none" -y $output
# unreleased
# ffmpeg -i $video -vf "$filters" out/out_%d.bmp
# audio
ffmpeg -i $video -f s16le -ac 1 -ar 48000 music.raw

638
encoder/cpp/BMPlib.h Normal file
View File

@ -0,0 +1,638 @@
/*
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
};
}

BIN
encoder/cpp/lzss Executable file

Binary file not shown.

481
encoder/cpp/lzss.cpp Normal file
View File

@ -0,0 +1,481 @@
/*----------------------------------------------------------------------------*/
/*-- 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
encoder/cpp/lzss.hpp Normal file
View File

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

37
encoder/cpp/main.cpp Normal file
View File

@ -0,0 +1,37 @@
#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;
}

78
encoder/index.js Normal file
View File

@ -0,0 +1,78 @@
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-60.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}`);
}
execSync("cp data_compress ../nitrofiles/")
// 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))
}

15
encoder/package.json Normal file
View File

@ -0,0 +1,15 @@
{
"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"
}
}