diff --git a/.gitignore b/.gitignore index a15a796..e06663f 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ /nitrofs/*.bin /nitrofs/*.raw +/nitrofs/*.sillyvideo compile_commands.json *.nds \ No newline at end of file diff --git a/Makefile b/Makefile index 6284c3e..1363049 100644 --- a/Makefile +++ b/Makefile @@ -40,7 +40,7 @@ NITROFSDIR := nitrofs # Defines passed to all files # --------------------------- -DEFINES := -DARM9 -DLWRB_DISABLE_ATOMIC +DEFINES := -DARM9 -DNDEBUG # Libraries # --------- diff --git a/assets/convert.sh b/assets/convert.sh index 949b6f0..5e1e0df 100644 --- a/assets/convert.sh +++ b/assets/convert.sh @@ -1,15 +1,33 @@ #!/bin/sh -video1="catch.mp4" +video1="mezmerize.mp4" palette1="palette1.png" -# output1="out_badapple.mp4" output1="out/out_%d.bmp" -filters="scale=256x192:flags=lanczos:force_original_aspect_ratio=decrease,pad=256:192:-1:-1:color=black,fps=24" +video2="mezmerize_fix.mp4" +palette2="palette2.png" +output2="out2/out_%d.bmp" + +filters="scale=256:-1:flags=lanczos,fps=30" +dither="none" +# "bayer", "heckbert", "floyd_steinberg", "sierra2", "sierra2_4a", "sierra3", "burkes", "atkinson", "none" # video -# ffmpeg -i $video1 -vf "$filters,palettegen=max_colors=256:reserve_transparent=0:stats_mode=diff" -y $palette1 -ffmpeg -i $video1 -i $palette1 -filter_complex "$filters[x];[x][1:v]paletteuse=dither=sierra3" -y $output1 +ffmpeg -i $video1 -vf "$filters,palettegen=max_colors=256:reserve_transparent=0:stats_mode=diff" -y $palette1 +ffmpeg -i $video1 -i $palette1 -filter_complex "$filters[x];[x][1:v]paletteuse=dither=$dither" -y $output1 + +ffmpeg -i $video2 -vf "$filters,palettegen=max_colors=256:reserve_transparent=0:stats_mode=diff" -y $palette2 +ffmpeg -i $video2 -i $palette2 -filter_complex "$filters[x];[x][1:v]paletteuse=dither=$dither" -y $output2 # audio -# ffmpeg -i $video1 -f s16le -vn -ac 2 -ar 22050 -y music1.raw \ No newline at end of file +ffmpeg -i $video1 -f s8 -vn -ac 1 -ar 16000 -y music1.raw + +for file in out/*.bmp; do + echo $file + magick "$file" -background black -gravity west -extent 256x "$file" +done + +for file in out2/*.bmp; do + echo $file + magick "$file" -background black -gravity west -extent 256x "$file" +done \ No newline at end of file diff --git a/assets/out/.keep b/assets/out/.keep deleted file mode 100644 index e69de29..0000000 diff --git a/encoder/CMakeLists.txt b/encoder/CMakeLists.txt index 70cebb7..f821501 100644 --- a/encoder/CMakeLists.txt +++ b/encoder/CMakeLists.txt @@ -7,18 +7,11 @@ set(PROJECT_NAME "encoder") project(${PROJECT_NAME}) -message(STATUS "Downloading fastlz library") -include(FetchContent) -FetchContent_Declare(fastlz URL https://github.com/ariya/FastLZ/archive/refs/heads/master.zip) -FetchContent_MakeAvailable(fastlz) - file(GLOB_RECURSE PROJECT_SOURCES CONFIGURE_DEPENDS - "*.cpp" "*.c" - ${fastlz_SOURCE_DIR}/fastlz.c) + "*.cpp" "*.c") set(PROJECT_INCLUDE - "encoder" - ${fastlz_SOURCE_DIR}) + "encoder") set(PROJECT_VENDOR "") diff --git a/encoder/lzss.c b/encoder/lzss.c index c5c37ba..18b3599 100644 --- a/encoder/lzss.c +++ b/encoder/lzss.c @@ -95,7 +95,14 @@ void Usage(void) "* multiple filenames are permitted\n"); } -void *Memory(size_t length, size_t size); +void *Memory(size_t length, size_t size) +{ + void *fb = calloc(length, size); + if (fb == NULL) + EXIT("\nMemory error\n"); + + return fb; +} void LZS_InsertNode(int r) { diff --git a/encoder/main.cpp b/encoder/main.cpp index 2303113..de8174e 100644 --- a/encoder/main.cpp +++ b/encoder/main.cpp @@ -1,16 +1,17 @@ +#include #include #include #include #include #include #include +#include +#include #define STB_IMAGE_IMPLEMENTATION #include "stb_image.h" -#include "fastlz.h" -extern "C" char *RLE_Code(unsigned char *raw_buffer, int raw_len, int *new_len); extern "C" unsigned char *LZS_Fast(unsigned char *raw_buffer, size_t raw_len, size_t *new_len); extern "C" unsigned char *LZS_Code(unsigned char *raw_buffer, size_t raw_len, size_t *new_len, size_t best); @@ -22,28 +23,84 @@ extern "C" unsigned char *LZS_Code(unsigned char *raw_buffer, size_t raw_len, si #define ASSETS_PATH "../assets/" #define PALETTE_SIZE 256 -#define FRAME_SIZE 256*192 -#define CHUNK_SIZE 8 +#define FRAME_PER_CHUNK 2 +#define FRAMERATE 30 -void Frame_RAWtoRGB15(unsigned char *frame, unsigned char *dest, uint16_t *palette_buffer); +size_t GetTotalFrame(std::string path) +{ + size_t total = 0; + + for (const auto& entry : std::filesystem::directory_iterator(path)) { + if (entry.is_regular_file()) { + std::string filename = entry.path().filename().string(); + int extpos = filename.find(".bmp", 4); + if (extpos != std::string::npos) + { + int number = std::stoi(filename.substr(4, extpos-4)); + if (number > total) total = number; + } + } + } + + return total; +} + +void GetFrameDimension(std::string path, int *w, int *h) +{ + int n; + unsigned char *raw = stbi_load(path.c_str(), w, h, &n, 3); + stbi_image_free(raw); +} + +void ConvertPalette(uint16_t *buffer_palette, std::string path) +{ + int pal_w, pal_h, pal_n; + unsigned char *palette_raw = stbi_load(path.c_str(), &pal_w, &pal_h, &pal_n, 3); + + for (int i=0; i time_avg) type = 4; - case 2: // rle - { - int compress_len; - char *compress = RLE_Code(frame_buffer, frame_buffer_len, &compress_len); - memcpy(compress_buffer, compress, compress_len); - return compress_len; - break; - } - - case 3: // lzss + switch (type) { + case 1: // lzss { size_t compress_len; unsigned char *compress = LZS_Fast(frame_buffer, frame_buffer_len, &compress_len); @@ -53,186 +110,236 @@ int Compress(uint8_t type, uint8_t *frame_buffer, uint32_t frame_buffer_len, uin return compress_len; break; } + + case 2: // raw + { + memcpy(compress_buffer, frame_buffer, frame_buffer_len); + return frame_buffer_len; + break; + } } return 0; } -void Convert(std::string frame_path, std::string palette_path, std::string output_path, std::string output_basename, uint8_t type) +void Convert( + std::string path_video1, + std::string path_palette1, + std::string path_video2, + std::string path_palette2, + std::string path_output) { - uint16_t palette_buffer[PALETTE_SIZE]; + uint16_t metadata_width1; + uint16_t metadata_width2; + uint16_t metadata_height1; + uint16_t metadata_height2; + size_t metadata_total_frame1; + size_t metadata_total_frame2; - size_t frame_total = 0; - uint8_t frame_buffer[FRAME_SIZE*CHUNK_SIZE]; + uint16_t *buffer_palette1 = new uint16_t[PALETTE_SIZE]; + uint16_t *buffer_palette2 = new uint16_t[PALETTE_SIZE]; - uint32_t compress_size = 0; - uint32_t compress_size_total = 0; - size_t compress_size_biggest = 0; - uint8_t compress_buffer[162000]; + uint8_t *buffer_frame; + uint8_t *buffer_compress; + + size_t size_video1_frame; + size_t size_video2_frame; + size_t size_buffer_frame; + size_t size_compress = 0; + size_t size_compress_total = 0; + size_t size_compress_max = 0; + size_t size_compress_min = 99999999; std::ofstream file_out; + file_out.open(path_output, std::ios::binary); + + if (!file_out) { + printf("fail to open output %s\n", path_output.c_str()); + return; + } - printf("Finding total frame..."); - // Find total frame - for (const auto& entry : std::filesystem::directory_iterator(frame_path)) { - if (entry.is_regular_file()) { - std::string filename = entry.path().filename().string(); - int extpos = filename.find(".bmp", 4); - if (extpos != std::string::npos) - { - int number = std::stoi(filename.substr(4, extpos-4)); - if (number > frame_total) frame_total = number; - } - } - } - - // Generate palette - printf("Generating palette map...\n"); - int pal_w, pal_h, pal_n; - unsigned char *palette_raw = stbi_load(palette_path.c_str(), &pal_w, &pal_h, &pal_n, 3); - - for (int i=0; i(palette_buffer), sizeof(palette_buffer)); - file_out.close(); + // --- + { + printf("Finding video dimension...\n"); + int w, h; + GetFrameDimension(path_video1 + "out_1.bmp", &w, &h); + metadata_width1 = w; + metadata_height1 = h; + + GetFrameDimension(path_video2 + "out_1.bmp", &w, &h); + metadata_width2 = w; + metadata_height2 = h; + + size_video1_frame = metadata_width1*metadata_height1; + size_video2_frame = metadata_width2*metadata_height2; + } + + printf("video1 dimension: %ix%i\n", metadata_width1, metadata_height1); + printf("video2 dimension: %ix%i\n", metadata_width2, metadata_height2); + + // --- + { + size_buffer_frame = size_video1_frame + size_video2_frame; + buffer_frame = new uint8_t[size_buffer_frame*FRAME_PER_CHUNK]; + buffer_compress = new uint8_t[size_buffer_frame*FRAME_PER_CHUNK]; + } + + // --- + { + printf("Generating palette map...\n"); + ConvertPalette(buffer_palette1, path_palette1); + ConvertPalette(buffer_palette2, path_palette2); + } + + // --- + { + printf("Writing metadata...\n"); + + uint8_t framerate = FRAMERATE; + uint8_t frame_per_chunk = FRAME_PER_CHUNK; + + file_out.write(reinterpret_cast(&framerate), sizeof(uint8_t)); + file_out.write(reinterpret_cast(&frame_per_chunk), sizeof(uint8_t)); + file_out.write(reinterpret_cast(&metadata_total_frame1), sizeof(uint32_t)); + file_out.write(reinterpret_cast(&metadata_total_frame2), sizeof(uint32_t)); + file_out.write(reinterpret_cast(&metadata_width1), sizeof(uint16_t)); + file_out.write(reinterpret_cast(&metadata_height1), sizeof(uint16_t)); + file_out.write(reinterpret_cast(&metadata_width2), sizeof(uint16_t)); + file_out.write(reinterpret_cast(&metadata_height2), sizeof(uint16_t)); + } + + // --- + { + printf("Writing palette map...\n"); + file_out.write(reinterpret_cast(buffer_palette1), PALETTE_SIZE*sizeof(uint16_t)); + file_out.write(reinterpret_cast(buffer_palette2), PALETTE_SIZE*sizeof(uint16_t)); + } + + // --- printf("Generating image map...\n"); std::stringstream ss; - file_out.open(output_path + output_basename + "_img.bin", std::ios::binary); - - // ########## PER FRAME ENCODER ########## - // for (int i=0; i compress_size_biggest) compress_size_biggest = compress_size; - // compress_size_total += compress_size; - - // file_out.write(reinterpret_cast(&compress_size), sizeof(uint32_t)); - // file_out.write(reinterpret_cast(compress_buffer), compress_size); - - // printf("write %i bytes (%i/%i)\n", compress_size, i+1, frame_total); - // } - // ######################################## // Calculate the number of complete iterations needed - int numIterations = frame_total / CHUNK_SIZE; + int numIterations = std::max(metadata_total_frame1, metadata_total_frame2) / FRAME_PER_CHUNK; // Calculate the number of remaining items - int remainingItems = frame_total % CHUNK_SIZE; + int remainingItems = std::max(metadata_total_frame1, metadata_total_frame2) % FRAME_PER_CHUNK; for (int i=0; i compress_size_biggest) compress_size_biggest = compress_size; - compress_size_total += compress_size; + size_compress = Compress(1, buffer_frame, size_buffer_frame*FRAME_PER_CHUNK, buffer_compress); + size_compress_max = std::max(size_compress, size_compress_max); + size_compress_min = std::min(size_compress, size_compress_min); + size_compress_total += size_compress; - file_out.write(reinterpret_cast(&compress_size), sizeof(uint32_t)); - file_out.write(reinterpret_cast(compress_buffer), compress_size); - // file_out.put('\0'); + file_out.write(reinterpret_cast(&size_compress), sizeof(uint32_t)); + file_out.write(reinterpret_cast(buffer_compress), size_compress); - printf("write chunk %i bytes %i/%i\n", compress_size, i, numIterations-1); + printf("write %i bytes (%i/%i)\n", size_compress, i+1, numIterations); } // Handle remaining frame if (remainingItems > 0) { - memset(frame_buffer, 0, FRAME_SIZE*CHUNK_SIZE); + memset(buffer_frame, 0, size_buffer_frame*FRAME_PER_CHUNK); int i_chunk = 0; - for (int k = frame_total-remainingItems; k compress_size_biggest) compress_size_biggest = compress_size; - compress_size_total += compress_size; + size_compress = Compress(1, buffer_frame, size_buffer_frame*FRAME_PER_CHUNK, buffer_compress); + size_compress_max = std::max(size_compress, size_compress_max); + size_compress_min = std::min(size_compress, size_compress_min); + size_compress_total += size_compress; - file_out.write(reinterpret_cast(&compress_size), sizeof(uint32_t)); - file_out.write(reinterpret_cast(compress_buffer), compress_size); - // file_out.put('\0'); + file_out.write(reinterpret_cast(&size_compress), sizeof(uint32_t)); + file_out.write(reinterpret_cast(buffer_compress), size_compress); - printf("write remaining chunk %i bytes\n", compress_size); + printf("write remaining chunk %i bytes\n", size_compress); } file_out.close(); // Print - printf("Total Frame: %i\n", frame_total); - printf("Biggest : %i\n", compress_size_biggest); - printf("Total Size : %1.fmb\n", static_cast(compress_size_total) / (1024*1024)); + printf("\n"); + printf("fps: %i\n", FRAMERATE); + printf("frame per chunk: %i\n", FRAME_PER_CHUNK); + printf("video1 total frame: %i\n", metadata_total_frame1); + printf("video2 total frame: %i\n", metadata_total_frame2); + printf("video1 dimension: %ix%i\n", metadata_width1, metadata_height1); + printf("video2 dimension: %ix%i\n", metadata_width2, metadata_height2); + printf("compress size max: %i\n", size_compress_max); + printf("compress size min: %i\n", size_compress_min); + printf("size total : %1.fmb\n", static_cast(size_compress_total) / (1024*1024)); + + delete[] buffer_palette1; + delete[] buffer_palette2; + delete[] buffer_frame; + delete[] buffer_compress; } int main() { - // Convert(ASSETS_PATH "out1/", ASSETS_PATH "palette1.png", "../nitrofs/", "data_fastlz", 1); - // Convert(ASSETS_PATH "out1/", ASSETS_PATH "palette1.png", "../nitrofs/", "data_rle", 2); - Convert(ASSETS_PATH "out/", ASSETS_PATH "palette1.png", "../nitrofs/", "main", 3); - // Convert(ASSETS_PATH "out2/", ASSETS_PATH "palette2.png", "../nitrofs/", "sub"); -} - -void Frame_RAWtoRGB15(unsigned char *frame, unsigned char *dest, uint16_t *palette_buffer) -{ - for (int rgb=0; rgb. --*/ -/*----------------------------------------------------------------------------*/ - -/*----------------------------------------------------------------------------*/ -#include -#include -#include - -/*----------------------------------------------------------------------------*/ -#define CMD_DECODE 0x00 // decode -#define CMD_CODE_30 0x30 // RLE magic number - -#define RLE_CHECK 1 // bits to check -#define RLE_MASK 0x80 // bits position: - // ((((1 << RLE_CHECK) - 1) << (8 - RLE_CHECK) -#define RLE_LENGTH 0x7F // length, (0xFF & ~RLE_MASK) - -#define RLE_THRESHOLD 2 // max number of bytes to not encode -#define RLE_N 0x80 // max store, (RLE_LENGTH + 1) -#define RLE_F 0x82 // max coded, (RLE_LENGTH + RLE_THRESHOLD + 1) - -#define RAW_MINIM 0x00000000 // empty file, 0 bytes -#define RAW_MAXIM 0x00FFFFFF // 3-bytes length, 16MB - 1 - -#define RLE_MINIM 0x00000004 // header only (empty RAW file) -#define RLE_MAXIM 0x01400000 // 0x01020003, padded to 20MB: - // * header, 4 - // * length, RAW_MAXIM - // * flags, (RAW_MAXIM + RLE_N - 1) / RLE_N - // 4 + 0x00FFFFFF + 0x00020000 + padding - -/*----------------------------------------------------------------------------*/ -#define BREAK(text) { printf(text); return; } -#define EXIT(text) { printf(text); exit(-1); } - -/*----------------------------------------------------------------------------*/ -void Title(void); -void Usage(void); - -char *Load(char *filename, int *length, int min, int max); -void Save(char *filename, char *buffer, int length); -char *Memory(int length, int size); - -void RLE_Decode(char *filename); -void RLE_Encode(char *filename); -char *RLE_Code(unsigned char *raw_buffer, int raw_len, int *new_len); - - -/*----------------------------------------------------------------------------*/ -char *Memory(int length, int size) { - char *fb; - - fb = (char *) calloc(length, size); - if (fb == NULL) EXIT("\nMemory error\n"); - - return(fb); -} - -/*----------------------------------------------------------------------------*/ -char *RLE_Code(unsigned char *raw_buffer, int raw_len, int *new_len) { - unsigned char *pak_buffer, *pak, *raw, *raw_end, store[RLE_N]; - unsigned int pak_len, len, store_len, count; - - pak_len = 4 + raw_len + ((raw_len + RLE_N - 1) / RLE_N); - pak_buffer = (unsigned char *) Memory(pak_len, sizeof(char)); - - *(unsigned int *)pak_buffer = CMD_CODE_30 | (raw_len << 8); - - pak = pak_buffer + 4; - raw = raw_buffer; - raw_end = raw_buffer + raw_len; - - store_len = 0; - while (raw < raw_end) { - for (len = 1; len < RLE_F; len++) { - if (raw + len == raw_end) break; - if (*(raw + len) != *raw) break; - } - - if (len <= RLE_THRESHOLD) store[store_len++] = *raw++; - - if ((store_len == RLE_N) || (store_len && (len > RLE_THRESHOLD))) { - *pak++ = store_len - 1; - for (count = 0; count < store_len; count++) *pak++ = store[count]; - store_len = 0; - } - - if (len > RLE_THRESHOLD) { - *pak++ = RLE_MASK | (len - (RLE_THRESHOLD + 1)); - *pak++ = *raw; - raw += len; - } - } - if (store_len) { - *pak++ = store_len - 1; - for (count = 0; count < store_len; count++) *pak++ = store[count]; - } - - *new_len = pak - pak_buffer; - - return(pak_buffer); -} - -/*----------------------------------------------------------------------------*/ -/*-- EOF Copyright (C) 2011 CUE --*/ -/*----------------------------------------------------------------------------*/ diff --git a/libs/RaylibDS b/libs/RaylibDS index a55a77f..23311fe 160000 --- a/libs/RaylibDS +++ b/libs/RaylibDS @@ -1 +1 @@ -Subproject commit a55a77fd3e960f472655ee3b9bbe9329202c8a50 +Subproject commit 23311fe88c6a6009ffdd7c23badd758dd99ef950 diff --git a/src/main.cpp b/src/main.cpp index 1a93e93..70a13db 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,17 +1,20 @@ -#include "fastlz.h" +#include "Panda.hpp" #include "filesystem.h" #include "mm_types.h" #include "nds/arm9/background.h" #include "nds/arm9/cache.h" #include "nds/arm9/console.h" #include "nds/arm9/input.h" +#include "nds/arm9/math.h" #include "nds/arm9/sassert.h" +#include "nds/arm9/video.h" #include "nds/cothread.h" #include "nds/decompress.h" #include "nds/dma.h" #include "nds/interrupts.h" #include "nds/timers.h" -#include "raylibds.hpp" +#include "tonccpy.h" +#include #include #include #include @@ -22,19 +25,9 @@ #include #define PALETTE_SIZE 256 -#define FRAME_SIZE 256*192 - -// TODO: hardcode fix -#define CHUNK_SIZE 8 -#define FRAMERATE 24 -#define VIDEO_TOTALFRAME 3268 - -#define VIDEO_RBUF_LEN CHUNK_SIZE*8 -#define VIDEO_RBUF_BUFFER FRAME_SIZE -#define VIDEO_TEMP_SIZE 204000 #define MMSTREAM_BUF_SIZE 800 -#define MUSIC_RBUF_SIZE 96000*2 +#define MUSIC_RBUF_SIZE 16000 void wait_forever(const char* msg); bool LoadNextChunk(unsigned char *dest); @@ -48,31 +41,28 @@ mm_word on_stream_request( mm_word length, mm_addr dest, mm_stream_formats forma volatile bool doDraw = true; volatile bool isPause = false; volatile int noframe = 0; +volatile bool time_to_exit = false; + -void *sassert_malloc(size_t size) -{ - void *p = malloc(size); - sassert(p != nullptr, "Memory allocation failed %i", size); - return p; -} struct RingBuffer { unsigned char *buffer = nullptr; int head; int tail; size_t buffer_size; + size_t size_per_item; size_t size; size_t count; - RingBuffer(size_t rb_len, size_t buffer_len, unsigned char * buffer_ptr) + RingBuffer(size_t count_frame, unsigned char * buffer_ptr, size_t buffer_len) { buffer = buffer_ptr; buffer_size = buffer_len; - size = rb_len; + size = count_frame; head = 0; tail = 0; count = 0; - Raylib::nocashMessageFormat("per block %i", buffer_size/size); + size_per_item = buffer_size/size; } unsigned char* Get() @@ -80,7 +70,7 @@ struct RingBuffer { if (count > 0) { count--; - unsigned char* ptr = &buffer[head*(buffer_size/size)]; + unsigned char* ptr = &buffer[head*size_per_item]; head = (head+1) % size; return ptr; } @@ -93,7 +83,7 @@ struct RingBuffer { if (count < size) { count++; - unsigned char* ptr = &buffer[tail*(buffer_size/size)]; + unsigned char* ptr = &buffer[tail*size_per_item]; tail = (tail+1) % size; return ptr; } @@ -103,13 +93,13 @@ struct RingBuffer { unsigned char* Manual_Read() { - unsigned char* ptr = &buffer[head*(buffer_size/size)]; + unsigned char* ptr = &buffer[head*size_per_item]; return ptr; } unsigned char* Manual_Write() { - unsigned char* ptr = &buffer[tail*(buffer_size/size)]; + unsigned char* ptr = &buffer[tail*size_per_item]; return ptr; } @@ -240,6 +230,21 @@ int file_music_len; FILE *file_videomain = nullptr; int file_videomain_len; +uint8_t metadata_fps; +uint8_t metadata_frame_per_chunk; +uint16_t metadata_width1; +uint16_t metadata_width2; +uint16_t metadata_height1; +uint16_t metadata_height2; +uint32_t metadata_total_frame1; +uint32_t metadata_total_frame2; + +uint32_t size_video1_frame; +uint32_t size_video2_frame; +uint32_t size_buffer_frame; + +uint32_t counter_frame; + RingBuffer *videomain_rb; unsigned char *frame_preload_temp; unsigned char *frame_read_temp; @@ -253,69 +258,165 @@ uint32_t next_video_size = 0; volatile int timer_start = 0; volatile int timer_avg = 0; +PrintConsole console_top; +PrintConsole console_bot; + int main(void) { videoSetMode(MODE_5_3D); videoSetModeSub(MODE_5_2D); vramSetBankA(VRAM_A_MAIN_BG); - vramSetBankC(VRAM_C_SUB_BG); + vramSetBankC(VRAM_C_SUB_BG_0x06200000); vramSetBankF(VRAM_F_TEX_PALETTE); - consoleDemoInit(); + // consoleDemoInit(); consoleDebugInit(DebugDevice_NOCASH); bool nitrofs = nitroFSInit(NULL); sassert(nitrofs, "nitrofs init failed"); - frame_preload_temp = (unsigned char*)sassert_malloc(VIDEO_TEMP_SIZE); - music_buffer_temp = (unsigned char*)sassert_malloc(MUSIC_RBUF_SIZE); + bool fatfs = fatInitDefault(); + sassert(fatfs, "fatfs init failed"); - videomain_rb = new RingBuffer(VIDEO_RBUF_LEN, VIDEO_RBUF_LEN*VIDEO_RBUF_BUFFER, (unsigned char*)sassert_malloc(VIDEO_RBUF_LEN*VIDEO_RBUF_BUFFER)); - music_rb = new Rbuf_Music(MUSIC_RBUF_SIZE, (unsigned char*)sassert_malloc(MUSIC_RBUF_SIZE)); - - memset(music_rb->buffer, 0, MUSIC_RBUF_SIZE); - - file_videomain = fopen("nitro:/main_img.bin", "rb"); - sassert(file_videomain != nullptr, "failed to load image.bin"); + file_videomain = fopen("nitro:/video.sillyvideo", "rb"); + sassert(file_videomain != nullptr, "failed to load video.sillyvideo"); fseek(file_videomain, 0, SEEK_END); file_videomain_len = ftell(file_videomain); fseek(file_videomain, 0, SEEK_SET); file_music = fopen("nitro:/music1.raw", "rb"); - sassert(file_music != nullptr, "failed to load music.raw"); + sassert(file_music != nullptr, "failed to load music1.raw"); fseek(file_music, 0, SEEK_END); file_music_len = ftell(file_music); fseek(file_music, 0, SEEK_SET); - ptr_background = bgInit(3, BgType_Bmp8, BgSize_B8_256x256, 0, 0); - // ptr_subbackground = bgInitSub(3, BgType_Bmp8, BgSize_B8_256x256, VRAM_C_SUB_BG, 0); + ptr_background = bgInit(3, BgType_Bmp8, BgSize_B8_256x256, 1, 0); + ptr_subbackground = bgInitSub(3, BgType_Bmp8, BgSize_B8_256x256, 1, 0); - int palmain_len; - unsigned char* palmain = Raylib::LoadFile("nitro:/main_pal.bin", palmain_len); + consoleInit(&console_top, 1, BgType_Text4bpp, BgSize_T_256x256, 2, 0, true, true); + consoleInit(&console_bot, 1, BgType_Text4bpp, BgSize_T_256x256, 2, 0, false, true); - DC_FlushRange(palmain, palmain_len); - dmaCopy(palmain, BG_PALETTE, palmain_len); + bgSetPriority(ptr_background, 1); + bgSetPriority(ptr_subbackground, 1); - Raylib::UnloadFile(palmain); + // consoleSetColor(&console, CONSOLE_RED); + + Panda::printf_nocash("scroll %i", metadata_height1); { - Raylib::nocashMessageFormat("preload video main"); - do { - unsigned char *ptr = videomain_rb->Manual_Write(); - LoadNextChunk(ptr); - videomain_rb->Manual_Skip(CHUNK_SIZE); - } while(videomain_rb->count+CHUNK_SIZE < videomain_rb->size); + Panda::printf_nocash("read metadata"); + fread(&metadata_fps, sizeof(uint8_t), 1, file_videomain); + fread(&metadata_frame_per_chunk, sizeof(uint8_t), 1, file_videomain); + fread(&metadata_total_frame1, sizeof(uint32_t), 1, file_videomain); + fread(&metadata_total_frame2, sizeof(uint32_t), 1, file_videomain); + fread(&metadata_width1, sizeof(uint16_t), 1, file_videomain); + fread(&metadata_height1, sizeof(uint16_t), 1, file_videomain); + fread(&metadata_width2, sizeof(uint16_t), 1, file_videomain); + fread(&metadata_height2, sizeof(uint16_t), 1, file_videomain); - Raylib::nocashMessageFormat("preload done"); + size_video1_frame = metadata_width1*metadata_height1; + size_video2_frame = metadata_width2*metadata_height2; + size_buffer_frame = size_video1_frame + size_video2_frame; + + Panda::printf_nocash("fps: %i", metadata_fps); + Panda::printf_nocash("frame per chunk: %i", metadata_frame_per_chunk); + Panda::printf_nocash("video1 total frame: %i", metadata_total_frame1); + Panda::printf_nocash("video2 total frame: %i", metadata_total_frame2); + Panda::printf_nocash("video1 dimension: %ix%i", metadata_width1, metadata_height1); + Panda::printf_nocash("video2 dimension: %ix%i", metadata_width2, metadata_height2); + } + + bgSetScale(ptr_background, 160, 160); + bgSetScale(ptr_subbackground, 160, 160); + bgSetCenter(ptr_background, 0, (SCREEN_HEIGHT-144)/2); + bgSetCenter(ptr_subbackground, 0, (SCREEN_HEIGHT-144)/2); + bgUpdate(); + + { + Panda::printf_nocash("read palette"); + unsigned char *buffer_palette = (unsigned char*)sassert_malloc(PALETTE_SIZE); + + fread(buffer_palette, sizeof(uint8_t), PALETTE_SIZE*sizeof(uint16_t), file_videomain); + DC_FlushRange(buffer_palette, PALETTE_SIZE*sizeof(uint16_t)); + dmaCopy(buffer_palette, BG_PALETTE, PALETTE_SIZE*sizeof(uint16_t)); + + fread(buffer_palette, sizeof(uint8_t), PALETTE_SIZE*sizeof(uint16_t), file_videomain); + DC_FlushRange(buffer_palette, PALETTE_SIZE*sizeof(uint16_t)); + dmaCopy(buffer_palette, BG_PALETTE_SUB, PALETTE_SIZE*sizeof(uint16_t)); + + free(buffer_palette); } { - Raylib::nocashMessageFormat("preload audio"); + Panda::printf_nocash("allocate buffer"); + + frame_preload_temp = (unsigned char*)sassert_malloc(size_buffer_frame*metadata_frame_per_chunk); + music_buffer_temp = (unsigned char*)sassert_malloc(MUSIC_RBUF_SIZE); + + int rbuf_count = 3145728 / (size_buffer_frame*metadata_frame_per_chunk); + Panda::printf_nocash("rbuf %i", rbuf_count); + + size_t size_rbuf_count = rbuf_count*metadata_frame_per_chunk; + size_t size_rbuf_buffer = size_rbuf_count*size_buffer_frame; + + unsigned char* buffer_video = (unsigned char*)sassert_malloc(size_rbuf_buffer); + unsigned char* buffer_music = (unsigned char*)sassert_malloc(MUSIC_RBUF_SIZE); + + videomain_rb = new RingBuffer(rbuf_count*metadata_frame_per_chunk, buffer_video, size_rbuf_buffer); + music_rb = new Rbuf_Music(MUSIC_RBUF_SIZE, buffer_music); + + memset(music_rb->buffer, 0, MUSIC_RBUF_SIZE); + } + + // { + // Raylib::nocashMessageFormat("calculate decompress time"); + + // unsigned char *ptr = videomain_rb->Manual_Write(); + // FILE *data = fopen("fat:/numbers.txt", "w"); + + // if (data == NULL) { + // perror("Failed to open file"); + // } + + // cpuStartTiming(1); + + // while (ftell(file_videomain) < file_videomain_len) + // { + // timer_start = cpuGetTiming(); + // fread(&preload_video_size, sizeof(uint32_t), 1, file_videomain); + // fread(frame_preload_temp, sizeof(uint8_t), preload_video_size, file_videomain); + // decompress(frame_preload_temp, ptr, DecompressType::LZ77); + // timer_avg = timerTicks2msec(cpuGetTiming() - timer_start); + // // time[counter] = timer_avg; + + // fprintf(stderr, "%i,\n", timer_avg); + // fprintf(data, "%i, ", timer_avg); + // } + + // fclose(data); + // cpuEndTiming(); + // Raylib::nocashMessageFormat("done calculate"); + // fseek(file_videomain, 0, SEEK_SET); + // } + + { + Panda::printf_nocash("preload video main"); + do { + unsigned char *ptr = videomain_rb->Manual_Write(); + LoadNextChunk(ptr); + videomain_rb->Manual_Skip(metadata_frame_per_chunk); + } while(videomain_rb->getFree() >= metadata_frame_per_chunk); + + Panda::printf_nocash("preload done"); + } + + { + Panda::printf_nocash("preload audio"); int len = music_rb->GetFree(); int adv = fread(music_rb->GetTail(), sizeof(char), len, file_music); music_rb->Advance(adv); - Raylib::nocashMessageFormat("preload done"); + Panda::printf_nocash("preload done"); } mm_ds_system sys; @@ -326,40 +427,24 @@ int main(void) { mmInit(&sys); mm_stream mystream; - mystream.sampling_rate = 22050; + mystream.sampling_rate = 16000; mystream.buffer_length = MMSTREAM_BUF_SIZE; mystream.callback = on_stream_request; - mystream.format = MM_STREAM_16BIT_STEREO; + mystream.format = MM_STREAM_8BIT_MONO; mystream.timer = MM_TIMER1; mystream.manual = false; - timerStart(0, ClockDivider_1024, TIMER_FREQ_1024(FRAMERATE), TimerCallback); - irqSet(IRQ_VBLANK, []{ - printf("\033[4;2H\033[Kvideo buffer: %i frames\n", videomain_rb->count); - printf("\033[5;2H\033[Kmusic buffer: %i bytes\n", music_rb->count); - if (noframe) printf("\033[6;2H\033[Kno frame: %i\n", noframe); + timerStart(0, ClockDivider_1024, TIMER_FREQ_1024(metadata_fps), TimerCallback); + irqSet(IRQ_VBLANK, VBLCallback); - // static int counter = 0; - // counter++; - - // if (counter % 30 == 0) - // printf("\033[6;2H\033[Kavg decode time: %ims\n", timerTicks2msec(timer_avg/30)); - - scanKeys(); - if (keysUp() & KEY_A) isPause = !isPause; - if (keysUp() & KEY_B) FrameStep(); - if (keysHeld() & KEY_Y) FrameStep(); - }); - - cothread_create(ThreadMusic, NULL, 0, COTHREAD_DETACHED); + // cothread_create(ThreadMusic, NULL, 0, COTHREAD_DETACHED); // cothread_create(ThreadVideo, NULL, 0, COTHREAD_DETACHED); // cpuStartTiming(1); mmStreamOpen( &mystream ); - while(1) { - cothread_yield(); + while(!time_to_exit) { // swiWaitForVBlank(); // cothread_yield_irq(IRQ_VBLANK); // scanKeys(); @@ -372,11 +457,11 @@ int main(void) { if (file_videomain) { unsigned char *ptr = videomain_rb->Manual_Write(); - if (videomain_rb->count+CHUNK_SIZE < videomain_rb->size) + if (videomain_rb->getFree() >= metadata_frame_per_chunk) { // timer_start = cpuGetTiming(); LoadNextChunk(ptr); - videomain_rb->Manual_Skip(CHUNK_SIZE); + videomain_rb->Manual_Skip(metadata_frame_per_chunk); // timer_avg = cpuGetTiming() - timer_start; } } @@ -387,6 +472,50 @@ int main(void) { file_videomain = nullptr; // return 0; } + + if (file_music != nullptr && music_rb->count < music_rb->size*0.7) + { + int free = music_rb->GetFree(); + int linear = music_rb->LinearWriteSize(); + int adv = 0; + + // memset(music_buffer_temp, 0, MUSIC_RBUF_SIZE); + // fread(music_buffer_temp, free, 1, file_music); + + + if (free < linear) + { + // memcpy(music_rb->GetTail(), music_buffer_temp, free); + adv += fread(music_rb->GetTail(), 1, free, file_music); + } + else + { + // memcpy(music_rb->GetTail(), music_buffer_temp, linear); + // memcpy(music_rb->buffer, music_buffer_temp, free-linear); + adv += fread(music_rb->GetTail(), 1, linear, file_music); + adv += fread(music_rb->buffer, 1, free-linear, file_music); + } + + music_rb->Advance(adv); + + } + + if (ftell(file_music) >= file_music_len) + { + fclose(file_music); + file_music = nullptr; + Panda::printf_nocash("music close!"); + } + + static bool closeOnce = false; + + if (!closeOnce && file_music == nullptr && music_rb->count <= 0) + { + mmStreamClose(); + Panda::printf_nocash("stream close!"); + closeOnce = true; + time_to_exit = true; + } } } @@ -394,86 +523,37 @@ int main(void) { return 0; } -int ThreadVideo(void *arg) +void VBLCallback() { - // while(1) { - // if (videomain_rb->getFree() > (sizeof(uint32_t)+preload_video_size) && videomain_rb->getFree() > videomain_rb->size/2) - // { - // // Raylib::nocashMessageFormat("video thread %i %i", videomain_rb->getFree(), preload_video_size+4); + static int counter = 0; + counter++; - // // if (comutex_try_acquire(&mutex)) - // // { - // bool preload; - // do { - // preload = LoadNextChunk(file_videomain); - // } while(preload); - // // comutex_release(&mutex); - // // } - // } + if (counter % 8 == 0) { - // if (ftell(file_videomain) == file_videomain_len) - // { - // fclose(file_videomain); - // file_videomain = nullptr; - // return 0; - // } - // cothread_yield(); - // } + consoleSelect(&console_top); + // float progress = counter_frame/metadata_total_frame1; + Panda::f32 f32_counter(inttof32(counter_frame)); + Panda::f32 f32_total(inttof32(metadata_total_frame1)); + Panda::f32 f32_progress((f32_counter/f32_total) * Panda::f32(inttof32(100))); + Panda::f32 f32_bar((f32_counter/f32_total) * Panda::f32(inttof32(30))); - // // Raylib::nocashMessageFormat("video thread exit"); - // return 0; -} + printf("\033[22;1H%i%% (%i/%i)\n[", f32toint(f32_progress.value), counter_frame, metadata_total_frame1); + for(int i=0; icount < music_rb->size*0.35) - { - int free = music_rb->GetFree(); - int linear = music_rb->LinearWriteSize(); - int adv = 0; - - // memset(music_buffer_temp, 0, MUSIC_RBUF_SIZE); - // fread(music_buffer_temp, free, 1, file_music); - - - if (free < linear) - { - // memcpy(music_rb->GetTail(), music_buffer_temp, free); - adv += fread(music_rb->GetTail(), 1, free, file_music); - } - else - { - // memcpy(music_rb->GetTail(), music_buffer_temp, linear); - // memcpy(music_rb->buffer, music_buffer_temp, free-linear); - adv += fread(music_rb->GetTail(), 1, linear, file_music); - adv += fread(music_rb->buffer, 1, free-linear, file_music); - } - - music_rb->Advance(adv); - - } - - if (ftell(file_music) >= file_music_len) - { - fclose(file_music); - file_music = nullptr; - Raylib::nocashMessageFormat("music close!"); - } - - static bool closeOnce = false; - - if (!closeOnce && file_music == nullptr && music_rb->count <= 0) - { - mmStreamClose(); - Raylib::nocashMessageFormat("stream close!"); - closeOnce = true; - } + consoleSelect(&console_bot); + printf("\033[21;1H\033[Kvideo buffer: %i frames", videomain_rb->count); + printf("\033[22;1H\033[Kmusic buffer: %i bytes", music_rb->count); + if (noframe) printf("\033[23;1H\033[Kframe drop: %i", noframe); + // else printf("\033[23;1H\033[Kframe drop: %i yay \\ >.< /\n", noframe); } - return 0; + // printf("\033[6;2H\033[Kavg decode time: %ims\n", timerTicks2msec(timer_avg/30)); + + scanKeys(); + if (keysUp() & KEY_A) isPause = !isPause; + if (keysUp() & KEY_B) FrameStep(); + if (keysHeld() & KEY_Y) FrameStep(); } void FrameStep() @@ -482,26 +562,14 @@ void FrameStep() if (videomain_rb->count) { - // if (comutex_try_acquire(&mutex)) - // { - // videomain_rb->Get(); - // videomain_rb->read((unsigned char*)&next_video_size, sizeof(uint32_t)); - unsigned char *dest = videomain_rb->Get(); - // Raylib::nocashMessageFormat("frame step start %p %i", dest, videomain_rb->count); - - // videomain_rb->read(frame_read_temp, next_video_size); - - // DC_FlushRange(dest, VIDEO_RBUF_BUFFER); - // decompress(dest, bgGetGfxPtr(ptr_background), DecompressType::LZ77Vram); - dmaCopyAsynch(dest, bgGetGfxPtr(ptr_background), FRAME_SIZE); - // dmaCopyAsynch(frame_temp, bgGetGfxPtr(ptr_background), FRAME_SIZE); - - // comutex_release(&mutex); - // Raylib::nocashMessageFormat("frame step end"); - } else { - printf("no frame!!!!!\n"); - noframe++; - } + unsigned char *dest = videomain_rb->Get(); + dmaCopyAsynch(dest, bgGetGfxPtr(ptr_background), size_video1_frame); + dmaCopyAsynch(dest+size_video1_frame, bgGetGfxPtr(ptr_subbackground), size_video2_frame); + counter_frame++; + } else { + // printf("no frame!!!!!\n"); + noframe++; + } // } } @@ -517,13 +585,18 @@ void TimerCallback() bool LoadNextChunk(unsigned char *dest) { if (!dest) return false; - // Raylib::nocashMessageFormat("load next start, %p", dest); - // videomain_rb->write((unsigned char*)&preload_video_size, sizeof(uint32_t)); - fread(&preload_video_size, sizeof(uint32_t), 1, file_videomain); - fread(frame_preload_temp, sizeof(uint8_t), preload_video_size, file_videomain); - decompress(frame_preload_temp, dest, DecompressType::LZ77); + // Panda::printf_nocash("load next start, %i", preload_video_size); + if (preload_video_size == size_buffer_frame*metadata_frame_per_chunk) + { + fread(dest, sizeof(uint8_t), preload_video_size, file_videomain); + } + else + { + fread(frame_preload_temp, sizeof(uint8_t), preload_video_size, file_videomain); + decompress(frame_preload_temp, dest, DecompressType::LZ77); + } // fastlz_decompress(frame_preload_temp, preload_video_size, dest, FRAME_SIZE*CHUNK_SIZE); return true; @@ -565,13 +638,13 @@ mm_word on_stream_request( mm_word length, mm_addr dest, mm_stream_formats forma if (len < linear) { - memcpy(dest, music_rb->GetHead(), len); + tonccpy(dest, music_rb->GetHead(), len); } else { // Raylib::nocashMessageFormat("linear %i", linear); - memcpy(dest, music_rb->GetHead(), linear); - memcpy((char*)dest+linear, music_rb->buffer, len-linear); + tonccpy(dest, music_rb->GetHead(), linear); + tonccpy((char*)dest+linear, music_rb->buffer, len-linear); } music_rb->Skip(len);