From 8abef54773006fba29f7ac48639ae541c5e15d7f Mon Sep 17 00:00:00 2001 From: MCJack123 Date: Fri, 19 Jan 2024 17:09:16 -0500 Subject: [PATCH] Fixed poor compression ratio of ANS --- 32vid-player-mini.lua | 22 +++++++++++++++++++--- src/generator.cpp | 35 ++++++++++++++++++++--------------- src/sanjuuni.cpp | 2 +- 3 files changed, 40 insertions(+), 19 deletions(-) diff --git a/32vid-player-mini.lua b/32vid-player-mini.lua index a121272..4606d72 100644 --- a/32vid-player-mini.lua +++ b/32vid-player-mini.lua @@ -36,6 +36,11 @@ if bit32_band(flags, 3) == 1 then local R = file.read() local L = 2^R local Ls = readDict(c and 24 or 32) + if R == 0 then + decodingTable = file.read() + X = nil + return + end local a = 0 for i = 0, #Ls do Ls[i] = Ls[i] == 0 and 0 or 2^(Ls[i]-1) a = a + Ls[i] end assert(a == L, a) @@ -43,7 +48,10 @@ if bit32_band(flags, 3) == 1 then local x, step, next, symbol = 0, 0.625 * L + 3, {}, {} for i = 0, #Ls do next[i] = Ls[i] - for _ = 1, Ls[i] do x, symbol[x] = (x + step) % L, i end + for _ = 1, Ls[i] do + while symbol[x] do x = (x + 1) % L end + x, symbol[x] = (x + step) % L, i + end end for x = 0, L - 1 do local s = symbol[x] @@ -63,6 +71,10 @@ if bit32_band(flags, 3) == 1 then end function read(nsym) local retval = {} + if X == nil then + for i = 1, nsym do retval[i] = decodingTable end + return retval + end local i = 1 local last = 0 while i <= nsym do @@ -105,6 +117,7 @@ for _ = 1, nframes do local fg = read(width * height) local dctime = os.epoch "utc" - dcstart while os.epoch "utc" < start + vframe * 1000 / fps do end + local texta, fga, bga = {}, {}, {} for y = 0, height - 1 do local text, fgs, bgs = "", "", "" for x = 1, width do @@ -112,10 +125,13 @@ for _ = 1, nframes do fgs = fgs .. blitColors[fg[y*width+x]] bgs = bgs .. blitColors[bg[y*width+x]] end - term.setCursorPos(1, y+1) - term.blit(text, fgs, bgs) + texta[y+1], fga[y+1], bga[y+1] = text, fgs, bgs end for i = 0, 15 do term.setPaletteColor(2^i, file.read() / 255, file.read() / 255, file.read() / 255) end + for y = 1, height do + term.setCursorPos(1, y) + term.blit(texta[y], fga[y], bga[y]) + end local delete = {} for i, v in ipairs(subs) do if vframe <= v.frame + v.length then diff --git a/src/generator.cpp b/src/generator.cpp index d57a0de..8df0af3 100644 --- a/src/generator.cpp +++ b/src/generator.cpp @@ -292,7 +292,7 @@ struct compare_node {bool operator()(tree_node *a, tree_node *b) { std::string make32vid_cmp(const uchar * characters, const uchar * colors, const std::vector& palette, int width, int height) { std::string screen, col, pal; - tree_node screen_nodes[32], color_nodes[24]; // color codes 16-23 = repeat last color 2^(n-15) times + tree_node screen_nodes[32] = {0}, color_nodes[24] = {0}; // color codes 16-23 = repeat last color 2^(n-15) times tree_node internal[31]; tree_node * internal_next = internal; uchar * fgcolors = new uchar[width*height]; @@ -539,26 +539,30 @@ class ANSEncoder { start = new int32_t[Lsl]; uint32_t * next = new uint32_t[Lsl]; uint8_t * symbol = new uint8_t[L]; + memset(symbol, 0xFF, L); uint32_t sumLs = 0; - const uint32_t step = 0.625 * L + 3; + const uint32_t step = ((L * 5) >> 3) + 3; for (uint8_t s = 0; s < Lsl; s++) { const uint32_t v = Ls[s]; - const uint32_t ks = R - log2i(v); - nb[s] = (ks << (R+1)) - (v << ks); - start[s] = (int32_t)sumLs - (int32_t)v; - next[s] = v; - for (int i = 0; i < v; i++) { - symbol[X] = s; - X = (X + step) % L; + //std::cout << (int)s << " " << v << "\n"; + if (v) { + const uint32_t ks = R - log2i(v); + nb[s] = (ks << (R+1)) - (v << ks); + start[s] = (int32_t)sumLs - (int32_t)v; + next[s] = v; + for (int i = 0; i < v; i++) { + while (symbol[X] != 0xFF) X = (X + 1) % L; + symbol[X] = s; + X = (X + step) % L; + } + sumLs = sumLs + v; } - sumLs = sumLs + v; } // create encoding table encodingTable = new uint32_t[2*L]; for (uint32_t x = L; x < 2*L; x++) { const uint8_t s = symbol[x - L]; - encodingTable[start[s] + next[s]] = x; - next[s]++; + encodingTable[start[s] + next[s]++] = x; } X = L; // free temps @@ -631,6 +635,7 @@ class ANSEncoder { uint8_t s = symbols[_size-1] & 0x1F; for (int i = _size-2; i >= 0; i--) { const uint8_t nbBits = ((X + nb[s]) >> (R + 1)); + //std::cout << (int)s << " " << (int)nbBits << "\n"; const uint8_t nexts = symbols[i] & 0x1F; bitstream[length++] = ((uint32_t)nbBits << 24) | (X & ((1 << nbBits) - 1)); bitCount += nbBits; @@ -685,7 +690,7 @@ static uint8_t ansdictcode(uint32_t n) { std::string make32vid_ans(const uchar * characters, const uchar * colors, const std::vector& palette, int width, int height) { std::string screen, col, pal; - uint32_t screen_freq[32], color_freq[24]; // color codes 16-23 = repeat last color 2^(n-15) times + uint32_t screen_freq[32] = {0}, color_freq[24] = {0}; // color codes 16-23 = repeat last color 2^(n-15) times uchar * fgcolors = new uchar[width*height]; uchar * bgcolors = new uchar[width*height]; uchar *fgnext = fgcolors, *bgnext = bgcolors; @@ -797,7 +802,7 @@ std::string make32vid_ans(const uchar * characters, const uchar * colors, const std::vector screenLs = ANSEncoder::makeLs(screen_freq, 32, screenR); if (screenLs.size() == 1) { // encode a full-screen pattern of the same thing - screen = std::string(16, '\0') + std::string(1, screenLs[0]); + screen = std::string(17, '\0') + std::string(1, screenLs[0]); } else { // compress data screen += screenR; @@ -813,7 +818,7 @@ std::string make32vid_ans(const uchar * characters, const uchar * colors, const std::vector colorsLs = ANSEncoder::makeLs(color_freq, 24, colorsR); if (colorsLs.size() == 1) { // encode a full-screen pattern of the same thing - col = std::string(12, '\0') + std::string(1, colorsLs[0]); + col = std::string(13, '\0') + std::string(1, colorsLs[0]); } else { // compress data col += colorsR; diff --git a/src/sanjuuni.cpp b/src/sanjuuni.cpp index 0420d63..47fbfe2 100644 --- a/src/sanjuuni.cpp +++ b/src/sanjuuni.cpp @@ -1061,7 +1061,7 @@ int main(int argc, const char * argv[]) { if (mode == OutputType::Vid32 && !separateStreams) { Vid32Chunk combinedChunk; Vid32Header header; - combinedChunk.nframes = 0; + combinedChunk.nframes = totalFrames; combinedChunk.type = (uint8_t)Vid32Chunk::Type::Combined; memcpy(header.magic, "32VD", 4); header.width = width / 2;