From 253c6f1e6f1eb8de749f065f649d0026880e4d08 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Sat, 19 Apr 2025 00:17:12 +0200 Subject: [PATCH 01/12] use a sparse vector for color rotations to reduce memory usage --- src/serum-decode.cpp | 130 ++++++++++++++++++++++++++++++++----------- 1 file changed, 99 insertions(+), 31 deletions(-) diff --git a/src/serum-decode.cpp b/src/serum-decode.cpp index 7b3a2f0..b642bc6 100644 --- a/src/serum-decode.cpp +++ b/src/serum-decode.cpp @@ -6,7 +6,8 @@ #include #include #include - +#include +#include #include #include #include @@ -53,6 +54,68 @@ const int pathbuflen = 4096; const uint32_t MAX_NUMBER_FRAMES = 0x7fffffff; const uint32_t IDENTIFY_SAME_FRAME = 0xfffffffe; +uint8_t* zeroBufferByte; +uint16_t* zeroBufferWord; + +class SparseVectorByte { + protected: + std::unordered_map> data; // Only stores non-zero data + public: + // Access data for a frame (returns pointer to zeros if not found) + uint8_t* operator[](const uint32_t frame) { + auto it = data.find(frame); + if (it != data.end()) return it->second.data(); // Existing frame data + return zeroBufferByte; // Default zeros + } + + // Load data (only store if non-zero) + void my_fread(size_t sizeElement, uint32_t nframes, FILE* stream) + { + uint8_t* tmp = (uint8_t*)malloc(sizeElement); + for(uint32_t i = 0; i < nframes; ++i) { + size_t readelem = fread(tmp, sizeElement, 1, stream); + ac_pos_in_file += readelem * sizeElement; + if (memcmp(tmp, zeroBufferByte, sizeElement) != 0) data[i].assign(tmp, tmp + sizeElement); + } + free(tmp); + } + + // Clear all stored frames (free memory) + void clear() { + data.clear(); // Vectors auto-free their memory + } +}; + + +class SparseVectorWord { + protected: + std::unordered_map> data; // Only stores non-zero data + public: + // Access data for a frame (returns pointer to zeros if not found) + uint16_t* operator[](const uint32_t frame) { + auto it = data.find(frame); + if (it != data.end()) return it->second.data(); // Existing frame data + return zeroBufferWord; // Default zeros + } + + // Load data (only store if non-zero) + void my_fread(size_t sizeElement, uint32_t nframes, FILE* stream) + { + uint8_t* tmp = (uint8_t*)malloc(sizeElement); + for(uint32_t i = 0; i < nframes; ++i) { + size_t readelem = fread(tmp, sizeElement, 1, stream); + ac_pos_in_file += readelem * sizeElement; + if (memcmp(tmp, zeroBufferWord, sizeElement) != 0) data[i].assign(tmp, tmp + sizeElement); + } + free(tmp); + } + + // Clear all stored frames (free memory) + void clear() { + data.clear(); // Vectors auto-free their memory + } +}; + // header char rname[64]; uint8_t SerumVersion = 0; @@ -90,8 +153,8 @@ uint16_t* spritecolored = NULL; uint16_t* spritecoloredx = NULL; uint8_t* activeframes = NULL; uint8_t* colorrotations = NULL; -uint16_t* colorrotationsn = NULL; -uint16_t* colorrotationsnx = NULL; +SparseVectorWord colorrotationsn; +SparseVectorWord colorrotationsnx; uint16_t* spritedetareas = NULL; uint32_t* spritedetdwords = NULL; uint16_t* spritedetdwordpos = NULL; @@ -141,7 +204,7 @@ bool enabled = true; // is colorization enabled? bool isoriginalrequested = true; // are the original resolution frames requested by the caller bool isextrarequested = false; // are the extra resolution frames requested by the caller -uint32_t rotationnextabsolutetime[MAX_COLOR_ROTATIONS]; // cumulative time for the next rotation for each color rotation +uint32_t rotationnextabsolutetime[MAX_COLOR_ROTATIONS]; // cumulative time for the next rotation for each color rotation Serum_Frame_Struc mySerum; // structure to keep communicate colorization data @@ -207,8 +270,8 @@ void Serum_free(void) Free_element((void**)&spritecoloredx); Free_element((void**)&activeframes); Free_element((void**)&colorrotations); - Free_element((void**)&colorrotationsn); - Free_element((void**)&colorrotationsnx); + colorrotationsn.clear(); + colorrotationsnx.clear(); Free_element((void**)&spritedetareas); Free_element((void**)&spritedetdwords); Free_element((void**)&spritedetdwordpos); @@ -238,6 +301,10 @@ void Serum_free(void) Free_element((void**)&mySerum.rotationsinframe64); Free_element((void**)&mySerum.modifiedelements32); Free_element((void**)&mySerum.modifiedelements64); + + Free_element((void**)&zeroBufferByte); + Free_element((void**)&zeroBufferWord); + cromloaded = false; } @@ -460,6 +527,9 @@ Serum_Frame_Struc* Serum_LoadFilev2(FILE* pfile, const uint8_t flags, bool uncom my_fread(&nsprites, 4, 1, pfile); my_fread(&nbackgrounds, 2, 1, pfile); // nbackgrounds is a uint16_t + zeroBufferByte = (uint8_t*)malloc(nframes * fwidthx * fheightx * sizeof(uint8_t)); + zeroBufferWord = (uint16_t*)malloc(nframes * fwidthx * fheightx * sizeof(uint16_t)); + hashcodes = (uint32_t*)malloc(sizeof(uint32_t) * nframes); shapecompmode = (uint8_t*)malloc(nframes); compmaskID = (uint8_t*)malloc(nframes); @@ -479,8 +549,6 @@ Serum_Frame_Struc* Serum_LoadFilev2(FILE* pfile, const uint8_t flags, bool uncom spritemaskx = (uint8_t*)malloc(nsprites * MAX_SPRITE_WIDTH * MAX_SPRITE_HEIGHT); spritecoloredx = (uint16_t*)malloc(nsprites * MAX_SPRITE_WIDTH * MAX_SPRITE_HEIGHT * sizeof(uint16_t)); activeframes = (uint8_t*)malloc(nframes); - colorrotationsn = (uint16_t*)malloc(nframes * MAX_LENGTH_COLOR_ROTATION * MAX_COLOR_ROTATIONN * sizeof(uint16_t)); - colorrotationsnx = (uint16_t*)malloc(nframes * MAX_LENGTH_COLOR_ROTATION * MAX_COLOR_ROTATIONN * sizeof(uint16_t)); spritedetdwords = (uint32_t*)malloc(nsprites * sizeof(uint32_t) * MAX_SPRITE_DETECT_AREAS); spritedetdwordpos = (uint16_t*)malloc(nsprites * sizeof(uint16_t) * MAX_SPRITE_DETECT_AREAS); spritedetareas = (uint16_t*)malloc(nsprites * sizeof(uint16_t) * MAX_SPRITE_DETECT_AREAS * 4); @@ -499,7 +567,7 @@ Serum_Frame_Struc* Serum_LoadFilev2(FILE* pfile, const uint8_t flags, bool uncom !cframesn || !cframesnx || !dynamasks || !dynamasksx || !dyna4colsn || !dyna4colsnx || (nsprites > 0 && (!isextrasprite || !spriteoriginal || !spritecolored || !spritemaskx || !spritecoloredx || !spritedetdwords || !spritedetdwordpos || !spritedetareas)) || - !framesprites || !framespriteBB || !activeframes || !colorrotationsn || !colorrotationsnx || + !framesprites || !framespriteBB || !activeframes || !triggerIDs || (nbackgrounds > 0 && (!isextrabackground || !backgroundframesn || !backgroundframesnx)) || !backgroundIDs || !backgroundmask || !backgroundmaskx || !dynashadowsdiro || !dynashadowscolo || !dynashadowsdirx || !dynashadowscolx) @@ -568,8 +636,8 @@ Serum_Frame_Struc* Serum_LoadFilev2(FILE* pfile, const uint8_t flags, bool uncom my_fread(spritemaskx, 1, nsprites * MAX_SPRITE_WIDTH * MAX_SPRITE_HEIGHT, pfile); my_fread(spritecoloredx, 2, nsprites * MAX_SPRITE_WIDTH * MAX_SPRITE_HEIGHT, pfile); my_fread(activeframes, 1, nframes, pfile); - my_fread(colorrotationsn, 2, nframes * MAX_LENGTH_COLOR_ROTATION * MAX_COLOR_ROTATIONN, pfile); - my_fread(colorrotationsnx, 2, nframes * MAX_LENGTH_COLOR_ROTATION * MAX_COLOR_ROTATIONN, pfile); + colorrotationsn.my_fread(2 * MAX_LENGTH_COLOR_ROTATION * MAX_COLOR_ROTATIONN, nframes, pfile); + colorrotationsnx.my_fread(2 * MAX_LENGTH_COLOR_ROTATION * MAX_COLOR_ROTATIONN, nframes, pfile); my_fread(spritedetdwords, 4, nsprites * MAX_SPRITE_DETECT_AREAS, pfile); my_fread(spritedetdwordpos, 2, nsprites * MAX_SPRITE_DETECT_AREAS, pfile); my_fread(spritedetareas, 2, nsprites * 4 * MAX_SPRITE_DETECT_AREAS, pfile); @@ -1137,8 +1205,8 @@ bool CheckExtraFrameAvailable(uint32_t frID) bool ColorInRotation(uint32_t IDfound, uint16_t col, uint16_t* norot, uint16_t* posinrot, bool isextra) { uint16_t* pcol = NULL; - if (isextra) pcol = &colorrotationsnx[IDfound * MAX_COLOR_ROTATIONN * MAX_LENGTH_COLOR_ROTATION]; - else pcol = &colorrotationsn[IDfound * MAX_COLOR_ROTATIONN * MAX_LENGTH_COLOR_ROTATION]; + if (isextra) pcol = colorrotationsnx[IDfound]; + else pcol = colorrotationsn[IDfound]; *norot = 0xffff; for (uint32_t ti = 0; ti < MAX_COLOR_ROTATIONN; ti++) { @@ -1229,7 +1297,7 @@ void Colorize_Framev2(uint8_t* frame, uint32_t IDfound) mySerum.flags |= FLAG_RETURNED_32P_FRAME_OK; prot = mySerum.rotationsinframe32; mySerum.width32 = fwidth; - prt = &colorrotationsn[IDfound * MAX_COLOR_ROTATIONN * MAX_LENGTH_COLOR_ROTATION]; + prt = colorrotationsn[IDfound]; cshft = colorshifts32; } else @@ -1238,7 +1306,7 @@ void Colorize_Framev2(uint8_t* frame, uint32_t IDfound) mySerum.flags |= FLAG_RETURNED_64P_FRAME_OK; prot = mySerum.rotationsinframe64; mySerum.width64 = fwidth; - prt = &colorrotationsn[IDfound * MAX_COLOR_ROTATIONN * MAX_LENGTH_COLOR_ROTATION]; + prt = colorrotationsn[IDfound]; cshft = colorshifts64; } memset(isdynapix, 0, fheight * fwidth); @@ -1292,7 +1360,7 @@ void Colorize_Framev2(uint8_t* frame, uint32_t IDfound) mySerum.flags |= FLAG_RETURNED_32P_FRAME_OK; prot = mySerum.rotationsinframe32; mySerum.width32 = fwidthx; - prt = &colorrotationsnx[IDfound * MAX_COLOR_ROTATIONN * MAX_LENGTH_COLOR_ROTATION]; + prt = colorrotationsnx[IDfound]; cshft = colorshifts32; } else @@ -1301,7 +1369,7 @@ void Colorize_Framev2(uint8_t* frame, uint32_t IDfound) mySerum.flags |= FLAG_RETURNED_64P_FRAME_OK; prot = mySerum.rotationsinframe64; mySerum.width64 = fwidthx; - prt = &colorrotationsnx[IDfound * MAX_COLOR_ROTATIONN * MAX_LENGTH_COLOR_ROTATION]; + prt = colorrotationsnx[IDfound]; cshft = colorshifts64; } memset(isdynapix, 0, fheightx * fwidthx); @@ -1381,14 +1449,14 @@ void Colorize_Spritev2(uint8_t nosprite, uint16_t frx, uint16_t fry, uint16_t sp { pfr = mySerum.frame32; prot = mySerum.rotationsinframe32; - prt = &colorrotationsn[IDfound * MAX_COLOR_ROTATIONN * MAX_LENGTH_COLOR_ROTATION]; + prt = colorrotationsn[IDfound]; cshft = colorshifts32; } else { pfr = mySerum.frame64; prot = mySerum.rotationsinframe64; - prt = &colorrotationsn[IDfound * MAX_COLOR_ROTATIONN * MAX_LENGTH_COLOR_ROTATION]; + prt = colorrotationsn[IDfound]; cshft = colorshifts64; } for (uint16_t tj = 0; tj < hei; tj++) @@ -1418,7 +1486,7 @@ void Colorize_Spritev2(uint8_t nosprite, uint16_t frx, uint16_t fry, uint16_t sp tfry = fry / 2; tspx = spx / 2; tspy = spy / 2; - prt = &colorrotationsnx[IDfound * MAX_COLOR_ROTATIONN * MAX_LENGTH_COLOR_ROTATION]; + prt = colorrotationsnx[IDfound]; cshft = colorshifts32; } else @@ -1431,7 +1499,7 @@ void Colorize_Spritev2(uint8_t nosprite, uint16_t frx, uint16_t fry, uint16_t sp tfry = fry * 2; tspx = spx * 2; tspy = spy * 2; - prt = &colorrotationsnx[IDfound * MAX_COLOR_ROTATIONN * MAX_LENGTH_COLOR_ROTATION]; + prt = colorrotationsnx[IDfound]; cshft = colorshifts64; } for (uint16_t tj = 0; tj < thei; tj++) @@ -1481,7 +1549,7 @@ uint32_t Serum_ColorizeWithMetadatav1(uint8_t* frame) { // return IDENTIFY_NO_FRAME if no new frame detected // return 0 if new frame with no rotation detected - // return > 0 if new frame with rotations detected, the value is the delay before the first rotation in ms + // return > 0 if new frame with rotations detected, the value is the delay before the first rotation in ms mySerum.triggerID = 0xffffffff; if (!enabled) @@ -1572,7 +1640,7 @@ SERUM_API uint32_t Serum_ColorizeWithMetadatav2(uint8_t* frame) { // return IDENTIFY_NO_FRAME if no new frame detected // return 0 if new frame with no rotation detected - // return > 0 if new frame with rotations detected, the value is the delay before the first rotation in ms + // return > 0 if new frame with rotations detected, the value is the delay before the first rotation in ms mySerum.triggerID = 0xffffffff; // Let's first identify the incoming frame among the ones we have in the crom @@ -1611,18 +1679,18 @@ SERUM_API uint32_t Serum_ColorizeWithMetadatav2(uint8_t* frame) uint16_t* pcr32, * pcr64; if (fheight == 32) { - pcr32 = colorrotationsn; - pcr64 = colorrotationsnx; + pcr32 = colorrotationsn[lastfound]; + pcr64 = colorrotationsnx[lastfound]; } else { - pcr32 = colorrotationsnx; - pcr64 = colorrotationsn; + pcr32 = colorrotationsnx[lastfound]; + pcr64 = colorrotationsn[lastfound]; } uint32_t now = lastframe_found; if (mySerum.frame32) { - memcpy(mySerum.rotations32, &pcr32[lastfound * MAX_LENGTH_COLOR_ROTATION * MAX_COLOR_ROTATIONN], MAX_COLOR_ROTATIONN * MAX_LENGTH_COLOR_ROTATION * 2); + memcpy(mySerum.rotations32, pcr32, MAX_COLOR_ROTATIONN * MAX_LENGTH_COLOR_ROTATION * 2); //memcpy(lastrotations32, mySerum.rotations32, MAX_COLOR_ROTATIONN * MAX_LENGTH_COLOR_ROTATION * 2); for (uint32_t ti = 0; ti < MAX_COLOR_ROTATIONN; ti++) { @@ -1646,7 +1714,7 @@ SERUM_API uint32_t Serum_ColorizeWithMetadatav2(uint8_t* frame) } if (mySerum.frame64) { - memcpy(mySerum.rotations64, &pcr64[lastfound * MAX_LENGTH_COLOR_ROTATION * MAX_COLOR_ROTATIONN], MAX_COLOR_ROTATIONN * MAX_LENGTH_COLOR_ROTATION * 2); + memcpy(mySerum.rotations64, pcr64, MAX_COLOR_ROTATIONN * MAX_LENGTH_COLOR_ROTATION * 2); //memcpy(lastrotations64, mySerum.rotations64, MAX_COLOR_ROTATIONN * MAX_LENGTH_COLOR_ROTATION * 2); for (uint32_t ti = 0; ti < MAX_COLOR_ROTATIONN; ti++) { @@ -1672,7 +1740,7 @@ SERUM_API uint32_t Serum_ColorizeWithMetadatav2(uint8_t* frame) return (uint32_t)mySerum.rotationtimer; // new frame, return true } } - + return IDENTIFY_NO_FRAME; // no new frame, client has to update rotations! } @@ -1680,7 +1748,7 @@ SERUM_API uint32_t Serum_Colorize(uint8_t* frame) { // return IDENTIFY_NO_FRAME if no new frame detected // return 0 if new frame with no rotation detected - // return > 0 if new frame with rotations detected, the value is the delay before the first rotation in ms + // return > 0 if new frame with rotations detected, the value is the delay before the first rotation in ms if (SerumVersion == SERUM_V2) return Serum_ColorizeWithMetadatav2(frame); else return Serum_ColorizeWithMetadatav1(frame); } From b4eed38146562728b352b3c18eb688a5a16f02bb Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Sat, 19 Apr 2025 00:21:17 +0200 Subject: [PATCH 02/12] fixed ac_pos_in_file --- src/serum-decode.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/serum-decode.cpp b/src/serum-decode.cpp index b642bc6..d051dad 100644 --- a/src/serum-decode.cpp +++ b/src/serum-decode.cpp @@ -57,6 +57,8 @@ const uint32_t IDENTIFY_SAME_FRAME = 0xfffffffe; uint8_t* zeroBufferByte; uint16_t* zeroBufferWord; +long long ac_pos_in_file; + class SparseVectorByte { protected: std::unordered_map> data; // Only stores non-zero data @@ -463,7 +465,6 @@ uint32_t min(uint32_t v1, uint32_t v2) } long serum_file_length; -long long ac_pos_in_file; FILE* fconsole; const bool IS_DEBUG_READ = false; From 49b0b4d060c8112242400b770fa6585cd2a8db94 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Sat, 19 Apr 2025 12:27:11 +0200 Subject: [PATCH 03/12] fixed formatting --- src/serum-decode.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/serum-decode.cpp b/src/serum-decode.cpp index d051dad..daf85a8 100644 --- a/src/serum-decode.cpp +++ b/src/serum-decode.cpp @@ -78,7 +78,7 @@ class SparseVectorByte { size_t readelem = fread(tmp, sizeElement, 1, stream); ac_pos_in_file += readelem * sizeElement; if (memcmp(tmp, zeroBufferByte, sizeElement) != 0) data[i].assign(tmp, tmp + sizeElement); - } + } free(tmp); } @@ -108,7 +108,7 @@ class SparseVectorWord { size_t readelem = fread(tmp, sizeElement, 1, stream); ac_pos_in_file += readelem * sizeElement; if (memcmp(tmp, zeroBufferWord, sizeElement) != 0) data[i].assign(tmp, tmp + sizeElement); - } + } free(tmp); } From 74cc11c76881730e4def42052bddf4c272c87c6d Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Sat, 19 Apr 2025 13:34:22 +0200 Subject: [PATCH 04/12] simplified code and usage --- src/serum-decode.cpp | 86 +++++++++++++++++--------------------------- 1 file changed, 32 insertions(+), 54 deletions(-) diff --git a/src/serum-decode.cpp b/src/serum-decode.cpp index daf85a8..5a2f1f7 100644 --- a/src/serum-decode.cpp +++ b/src/serum-decode.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include "serum-version.h" @@ -54,67 +55,50 @@ const int pathbuflen = 4096; const uint32_t MAX_NUMBER_FRAMES = 0x7fffffff; const uint32_t IDENTIFY_SAME_FRAME = 0xfffffffe; -uint8_t* zeroBufferByte; -uint16_t* zeroBufferWord; - long long ac_pos_in_file; -class SparseVectorByte { +template +class SparseVector { + static_assert(std::is_trivial::value && std::is_standard_layout::value, + "SparseVector only supports trivial types like uint8_t or uint16_t"); + protected: - std::unordered_map> data; // Only stores non-zero data + std::unordered_map> data; + std::vector zeroBuffer; + public: // Access data for a frame (returns pointer to zeros if not found) - uint8_t* operator[](const uint32_t frame) { + T* operator[](const uint32_t frame) { auto it = data.find(frame); - if (it != data.end()) return it->second.data(); // Existing frame data - return zeroBufferByte; // Default zeros + if (it != data.end()) return it->second.data(); + return zeroBuffer.data(); } // Load data (only store if non-zero) - void my_fread(size_t sizeElement, uint32_t nframes, FILE* stream) - { - uint8_t* tmp = (uint8_t*)malloc(sizeElement); - for(uint32_t i = 0; i < nframes; ++i) { - size_t readelem = fread(tmp, sizeElement, 1, stream); - ac_pos_in_file += readelem * sizeElement; - if (memcmp(tmp, zeroBufferByte, sizeElement) != 0) data[i].assign(tmp, tmp + sizeElement); - } - free(tmp); - } + void my_fread(size_t elementCount, uint32_t nframes, FILE* stream) { + size_t blockSize = elementCount * sizeof(T); - // Clear all stored frames (free memory) - void clear() { - data.clear(); // Vectors auto-free their memory - } -}; + // Ensure zeroBuffer is large enough + if (zeroBuffer.size() < elementCount) + zeroBuffer.resize(elementCount, static_cast(0)); + std::vector tmp(elementCount); -class SparseVectorWord { - protected: - std::unordered_map> data; // Only stores non-zero data - public: - // Access data for a frame (returns pointer to zeros if not found) - uint16_t* operator[](const uint32_t frame) { - auto it = data.find(frame); - if (it != data.end()) return it->second.data(); // Existing frame data - return zeroBufferWord; // Default zeros - } + for (uint32_t i = 0; i < nframes; ++i) { + if (1 != fread(tmp.data(), blockSize, 1, stream)) { + // Error reading file + exit(1); + } + ac_pos_in_file += blockSize; - // Load data (only store if non-zero) - void my_fread(size_t sizeElement, uint32_t nframes, FILE* stream) - { - uint8_t* tmp = (uint8_t*)malloc(sizeElement); - for(uint32_t i = 0; i < nframes; ++i) { - size_t readelem = fread(tmp, sizeElement, 1, stream); - ac_pos_in_file += readelem * sizeElement; - if (memcmp(tmp, zeroBufferWord, sizeElement) != 0) data[i].assign(tmp, tmp + sizeElement); + if (memcmp(tmp.data(), zeroBuffer.data(), blockSize) != 0) + data[i] = tmp; } - free(tmp); } - // Clear all stored frames (free memory) + // Clear all stored frames void clear() { - data.clear(); // Vectors auto-free their memory + data.clear(); } }; @@ -155,8 +139,8 @@ uint16_t* spritecolored = NULL; uint16_t* spritecoloredx = NULL; uint8_t* activeframes = NULL; uint8_t* colorrotations = NULL; -SparseVectorWord colorrotationsn; -SparseVectorWord colorrotationsnx; +SparseVector colorrotationsn; +SparseVector colorrotationsnx; uint16_t* spritedetareas = NULL; uint32_t* spritedetdwords = NULL; uint16_t* spritedetdwordpos = NULL; @@ -304,9 +288,6 @@ void Serum_free(void) Free_element((void**)&mySerum.modifiedelements32); Free_element((void**)&mySerum.modifiedelements64); - Free_element((void**)&zeroBufferByte); - Free_element((void**)&zeroBufferWord); - cromloaded = false; } @@ -528,9 +509,6 @@ Serum_Frame_Struc* Serum_LoadFilev2(FILE* pfile, const uint8_t flags, bool uncom my_fread(&nsprites, 4, 1, pfile); my_fread(&nbackgrounds, 2, 1, pfile); // nbackgrounds is a uint16_t - zeroBufferByte = (uint8_t*)malloc(nframes * fwidthx * fheightx * sizeof(uint8_t)); - zeroBufferWord = (uint16_t*)malloc(nframes * fwidthx * fheightx * sizeof(uint16_t)); - hashcodes = (uint32_t*)malloc(sizeof(uint32_t) * nframes); shapecompmode = (uint8_t*)malloc(nframes); compmaskID = (uint8_t*)malloc(nframes); @@ -637,8 +615,8 @@ Serum_Frame_Struc* Serum_LoadFilev2(FILE* pfile, const uint8_t flags, bool uncom my_fread(spritemaskx, 1, nsprites * MAX_SPRITE_WIDTH * MAX_SPRITE_HEIGHT, pfile); my_fread(spritecoloredx, 2, nsprites * MAX_SPRITE_WIDTH * MAX_SPRITE_HEIGHT, pfile); my_fread(activeframes, 1, nframes, pfile); - colorrotationsn.my_fread(2 * MAX_LENGTH_COLOR_ROTATION * MAX_COLOR_ROTATIONN, nframes, pfile); - colorrotationsnx.my_fread(2 * MAX_LENGTH_COLOR_ROTATION * MAX_COLOR_ROTATIONN, nframes, pfile); + colorrotationsn.my_fread(MAX_LENGTH_COLOR_ROTATION * MAX_COLOR_ROTATIONN, nframes, pfile); + colorrotationsnx.my_fread(MAX_LENGTH_COLOR_ROTATION * MAX_COLOR_ROTATIONN, nframes, pfile); my_fread(spritedetdwords, 4, nsprites * MAX_SPRITE_DETECT_AREAS, pfile); my_fread(spritedetdwordpos, 2, nsprites * MAX_SPRITE_DETECT_AREAS, pfile); my_fread(spritedetareas, 2, nsprites * 4 * MAX_SPRITE_DETECT_AREAS, pfile); From cd62677ffc55836c1ea329f954709453ff9f27a7 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Sat, 19 Apr 2025 20:06:04 +0200 Subject: [PATCH 05/12] handle dynamasks, framesprites, framespriteBB, backgroundmask --- src/serum-decode.cpp | 134 +++++++++++++++++++++---------------------- 1 file changed, 67 insertions(+), 67 deletions(-) diff --git a/src/serum-decode.cpp b/src/serum-decode.cpp index 5a2f1f7..c41a0dd 100644 --- a/src/serum-decode.cpp +++ b/src/serum-decode.cpp @@ -55,8 +55,6 @@ const int pathbuflen = 4096; const uint32_t MAX_NUMBER_FRAMES = 0x7fffffff; const uint32_t IDENTIFY_SAME_FRAME = 0xfffffffe; -long long ac_pos_in_file; - template class SparseVector { static_assert(std::is_trivial::value && std::is_standard_layout::value, @@ -64,38 +62,50 @@ class SparseVector { protected: std::unordered_map> data; - std::vector zeroBuffer; + std::vector noData; public: + SparseVector(T noDataSignature) { + noData(1, noDataSignature); + } + // Access data for a frame (returns pointer to zeros if not found) T* operator[](const uint32_t frame) { auto it = data.find(frame); if (it != data.end()) return it->second.data(); - return zeroBuffer.data(); + return noData.data(); } // Load data (only store if non-zero) void my_fread(size_t elementCount, uint32_t nframes, FILE* stream) { size_t blockSize = elementCount * sizeof(T); - // Ensure zeroBuffer is large enough - if (zeroBuffer.size() < elementCount) - zeroBuffer.resize(elementCount, static_cast(0)); + if (noData.size() < elementCount) noData.resize(elementCount, noData[0]); - std::vector tmp(elementCount); + std::vector tmp(elementCount); for (uint32_t i = 0; i < nframes; ++i) { if (1 != fread(tmp.data(), blockSize, 1, stream)) { // Error reading file exit(1); } - ac_pos_in_file += blockSize; - if (memcmp(tmp.data(), zeroBuffer.data(), blockSize) != 0) + if (memcmp(tmp.data(), noData.data(), noData.size() * sizeof(T) * ) != 0) data[i] = tmp; } } + void set(uint32_t frame, const T* values, size_t elementCount) { + auto it = data.find(frame); + if (it != data.end()) { + it->second.resize(elementCount); + memcpy(it->second.data(), values, elementCount * sizeof(T)); + } else { + std::vector tmp(values, values + elementCount); + data[frame] = tmp; + } + } + // Clear all stored frames void clear() { data.clear(); @@ -124,12 +134,12 @@ uint8_t* isextraframe = NULL; uint8_t* cframes = NULL; uint16_t* cframesn = NULL; uint16_t* cframesnx = NULL; -uint8_t* dynamasks = NULL; -uint8_t* dynamasksx = NULL; +SparseVector dynamasks(255); +SparseVector dynamasksx(255); uint8_t* dyna4cols = NULL; uint16_t* dyna4colsn = NULL; uint16_t* dyna4colsnx = NULL; -uint8_t* framesprites = NULL; +SparseVector framesprites(255); uint8_t* spritedescriptionso = NULL; uint8_t* spritedescriptionsc = NULL; uint8_t* isextrasprite = NULL; @@ -139,24 +149,24 @@ uint16_t* spritecolored = NULL; uint16_t* spritecoloredx = NULL; uint8_t* activeframes = NULL; uint8_t* colorrotations = NULL; -SparseVector colorrotationsn; -SparseVector colorrotationsnx; +SparseVector colorrotationsn(0); +SparseVector colorrotationsnx(0); uint16_t* spritedetareas = NULL; uint32_t* spritedetdwords = NULL; uint16_t* spritedetdwordpos = NULL; uint32_t* triggerIDs = NULL; -uint16_t* framespriteBB = NULL; +SparseVector framespriteBB(0); uint8_t* isextrabackground = NULL; uint8_t* backgroundframes = NULL; uint16_t* backgroundframesn = NULL; uint16_t* backgroundframesnx = NULL; uint16_t* backgroundIDs = NULL; uint16_t* backgroundBB = NULL; -uint8_t* backgroundmask = NULL; -uint8_t* backgroundmaskx = NULL; +SparseVector backgroundmask(0); +SparseVector backgroundmaskx(0); uint8_t* dynashadowsdiro = NULL; uint16_t* dynashadowscolo = NULL; -uint8_t* dynashadowsdirx = NULL; +uint8_t* dynashadowsdirx = NULL;q uint16_t* dynashadowscolx = NULL; // variables @@ -241,12 +251,12 @@ void Serum_free(void) Free_element((void**)&cframesn); Free_element((void**)&cframesnx); Free_element((void**)&cframes); - Free_element((void**)&dynamasks); - Free_element((void**)&dynamasksx); + dynamasks.clear(); + dynamasksx.clear(); Free_element((void**)&dyna4cols); Free_element((void**)&dyna4colsn); Free_element((void**)&dyna4colsnx); - Free_element((void**)&framesprites); + framesprites.clear(); Free_element((void**)&spritedescriptionso); Free_element((void**)&spritedescriptionsc); Free_element((void**)&isextrasprite); @@ -262,15 +272,15 @@ void Serum_free(void) Free_element((void**)&spritedetdwords); Free_element((void**)&spritedetdwordpos); Free_element((void**)&triggerIDs); - Free_element((void**)&framespriteBB); + framespriteBB.clear(); Free_element((void**)&isextrabackground); Free_element((void**)&backgroundframes); Free_element((void**)&backgroundframesn); Free_element((void**)&backgroundframesnx); Free_element((void**)&backgroundIDs); Free_element((void**)&backgroundBB); - Free_element((void**)&backgroundmask); - Free_element((void**)&backgroundmaskx); + backgroundmask.clear(); + backgroundmaskx.clear(); Free_element((void**)&dynashadowsdiro); Free_element((void**)&dynashadowscolo); Free_element((void**)&dynashadowsdirx); @@ -453,8 +463,7 @@ const bool IS_DEBUG_READ = false; size_t my_fread(void* pBuffer, size_t sizeElement, size_t nElements, FILE* stream) { size_t readelem = fread(pBuffer, sizeElement, nElements, stream); - ac_pos_in_file += readelem * sizeElement; - if (IS_DEBUG_READ) printf("sent elements: %llu / written elements: %llu / written bytes: %llu / current position: %llu\r", nElements, readelem, readelem * sizeElement, ac_pos_in_file); + if (IS_DEBUG_READ) printf("sent elements: %llu / written elements: %llu / written bytes: %llu\r", nElements, readelem, readelem * sizeElement); return readelem; } @@ -516,13 +525,9 @@ Serum_Frame_Struc* Serum_LoadFilev2(FILE* pfile, const uint8_t flags, bool uncom isextraframe = (uint8_t*)malloc(nframes); cframesn = (uint16_t*)malloc(nframes * fwidth * fheight * sizeof(uint16_t)); cframesnx = (uint16_t*)malloc(nframes * fwidthx * fheightx * sizeof(uint16_t)); - dynamasks = (uint8_t*)malloc(nframes * fwidth * fheight); - dynamasksx = (uint8_t*)malloc(nframes * fwidthx * fheightx); dyna4colsn = (uint16_t*)malloc(nframes * MAX_DYNA_SETS_PER_FRAMEN * nocolors * sizeof(uint16_t)); dyna4colsnx = (uint16_t*)malloc(nframes * MAX_DYNA_SETS_PER_FRAMEN * nocolors * sizeof(uint16_t)); isextrasprite = (uint8_t*)malloc(nsprites); - framesprites = (uint8_t*)malloc(nframes * MAX_SPRITES_PER_FRAME); - framespriteBB = (uint16_t*)malloc(nframes * MAX_SPRITES_PER_FRAME * 4 * sizeof(uint16_t)); spriteoriginal = (uint8_t*)malloc(nsprites * MAX_SPRITE_WIDTH * MAX_SPRITE_HEIGHT); spritecolored = (uint16_t*)malloc(nsprites * MAX_SPRITE_WIDTH * MAX_SPRITE_HEIGHT * sizeof(uint16_t)); spritemaskx = (uint8_t*)malloc(nsprites * MAX_SPRITE_WIDTH * MAX_SPRITE_HEIGHT); @@ -536,19 +541,17 @@ Serum_Frame_Struc* Serum_LoadFilev2(FILE* pfile, const uint8_t flags, bool uncom backgroundframesn = (uint16_t*)malloc(nbackgrounds * fwidth * fheight * sizeof(uint16_t)); backgroundframesnx = (uint16_t*)malloc(nbackgrounds * fwidthx * fheightx * sizeof(uint16_t)); backgroundIDs = (uint16_t*)malloc(nframes * sizeof(uint16_t)); - backgroundmask = (uint8_t*)malloc(nframes * fwidth * fheight); - backgroundmaskx = (uint8_t*)malloc(nframes * fwidthx * fheightx); dynashadowsdiro = (uint8_t*)malloc(nframes * MAX_DYNA_SETS_PER_FRAMEN); dynashadowscolo = (uint16_t*)malloc(nframes * MAX_DYNA_SETS_PER_FRAMEN * sizeof(uint16_t)); dynashadowsdirx = (uint8_t*)malloc(nframes * MAX_DYNA_SETS_PER_FRAMEN); dynashadowscolx = (uint16_t*)malloc(nframes * MAX_DYNA_SETS_PER_FRAMEN * sizeof(uint16_t)); if (!hashcodes || !shapecompmode || !compmaskID || (ncompmasks > 0 && !compmasks) || !isextraframe || - !cframesn || !cframesnx || !dynamasks || !dynamasksx || !dyna4colsn || !dyna4colsnx || + !cframesn || !cframesnx || !dyna4colsn || !dyna4colsnx || (nsprites > 0 && (!isextrasprite || !spriteoriginal || !spritecolored || !spritemaskx || !spritecoloredx || !spritedetdwords || !spritedetdwordpos || !spritedetareas)) || - !framesprites || !framespriteBB || !activeframes || + !activeframes || !triggerIDs || (nbackgrounds > 0 && (!isextrabackground || !backgroundframesn || - !backgroundframesnx)) || !backgroundIDs || !backgroundmask || !backgroundmaskx + !backgroundframesnx)) || !backgroundIDs || !dynashadowsdiro || !dynashadowscolo || !dynashadowsdirx || !dynashadowscolx) { Serum_free(); @@ -604,12 +607,12 @@ Serum_Frame_Struc* Serum_LoadFilev2(FILE* pfile, const uint8_t flags, bool uncom } my_fread(cframesn, 2, nframes * fwidth * fheight, pfile); my_fread(cframesnx, 2, nframes * fwidthx * fheightx, pfile); - my_fread(dynamasks, 1, nframes * fwidth * fheight, pfile); - my_fread(dynamasksx, 1, nframes * fwidthx * fheightx, pfile); + dynamasks.my_fread(fwidth * fheight, nframes, pfile); + dynamasksx.my_fread(fwidthx * fheightx, nframes, pfile); my_fread(dyna4colsn, 2, nframes * MAX_DYNA_SETS_PER_FRAMEN * nocolors, pfile); my_fread(dyna4colsnx, 2, nframes * MAX_DYNA_SETS_PER_FRAMEN * nocolors, pfile); my_fread(isextrasprite, 1, nsprites, pfile); - my_fread(framesprites, 1, nframes * MAX_SPRITES_PER_FRAME, pfile); + framesprites.my_fread(MAX_SPRITES_PER_FRAME, nframes, pfile); my_fread(spriteoriginal, 1, nsprites * MAX_SPRITE_WIDTH * MAX_SPRITE_HEIGHT, pfile); my_fread(spritecolored, 2, nsprites * MAX_SPRITE_WIDTH * MAX_SPRITE_HEIGHT, pfile); my_fread(spritemaskx, 1, nsprites * MAX_SPRITE_WIDTH * MAX_SPRITE_HEIGHT, pfile); @@ -621,13 +624,13 @@ Serum_Frame_Struc* Serum_LoadFilev2(FILE* pfile, const uint8_t flags, bool uncom my_fread(spritedetdwordpos, 2, nsprites * MAX_SPRITE_DETECT_AREAS, pfile); my_fread(spritedetareas, 2, nsprites * 4 * MAX_SPRITE_DETECT_AREAS, pfile); my_fread(triggerIDs, 4, nframes, pfile); - my_fread(framespriteBB, 2, nframes * MAX_SPRITES_PER_FRAME * 4, pfile); + framespriteBB.my_fread(MAX_SPRITES_PER_FRAME * 4, nframes, pfile); my_fread(isextrabackground, 1, nbackgrounds, pfile); my_fread(backgroundframesn, 2, nbackgrounds * fwidth * fheight, pfile); my_fread(backgroundframesnx, 2, nbackgrounds * fwidthx * fheightx, pfile); my_fread(backgroundIDs, 2, nframes, pfile); - my_fread(backgroundmask, 1, nframes * fwidth * fheight, pfile); - my_fread(backgroundmaskx, 1, nframes * fwidthx * fheightx, pfile); + backgroundmask.my_fread(fwidth * fheight, nframes, pfile); + backgroundmaskx.my_fread(fwidthx * fheightx, nframes, pfile); memset(dynashadowsdiro, 0, nframes * MAX_DYNA_SETS_PER_FRAMEN); memset(dynashadowscolo, 0, nframes * MAX_DYNA_SETS_PER_FRAMEN * 2); memset(dynashadowsdirx, 0, nframes * MAX_DYNA_SETS_PER_FRAMEN); @@ -686,7 +689,6 @@ Serum_Frame_Struc* Serum_LoadFilev2(FILE* pfile, const uint8_t flags, bool uncom Serum_Frame_Struc* Serum_LoadFilev1(const char* const filename, const uint8_t flags) { char pathbuf[pathbuflen]; - ac_pos_in_file = 0; if (!crc32_ready) CRC32encode(); // check if we're using an uncompressed cROM file @@ -775,10 +777,7 @@ Serum_Frame_Struc* Serum_LoadFilev1(const char* const filename, const uint8_t fl movrcts = (uint8_t*)malloc(nmovmasks * 4); cpal = (uint8_t*)malloc(nframes * 3 * nccolors); cframes = (uint8_t*)malloc(nframes * fwidth * fheight); - dynamasks = (uint8_t*)malloc(nframes * fwidth * fheight); dyna4cols = (uint8_t*)malloc(nframes * MAX_DYNA_4COLS_PER_FRAME * nocolors); - framesprites = (uint8_t*)malloc(nframes * MAX_SPRITES_PER_FRAME); - framespriteBB = (uint16_t*)malloc(nframes * MAX_SPRITES_PER_FRAME * 4 * sizeof(uint16_t)); spritedescriptionso = (uint8_t*)malloc(nsprites * MAX_SPRITE_SIZE * MAX_SPRITE_SIZE); spritedescriptionsc = (uint8_t*)malloc(nsprites * MAX_SPRITE_SIZE * MAX_SPRITE_SIZE); activeframes = (uint8_t*)malloc(nframes); @@ -794,7 +793,7 @@ Serum_Frame_Struc* Serum_LoadFilev1(const char* const filename, const uint8_t fl mySerum.palette = (uint8_t*)malloc(3 * 64); mySerum.rotations = (uint8_t*)malloc(MAX_COLOR_ROTATIONS * 3); if (!hashcodes || !shapecompmode || !compmaskID || !movrctID || !cpal || - !cframes || !dynamasks || !dyna4cols || !framesprites || !framespriteBB || + !cframes || !dyna4cols || !activeframes || !colorrotations || !triggerIDs || (!compmasks && ncompmasks > 0) || (!movrcts && nmovmasks > 0) || ((nsprites > 0) && (!spritedescriptionso || !spritedescriptionsc || !spritedetdwords || @@ -816,9 +815,9 @@ Serum_Frame_Struc* Serum_LoadFilev1(const char* const filename, const uint8_t fl my_fread(movrcts, 1, nmovmasks * fwidth * fheight, pfile); my_fread(cpal, 1, nframes * 3 * nccolors, pfile); my_fread(cframes, 1, nframes * fwidth * fheight, pfile); - my_fread(dynamasks, 1, nframes * fwidth * fheight, pfile); + dynamasks.my_fread(fwidth * fheight, nframes, pfile); my_fread(dyna4cols, 1, nframes * MAX_DYNA_4COLS_PER_FRAME * nocolors, pfile); - my_fread(framesprites, 1, nframes * MAX_SPRITES_PER_FRAME, pfile); + framesprites.my_fread(MAX_SPRITES_PER_FRAME, nframes, pfile); for (int ti = 0; ti < (int)nsprites * MAX_SPRITE_SIZE * MAX_SPRITE_SIZE; ti++) { my_fread(&spritedescriptionsc[ti], 1, 1, pfile); @@ -839,19 +838,20 @@ Serum_Frame_Struc* Serum_LoadFilev1(const char* const filename, const uint8_t fl } } else memset(triggerIDs, 0xFF, sizeof(uint32_t) * nframes); - if (sizeheader >= 12 * sizeof(uint32_t)) my_fread(framespriteBB, sizeof(uint16_t), nframes * MAX_SPRITES_PER_FRAME * 4, pfile); + if (sizeheader >= 12 * sizeof(uint32_t)) framespriteBB.my_fread(MAX_SPRITES_PER_FRAME * 4, nframes, pfile); else { for (uint32_t tj = 0; tj < nframes; tj++) { + uint16_t tmp_framespriteBB[4 * MAX_SPRITES_PER_FRAME]; for (uint32_t ti = 0; ti < MAX_SPRITES_PER_FRAME; ti++) { - framespriteBB[tj * MAX_SPRITES_PER_FRAME * 4 + ti * 4] = 0; - framespriteBB[tj * MAX_SPRITES_PER_FRAME * 4 + ti * 4 + 1] = 0; - framespriteBB[tj * MAX_SPRITES_PER_FRAME * 4 + ti * 4 + 2] = fwidth - 1; - framespriteBB[tj * MAX_SPRITES_PER_FRAME * 4 + ti * 4 + 3] = - fheight - 1; + tmp_framespriteBB[ti * 4] = 0; + tmp_framespriteBB[ti * 4 + 1] = 0; + tmp_framespriteBB[ti * 4 + 2] = fwidth - 1; + tmp_framespriteBB[ti * 4 + 3] = fheight - 1; } + framespriteBB.set(tj, tmp_framespriteBB, MAX_SPRITES_PER_FRAME * 4); } } if (sizeheader >= 13 * sizeof(uint32_t)) @@ -1033,15 +1033,15 @@ bool Check_Sprites(uint8_t* Frame, uint32_t quelleframe, uint8_t* pquelsprites, spr_height = MAX_SPRITE_SIZE; pspro = spritedescriptionso; } - while ((ti < MAX_SPRITES_PER_FRAME) && (framesprites[quelleframe * MAX_SPRITES_PER_FRAME + ti] < 255)) + while ((ti < MAX_SPRITES_PER_FRAME) && (framesprites[quelleframe][ti] < 255)) { - uint8_t qspr = framesprites[quelleframe * MAX_SPRITES_PER_FRAME + ti]; + uint8_t qspr = framesprites[quelleframe][ti]; int spw, sph; GetSpriteSize(qspr, &spw, &sph, pspro, spr_width, spr_height); - short minxBB = (short)framespriteBB[(quelleframe * MAX_SPRITES_PER_FRAME + ti) * 4]; - short minyBB = (short)framespriteBB[(quelleframe * MAX_SPRITES_PER_FRAME + ti) * 4 + 1]; - short maxxBB = (short)framespriteBB[(quelleframe * MAX_SPRITES_PER_FRAME + ti) * 4 + 2]; - short maxyBB = (short)framespriteBB[(quelleframe * MAX_SPRITES_PER_FRAME + ti) * 4 + 3]; + short minxBB = (short)framespriteBB[quelleframe][ti * 4]; + short minyBB = (short)framespriteBB[quelleframe][ti * 4 + 1]; + short maxxBB = (short)framespriteBB[quelleframe][ti * 4 + 2]; + short maxyBB = (short)framespriteBB[quelleframe][ti * 4 + 3]; for (uint32_t tm = 0; tm < MAX_SPRITE_DETECT_AREAS; tm++) { if (spritedetareas[qspr * MAX_SPRITE_DETECT_AREAS * 4 + tm * 4] == 0xffff) continue; @@ -1160,7 +1160,7 @@ void Colorize_Framev1(uint8_t* frame, uint32_t IDfound) mySerum.frame[tk] = backgroundframes[backgroundIDs[IDfound] * fwidth * fheight + tk]; else { - uint8_t dynacouche = dynamasks[IDfound * fwidth * fheight + tk]; + uint8_t dynacouche = dynamasks[IDfound][tk]; if (dynacouche == 255) mySerum.frame[tk] = cframes[IDfound * fwidth * fheight + tk]; else mySerum.frame[tk] = dyna4cols[IDfound * MAX_DYNA_4COLS_PER_FRAME * nocolors + dynacouche * nocolors + frame[tk]]; } @@ -1176,7 +1176,7 @@ bool CheckExtraFrameAvailable(uint32_t frID) if (backgroundIDs[frID] < 0xffff && isextrabackground[backgroundIDs[frID]] == 0) return false; for (uint32_t ti = 0; ti < MAX_SPRITES_PER_FRAME; ti++) { - if (framesprites[frID * MAX_SPRITES_PER_FRAME + ti] < 255 && isextrasprite[framesprites[frID * MAX_SPRITES_PER_FRAME + ti]] == 0) return false; + if (framesprites[frID][ti] < 255 && isextrasprite[framesprites[frID][ti]] == 0) return false; } return true; } @@ -1294,7 +1294,7 @@ void Colorize_Framev2(uint8_t* frame, uint32_t IDfound) for (ti = 0; ti < fwidth; ti++) { uint16_t tk = tj * fwidth + ti; - if ((backgroundIDs[IDfound] < nbackgrounds) && (frame[tk] == 0) && (backgroundmask[IDfound * fwidth * fheight + tk] > 0)) + if ((backgroundIDs[IDfound] < nbackgrounds) && (frame[tk] == 0) && (backgroundmask[IDfound][tk] > 0)) { if (isdynapix[tk] == 0) { @@ -1305,7 +1305,7 @@ void Colorize_Framev2(uint8_t* frame, uint32_t IDfound) } else { - uint8_t dynacouche = dynamasks[IDfound * fwidth * fheight + tk]; + uint8_t dynacouche = dynamasks[IDfound][tk]; if (dynacouche == 255) { if (isdynapix[tk] == 0) @@ -1361,7 +1361,7 @@ void Colorize_Framev2(uint8_t* frame, uint32_t IDfound) if (fheightx == 64) tl = tj / 2 * fwidth + ti / 2; else tl = tj * 2 * fwidth + ti * 2; - if ((backgroundIDs[IDfound] < nbackgrounds) && (frame[tl] == 0) && (backgroundmaskx[IDfound * fwidthx * fheightx + tk] > 0)) + if ((backgroundIDs[IDfound] < nbackgrounds) && (frame[tl] == 0) && (backgroundmaskx[IDfound][tk] > 0)) { if (isdynapix[tk] == 0) { @@ -1374,7 +1374,7 @@ void Colorize_Framev2(uint8_t* frame, uint32_t IDfound) } else { - uint8_t dynacouche = dynamasksx[IDfound * fwidthx * fheightx + tk]; + uint8_t dynacouche = dynamasksx[IDfound][tk]; if (dynacouche == 255) { if (isdynapix[tk] == 0) From 85b3aa51416c7e7434bb0db5c3883a57e69ea122 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Sat, 19 Apr 2025 20:27:58 +0200 Subject: [PATCH 06/12] fixed some compile errors --- src/serum-decode.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/serum-decode.cpp b/src/serum-decode.cpp index c41a0dd..fa5a5fb 100644 --- a/src/serum-decode.cpp +++ b/src/serum-decode.cpp @@ -66,7 +66,7 @@ class SparseVector { public: SparseVector(T noDataSignature) { - noData(1, noDataSignature); + noData.resize(1, noDataSignature); } // Access data for a frame (returns pointer to zeros if not found) @@ -90,7 +90,7 @@ class SparseVector { exit(1); } - if (memcmp(tmp.data(), noData.data(), noData.size() * sizeof(T) * ) != 0) + if (memcmp(tmp.data(), noData.data(), noData.size() * sizeof(T)) != 0) data[i] = tmp; } } @@ -166,7 +166,7 @@ SparseVector backgroundmask(0); SparseVector backgroundmaskx(0); uint8_t* dynashadowsdiro = NULL; uint16_t* dynashadowscolo = NULL; -uint8_t* dynashadowsdirx = NULL;q +uint8_t* dynashadowsdirx = NULL; uint16_t* dynashadowscolx = NULL; // variables From 1d3802332b8b760074a4698e3f7a0aadcbfbe3bd Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Sun, 20 Apr 2025 23:37:30 +0200 Subject: [PATCH 07/12] moced sparsevector to a header file --- src/serum-decode.cpp | 61 +--------------------------------------- src/sparse-vector.h | 67 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 60 deletions(-) create mode 100644 src/sparse-vector.h diff --git a/src/serum-decode.cpp b/src/serum-decode.cpp index fa5a5fb..2e73863 100644 --- a/src/serum-decode.cpp +++ b/src/serum-decode.cpp @@ -6,15 +6,13 @@ #include #include #include -#include -#include #include #include #include #include -#include #include "serum-version.h" +#include "sparse-vector.h" #if defined(__APPLE__) #include @@ -55,63 +53,6 @@ const int pathbuflen = 4096; const uint32_t MAX_NUMBER_FRAMES = 0x7fffffff; const uint32_t IDENTIFY_SAME_FRAME = 0xfffffffe; -template -class SparseVector { - static_assert(std::is_trivial::value && std::is_standard_layout::value, - "SparseVector only supports trivial types like uint8_t or uint16_t"); - - protected: - std::unordered_map> data; - std::vector noData; - - public: - SparseVector(T noDataSignature) { - noData.resize(1, noDataSignature); - } - - // Access data for a frame (returns pointer to zeros if not found) - T* operator[](const uint32_t frame) { - auto it = data.find(frame); - if (it != data.end()) return it->second.data(); - return noData.data(); - } - - // Load data (only store if non-zero) - void my_fread(size_t elementCount, uint32_t nframes, FILE* stream) { - size_t blockSize = elementCount * sizeof(T); - - if (noData.size() < elementCount) noData.resize(elementCount, noData[0]); - - std::vector tmp(elementCount); - - for (uint32_t i = 0; i < nframes; ++i) { - if (1 != fread(tmp.data(), blockSize, 1, stream)) { - // Error reading file - exit(1); - } - - if (memcmp(tmp.data(), noData.data(), noData.size() * sizeof(T)) != 0) - data[i] = tmp; - } - } - - void set(uint32_t frame, const T* values, size_t elementCount) { - auto it = data.find(frame); - if (it != data.end()) { - it->second.resize(elementCount); - memcpy(it->second.data(), values, elementCount * sizeof(T)); - } else { - std::vector tmp(values, values + elementCount); - data[frame] = tmp; - } - } - - // Clear all stored frames - void clear() { - data.clear(); - } -}; - // header char rname[64]; uint8_t SerumVersion = 0; diff --git a/src/sparse-vector.h b/src/sparse-vector.h new file mode 100644 index 0000000..b537243 --- /dev/null +++ b/src/sparse-vector.h @@ -0,0 +1,67 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +template +class SparseVector +{ + static_assert(std::is_trivial::value && std::is_standard_layout::value, + "SparseVector only supports trivial types like uint8_t or uint16_t"); + + protected: + std::unordered_map> data; + std::vector noData; + + public: + SparseVector(T noDataSignature) { + noData.resize(1, noDataSignature); + } + + // Access data for a frame (returns pointer to noData if not found) + T* operator[](const uint32_t frame) { + auto it = data.find(frame); + if (it != data.end()) return it->second.data(); + return noData.data(); + } + + // Load data (only store if not matching the noData signature) + void my_fread(size_t elementCount, uint32_t nframes, FILE* stream) { + size_t blockSize = elementCount * sizeof(T); + + if (noData.size() < elementCount) noData.resize(elementCount, noData[0]); + + std::vector tmp(elementCount); + + for (uint32_t i = 0; i < nframes; ++i) { + if (1 != fread(tmp.data(), blockSize, 1, stream)) { + // Error reading file + exit(1); + } + + if (memcmp(tmp.data(), noData.data(), noData.size() * sizeof(T)) != 0) + data[i] = tmp; + } + } + + void set(uint32_t frame, const T* values, size_t elementCount) { + auto it = data.find(frame); + if (it != data.end()) { + it->second.resize(elementCount); + memcpy(it->second.data(), values, elementCount * sizeof(T)); + } else { + std::vector tmp(values, values + elementCount); + data[frame] = tmp; + } + } + + // Clear all stored frames + void clear() { + data.clear(); + } +}; From 1ea1f34ff5b155ec1a74e5bac76f79035012ceb6 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Sun, 20 Apr 2025 23:48:00 +0200 Subject: [PATCH 08/12] formatting --- src/serum-decode.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/serum-decode.cpp b/src/serum-decode.cpp index 2e73863..edd5cd5 100644 --- a/src/serum-decode.cpp +++ b/src/serum-decode.cpp @@ -6,6 +6,7 @@ #include #include #include + #include #include #include From d6d25753793c46c738ecd8a32ba6c5b280772a4b Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Sun, 20 Apr 2025 23:56:09 +0200 Subject: [PATCH 09/12] formatting --- src/serum-decode.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/serum-decode.cpp b/src/serum-decode.cpp index edd5cd5..f5e4dc5 100644 --- a/src/serum-decode.cpp +++ b/src/serum-decode.cpp @@ -239,7 +239,6 @@ void Serum_free(void) Free_element((void**)&mySerum.rotationsinframe64); Free_element((void**)&mySerum.modifiedelements32); Free_element((void**)&mySerum.modifiedelements64); - cromloaded = false; } From 238299000d471788d048860b077ec955fa98c9be Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Mon, 21 Apr 2025 00:01:32 +0200 Subject: [PATCH 10/12] formatting --- src/serum-decode.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/serum-decode.cpp b/src/serum-decode.cpp index f5e4dc5..b82823e 100644 --- a/src/serum-decode.cpp +++ b/src/serum-decode.cpp @@ -142,7 +142,7 @@ bool enabled = true; // is colorization enabled? bool isoriginalrequested = true; // are the original resolution frames requested by the caller bool isextrarequested = false; // are the extra resolution frames requested by the caller -uint32_t rotationnextabsolutetime[MAX_COLOR_ROTATIONS]; // cumulative time for the next rotation for each color rotation +uint32_t rotationnextabsolutetime[MAX_COLOR_ROTATIONS]; // cumulative time for the next rotation for each color rotation Serum_Frame_Struc mySerum; // structure to keep communicate colorization data @@ -1469,7 +1469,7 @@ uint32_t Serum_ColorizeWithMetadatav1(uint8_t* frame) { // return IDENTIFY_NO_FRAME if no new frame detected // return 0 if new frame with no rotation detected - // return > 0 if new frame with rotations detected, the value is the delay before the first rotation in ms + // return > 0 if new frame with rotations detected, the value is the delay before the first rotation in ms mySerum.triggerID = 0xffffffff; if (!enabled) @@ -1560,7 +1560,7 @@ SERUM_API uint32_t Serum_ColorizeWithMetadatav2(uint8_t* frame) { // return IDENTIFY_NO_FRAME if no new frame detected // return 0 if new frame with no rotation detected - // return > 0 if new frame with rotations detected, the value is the delay before the first rotation in ms + // return > 0 if new frame with rotations detected, the value is the delay before the first rotation in ms mySerum.triggerID = 0xffffffff; // Let's first identify the incoming frame among the ones we have in the crom @@ -1660,7 +1660,7 @@ SERUM_API uint32_t Serum_ColorizeWithMetadatav2(uint8_t* frame) return (uint32_t)mySerum.rotationtimer; // new frame, return true } } - + return IDENTIFY_NO_FRAME; // no new frame, client has to update rotations! } From 38e19598e8d0c49ed7082c669a48cd6b3c3aac0c Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Mon, 21 Apr 2025 00:14:15 +0200 Subject: [PATCH 11/12] formatting --- src/serum-decode.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/serum-decode.cpp b/src/serum-decode.cpp index b82823e..f1388b1 100644 --- a/src/serum-decode.cpp +++ b/src/serum-decode.cpp @@ -1668,7 +1668,7 @@ SERUM_API uint32_t Serum_Colorize(uint8_t* frame) { // return IDENTIFY_NO_FRAME if no new frame detected // return 0 if new frame with no rotation detected - // return > 0 if new frame with rotations detected, the value is the delay before the first rotation in ms + // return > 0 if new frame with rotations detected, the value is the delay before the first rotation in ms if (SerumVersion == SERUM_V2) return Serum_ColorizeWithMetadatav2(frame); else return Serum_ColorizeWithMetadatav1(frame); } From 871c3da9953ab3e8d7177562b24854a4db8112f5 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Mon, 21 Apr 2025 00:16:35 +0200 Subject: [PATCH 12/12] formatting --- src/sparse-vector.h | 98 +++++++++++++++++++++++++-------------------- 1 file changed, 55 insertions(+), 43 deletions(-) diff --git a/src/sparse-vector.h b/src/sparse-vector.h index b537243..35d72c6 100644 --- a/src/sparse-vector.h +++ b/src/sparse-vector.h @@ -8,60 +8,72 @@ #include #include -template +template class SparseVector { - static_assert(std::is_trivial::value && std::is_standard_layout::value, - "SparseVector only supports trivial types like uint8_t or uint16_t"); + static_assert(std::is_trivial::value && std::is_standard_layout::value, + "SparseVector only supports trivial types like uint8_t or uint16_t"); - protected: - std::unordered_map> data; - std::vector noData; +protected: + std::unordered_map> data; + std::vector noData; - public: - SparseVector(T noDataSignature) { - noData.resize(1, noDataSignature); - } +public: + SparseVector(T noDataSignature) + { + noData.resize(1, noDataSignature); + } - // Access data for a frame (returns pointer to noData if not found) - T* operator[](const uint32_t frame) { - auto it = data.find(frame); - if (it != data.end()) return it->second.data(); - return noData.data(); - } + // Access data for a frame (returns pointer to noData if not found) + T *operator[](const uint32_t frame) + { + auto it = data.find(frame); + if (it != data.end()) + return it->second.data(); + return noData.data(); + } - // Load data (only store if not matching the noData signature) - void my_fread(size_t elementCount, uint32_t nframes, FILE* stream) { - size_t blockSize = elementCount * sizeof(T); + // Load data (only store if not matching the noData signature) + void my_fread(size_t elementCount, uint32_t nframes, FILE *stream) + { + size_t blockSize = elementCount * sizeof(T); - if (noData.size() < elementCount) noData.resize(elementCount, noData[0]); + if (noData.size() < elementCount) + noData.resize(elementCount, noData[0]); - std::vector tmp(elementCount); + std::vector tmp(elementCount); - for (uint32_t i = 0; i < nframes; ++i) { - if (1 != fread(tmp.data(), blockSize, 1, stream)) { - // Error reading file - exit(1); - } + for (uint32_t i = 0; i < nframes; ++i) + { + if (1 != fread(tmp.data(), blockSize, 1, stream)) + { + // Error reading file + exit(1); + } - if (memcmp(tmp.data(), noData.data(), noData.size() * sizeof(T)) != 0) - data[i] = tmp; - } - } + if (memcmp(tmp.data(), noData.data(), noData.size() * sizeof(T)) != 0) + data[i] = tmp; + } + } - void set(uint32_t frame, const T* values, size_t elementCount) { - auto it = data.find(frame); - if (it != data.end()) { - it->second.resize(elementCount); - memcpy(it->second.data(), values, elementCount * sizeof(T)); - } else { - std::vector tmp(values, values + elementCount); - data[frame] = tmp; + void set(uint32_t frame, const T *values, size_t elementCount) + { + auto it = data.find(frame); + if (it != data.end()) + { + it->second.resize(elementCount); + memcpy(it->second.data(), values, elementCount * sizeof(T)); + } + else + { + std::vector tmp(values, values + elementCount); + data[frame] = tmp; + } } - } - // Clear all stored frames - void clear() { - data.clear(); - } + // Clear all stored frames + void clear() + { + data.clear(); + } };