diff --git a/osufs/osufs/fontenc.c b/osufs/osufs/fontenc.c index a7ed4f37f59b681d277682d5128d40c64ec2808a..247d7252a103e06675f51097d7a41eccc6cf8ee2 100644 --- a/osufs/osufs/fontenc.c +++ b/osufs/osufs/fontenc.c @@ -77,3 +77,43 @@ uint32_t font_write(const char *filename, int ptsize, mdev *dev, uint32_t addr) return addr; } +uint32_t font_score_write(const char *dirname, mdev *dev, uint32_t addr) { + +#define FONT_IMPORT_GLYPH(chr, filename)\ +strcpy(fname, filename);\ +w = -1;\ +fnt.font[chr-' '] = addr;\ +addr = img_write_dither64(cbuf, dev, addr, &(w), &(h));\ +fnt.widths[chr-' '] = w; + + osu_font fnt; + memset(&fnt, 0, sizeof(fnt)); + char cbuf[1024], *fname = cbuf + strlen(dirname); + strncpy(cbuf, dirname, 1024); + *fname = '/'; + fname++; + + fnt.height = 36; + uint16_t w, h = fnt.height; + + FONT_IMPORT_GLYPH('0', "score-0.png") + FONT_IMPORT_GLYPH('1', "score-1.png") + FONT_IMPORT_GLYPH('2', "score-2.png") + FONT_IMPORT_GLYPH('3', "score-3.png") + FONT_IMPORT_GLYPH('4', "score-4.png") + FONT_IMPORT_GLYPH('5', "score-5.png") + FONT_IMPORT_GLYPH('6', "score-6.png") + FONT_IMPORT_GLYPH('7', "score-7.png") + FONT_IMPORT_GLYPH('8', "score-8.png") + FONT_IMPORT_GLYPH('9', "score-9.png") + FONT_IMPORT_GLYPH(',', "score-comma.png") + FONT_IMPORT_GLYPH('.', "score-dot.png") + FONT_IMPORT_GLYPH('%', "score-percent.png") + FONT_IMPORT_GLYPH('x', "score-x.png") + + + blkio_write(dev, addr++, &fnt); + strncpy(fnt.magic, "oFNT", 4); + + return addr; +} diff --git a/osufs/osufs/fontenc.h b/osufs/osufs/fontenc.h index fb8e8bd0a5a6d9ac64bf3394fc0023d52acb3e75..e51c01379c2ec3cd6f9ba8ceea916a486a030ded 100644 --- a/osufs/osufs/fontenc.h +++ b/osufs/osufs/fontenc.h @@ -17,7 +17,8 @@ extern "C" { #include "blkio.h" uint32_t font_write(const char *filename, int ptsize, mdev *dev, uint32_t addr); - + uint32_t font_score_write(const char *dirname, mdev *dev, uint32_t addr); + #ifdef __cplusplus } #endif diff --git a/osufs/osufs/imgenc.c b/osufs/osufs/imgenc.c index 66f3163d9f94c3bcb169efeadd427f546fe8ae58..e2ca880410860e1c4f2c1ac269f07a48666abfc8 100644 --- a/osufs/osufs/imgenc.c +++ b/osufs/osufs/imgenc.c @@ -67,7 +67,7 @@ uint32_t img_write_dither128(const char *filename, mdev *dev, uint32_t addr) { // Dump image, row major printf("Saving pixels in %s\n", filename); - size_t bufsize = png_get_rowbytes(img.png_ptr, img.info_ptr) * img.height; + ssize_t bufsize = png_get_rowbytes(img.png_ptr, img.info_ptr) * img.height; size_t bufptr = 0; while (bufsize > 0) { blkio_write(dev, addr++, img.row_pointers[0]+bufptr); @@ -80,7 +80,85 @@ uint32_t img_write_dither128(const char *filename, mdev *dev, uint32_t addr) { return addr; } -uint32_t img_write_rgb16(const char *filename, mdev *dev, uint32_t addr, uint16_t *w, uint16_t *h) { +uint32_t img_write_dither64(const char *filename, mdev *dev, uint32_t addr, + uint16_t *w, uint16_t *h) { + char cbuf[1024]; + int ret; + + int w_signed = *w==0xffff ? -1 : *w, h_signed = *h==0xffff ? -1 : *h; + + system("rm -f /tmp/source.png /tmp/plt.png /tmp/dither.png"); + + // Resize + sprintf(cbuf, "ffmpeg -loglevel error -i \"%s\" -vf \"scale=%d:%d\" /tmp/source.png", filename, w_signed, h_signed); + ret = system(cbuf); + if (ret != 0) { + fprintf(stderr, "ffmpeg resize failed with exit code: %d\n", ret); + return addr; + } + + // PaletteGen + ret = system("ffmpeg -loglevel error -i /tmp/source.png -vf \"palettegen=max_colors=64\" /tmp/plt.png"); + if (ret != 0) { + fprintf(stderr, "ffmpeg palettegen failed with exit code: %d\n", ret); + return addr; + } + + // Dithering + ret = system("ffmpeg -loglevel error -i /tmp/source.png -i /tmp/plt.png -lavfi \"paletteuse=dither=floyd_steinberg\" -y /tmp/dither.png"); + if (ret != 0) { + fprintf(stderr, "ffmpeg dithering failed with exit code: %d\n", ret); + } + + + PNGImage img = pngimg_read("/tmp/dither.png"); + if (img.color_type != PNG_COLOR_TYPE_PALETTE) { + fprintf(stderr, "Internal Error: dithered image is not index!\n"); + return addr; + } + + png_colorp plt; + int nplt; + if (!png_get_PLTE(img.png_ptr, img.info_ptr, &plt, &nplt)) { + fprintf(stderr, "Internal Error: failed to read palette!\n"); + return addr; + } + + // Dump palette + uint8_t buf[512], *pltbuf = buf + 3; + buf[0] = 'P'; + buf[1] = 'L'; + buf[2] = 'T'; + for (int i=0; i<64; i++) { + pltbuf[i*3+0] = plt[0xff-i].red; + pltbuf[i*3+1] = plt[0xff-i].green; + pltbuf[i*3+2] = plt[0xff-i].blue; + } + blkio_write(dev, addr++, buf); + + // Dump image, row major + *w = img.width; + *h = img.height; + printf("Saving pixels in %s\n", filename); + ssize_t bufsize = png_get_rowbytes(img.png_ptr, img.info_ptr) * img.height; + size_t bufptr = 0; + uint8_t pixbuf[512]; + while (bufsize > 0) { + for (int i=0; i<512 && bufsize>0; i++) { + pixbuf[i] = 0xff - (img.row_pointers[0]+bufptr)[i]; + bufsize--; + } + blkio_write(dev, addr++, pixbuf); + bufptr += 512; + } + + pngimg_release(&img); + + return addr; +} + +uint32_t img_write_rgb16(const char *filename, mdev *dev, uint32_t addr, + uint16_t *w, uint16_t *h) { char cbuf[1024]; int ret; diff --git a/osufs/osufs/imgenc.h b/osufs/osufs/imgenc.h index 1f49ea13d561d890a627f56b3a5651d3c3befda2..f0a0e948708398d20c34e233e81df70dee0cec0f 100644 --- a/osufs/osufs/imgenc.h +++ b/osufs/osufs/imgenc.h @@ -17,7 +17,10 @@ extern "C" { #include "blkio.h" uint32_t img_write_dither128(const char *filename, mdev *dev, uint32_t addr); - uint32_t img_write_rgb16(const char *filename, mdev *dev, uint32_t addr, uint16_t *w, uint16_t *h); + uint32_t img_write_dither64(const char *filename, mdev *dev, uint32_t addr, + uint16_t *w, uint16_t *h); + uint32_t img_write_rgb16(const char *filename, mdev *dev, uint32_t addr, + uint16_t *w, uint16_t *h); #ifdef __cplusplus } diff --git a/osufs/osufs/main.cpp b/osufs/osufs/main.cpp index bada42e0ef0d3c8dba7be556ceedcfb5fbafa365..28f3b5c51fa640a9e9e01b994d46b124ae5f6a49 100644 --- a/osufs/osufs/main.cpp +++ b/osufs/osufs/main.cpp @@ -29,8 +29,10 @@ int main(int argc, char *argv[]) { // Self-checks assert(sizeof(osu_meta) == 512 && "Invalid osu_meta struct size"); assert(sizeof(osu_song) == 512 && "Invalid osu_song struct size"); + assert(sizeof(osu_font) == 512 && "Invalid osu_font struct size"); assert(sizeof(elem_hit_circle) == 32 && "Invalid elem_hit_circle size"); assert(sizeof(elem_spinner) == 32 && "Invalid elem_spinner size"); + assert(sizeof(osu_storyboard) == 2097152 && "Invalid osu_storyboard size"); mdev *dev = blkio_open(argv[1]); if (!dev) { diff --git a/osufs/osufs/osu.cpp b/osufs/osufs/osu.cpp index 85a03135f158144caffd0630359f89109dc67a01..3f592265e831d62289f47fbd46002c20bb5416fa 100644 --- a/osufs/osufs/osu.cpp +++ b/osufs/osufs/osu.cpp @@ -39,6 +39,13 @@ meta-> entry ## _w = w;\ meta-> entry ## _h = h;\ addr = img_write_rgb16(cbuf, dev, addr, &(meta-> entry ## _w), &(meta-> entry ## _h)); +#define SKIN_IMPORT_IMAGE_DITHER64(entry, filename, w, h)\ +strcpy(fname, filename);\ +meta-> entry = addr;\ +meta-> entry ## _w = w;\ +meta-> entry ## _h = h;\ +addr = img_write_dither64(cbuf, dev, addr, &(meta-> entry ## _w), &(meta-> entry ## _h)); + char cbuf[1024], *fname; uint32_t addr = meta->available_block; @@ -98,16 +105,16 @@ addr = img_write_rgb16(cbuf, dev, addr, &(meta-> entry ## _w), &(meta-> entry ## SKIN_IMPORT_IMAGE(pause_continue, "pause-continue.png", 235, -1) SKIN_IMPORT_IMAGE(pause_retry, "pause-retry.png", 235, -1) - SKIN_IMPORT_IMAGE(ranking_ss, "ranking-X.png", 160, -1) - SKIN_IMPORT_IMAGE(ranking_s, "ranking-S.png", 160, -1) - SKIN_IMPORT_IMAGE(ranking_a, "ranking-A.png", 160, -1) - SKIN_IMPORT_IMAGE(ranking_b, "ranking-B.png", 160, -1) - SKIN_IMPORT_IMAGE(ranking_c, "ranking-C.png", 160, -1) - SKIN_IMPORT_IMAGE(ranking_d, "ranking-D.png", 160, -1) + SKIN_IMPORT_IMAGE_DITHER64(ranking_ss, "ranking-X.png", 160, -1) + SKIN_IMPORT_IMAGE_DITHER64(ranking_s, "ranking-S.png", 160, -1) + SKIN_IMPORT_IMAGE_DITHER64(ranking_a, "ranking-A.png", 160, -1) + SKIN_IMPORT_IMAGE_DITHER64(ranking_b, "ranking-B.png", 160, -1) + SKIN_IMPORT_IMAGE_DITHER64(ranking_c, "ranking-C.png", 160, -1) + SKIN_IMPORT_IMAGE_DITHER64(ranking_d, "ranking-D.png", 160, -1) + + SKIN_IMPORT_IMAGE_DITHER64(ranking_title, "ranking-title.png", 240, -1) + SKIN_IMPORT_IMAGE_DITHER64(ranking_panel, "ranking-panel.png", 378, -1) -// SKIN_IMPORT_IMAGE(ranking_title, "ranking-title.png", 240, -1) -// SKIN_IMPORT_IMAGE(ranking_panel, "ranking-panel.png", 378, -1) - meta->selection_w = 48; meta->selection_h = 56; meta->selection_mod = addr; @@ -148,6 +155,10 @@ addr = img_write_rgb16(cbuf, dev, addr, &(meta-> entry ## _w), &(meta-> entry ## #pragma clang diagnostic pop + // Score fonts + addr = font_score_write(dirname, dev, addr); + meta->font_score = addr-1; + // Update meta addr meta->available_block = addr; } @@ -265,6 +276,15 @@ osu_song osu_read_osu(const char *filename, mdev *dev, osu_meta *meta, void(0); } + uint32_t addr = meta->available_block; + uint8_t *sbbuf = (uint8_t *) ret.storyboard; + ret.beatmap_begin = addr; + ret.beatmap_len = 4096; + for (int i=0; i<4096; i++) { + blkio_write(dev, addr++, sbbuf+512*i); + } + meta->available_block = addr; + strncpy(ret.magic, "BEAT", 4); printf("Parsing done. Performing sanity check...\n"); @@ -281,7 +301,7 @@ int osu_parse_general(char *line, osu_song *song, return 1; } // AudioFilename (String) specifies the location of the audio file relative to the current folder. - if (0 && strcasecmp(key, "AudioFilename") == 0) { + if (strcasecmp(key, "AudioFilename") == 0) { if (cont->fs.find(val) == cont->fs.end()) { printf("Allocating storage for audio %s\n", val); uint32_t addr = meta->available_block; @@ -481,7 +501,6 @@ int osu_parse_difficulty(char *line, osu_song *song, int osu_parse_events(char *line, osu_song *song, mdev *dev, osu_meta *meta, osu_dir *cont) { // Events section is in CSV format - return 0; switch (line[0]) { case '0': { // Background image diff --git a/osufs/osufs/osu_object_analyze/osu_object_includes.h b/osufs/osufs/osu_object_analyze/osu_object_includes.h index 3dd16acf3500335e65e1fdd359cc12548d298d40..eb1752a1660bbbf885a857d32ad03b400bb06d39 100644 --- a/osufs/osufs/osu_object_analyze/osu_object_includes.h +++ b/osufs/osufs/osu_object_analyze/osu_object_includes.h @@ -17,7 +17,7 @@ typedef struct __attribute__((__packed__)) hit_circle_t{ uint16_t approach_rate; uint16_t gradient_color1; uint16_t gradient_color2; - uint8_t gradient_direction; + uint8_t hit_sound; char type; } elem_hit_circle; diff --git a/osufs/osufs/osu_object_analyze/osu_object_parser.cpp b/osufs/osufs/osu_object_analyze/osu_object_parser.cpp index 4f91e350ce94f7e79e87dfe168c9784ceb7dfe24..bdadffa5369db3f6ab15e694e8b34f011d1f32ce 100644 --- a/osufs/osufs/osu_object_analyze/osu_object_parser.cpp +++ b/osufs/osufs/osu_object_analyze/osu_object_parser.cpp @@ -62,7 +62,7 @@ int osu_parse_hit_object(char* line, osu_song* song){ //hit sound //elemn->hit_sound = stoi(v[4]); // -// elemn->hit_sound = 1; // TODO + sscanf(v[4].c_str(),"%c",&(elemn->hit_sound)); // //handle timing stuff int temp_c = 0; @@ -79,15 +79,20 @@ int osu_parse_hit_object(char* line, osu_song* song){ } //update count and data block if (!song->storyboard){ - song->storyboard = (uint8_t *) malloc(4+4+32*temp_c); - *((uint32_t*)(song->storyboard)) = 0b01110010011001010110000101101100; + song->storyboard = (osu_storyboard*) malloc(sizeof(osu_storyboard)); + /**((uint32_t*)(song->storyboard)) = 0b01110010011001010110000101101100; *((uint32_t*)(song->storyboard)+1) = temp_c; - memcpy(song->storyboard+8,elemn,32*temp_c); + memcpy(song->storyboard+8,elemn,32*temp_c);*/ + song->storyboard->magic = 0b01110010011001010110000101101100; + song->storyboard->object_number = temp_c; }else{ - song->storyboard = (uint8_t *) realloc(song->storyboard,4+4+ + /*song->storyboard = (uint8_t *) realloc(song->storyboard,4+4+ 32*(temp_c+(*((uint32_t*)(song->storyboard)+1)))); memcpy(song->storyboard+8+32*(*((uint32_t*)(song->storyboard)+1)),elemn,32*temp_c); - *((uint32_t*)(song->storyboard)+1) += temp_c; + *((uint32_t*)(song->storyboard)+1) += temp_c;*/ + memcpy(song->storyboard->object_list, + elemn,temp_c*sizeof(elem_hit_circle)); + song->storyboard->object_number += temp_c; } free(elemn); return 0; diff --git a/osufs/osufs/osufs.h b/osufs/osufs/osufs.h index a4b2458c5295aad0cc84876f89f4f3ffbc592321..2b260c3205ace6cb5c90af1d4d8b518e359a9705 100644 --- a/osufs/osufs/osufs.h +++ b/osufs/osufs/osufs.h @@ -16,7 +16,7 @@ extern "C" { #include <stdio.h> #include <inttypes.h> #include "blkio.h" - +#include "osu_object_analyze/osu_object_includes.h" typedef struct __attribute__((__packed__)) osu_meta_t { char magic[4]; // 0 - 3 @@ -209,6 +209,13 @@ extern "C" { char _padding[27]; // 486 - 511 } osu_font; + typedef struct __attribute__((__packed__)) storyboard_t { + uint32_t magic; //4 + uint32_t object_number; //4 + elem_hit_circle object_list[65535]; //fill a total of 4096 blocks + char _padding[24]; //32-8 = 24 + } osu_storyboard; + typedef struct __attribute__((__packed__)) osu_song_t { char magic[4]; // 0 - 3 uint32_t cover_begin, cover_len; // 4 - 11 @@ -228,7 +235,7 @@ extern "C" { uint16_t stack_leniency; // 78 - 79 //for analyze side only - uint8_t *storyboard; // 80 - 87 + osu_storyboard *storyboard; // 80 - 87 uint8_t combo_colors_count; // 88 uint8_t combo_colors_start; // 89 uint8_t combo_slider_color[3]; // 90 - 92 @@ -241,7 +248,8 @@ extern "C" { char creator[32]; // 448 - 479 char version[32]; // 480 - 511 } osu_song; - + + osu_meta osu_read_meta(mdev *dev); osu_song osu_read_song(mdev *dev, int idx); void osu_write_meta(mdev *dev, osu_meta *meta);