diff --git a/platforms/android/arm64-v8a/external.sh b/platforms/android/arm64-v8a/external.sh index 42848f1..bc6d03c 100755 --- a/platforms/android/arm64-v8a/external.sh +++ b/platforms/android/arm64-v8a/external.sh @@ -6,7 +6,7 @@ CARGS_SHA=5949a20a926e902931de4a32adaad9f19c76f251 LIBZEDMD_SHA=42d95ed6f1fe2065ecbd247502d177d7e5eb7e4c LIBSERUM_SHA=b69d2b436bc93570a2e7e78d0946cd3c43f7aed5 SOCKPP_SHA=e6c4688a576d95f42dd7628cefe68092f6c5cd0f -LIBPUPDMD_SHA=5ed99b7c02a3873ba2ef0bd582b6e9fcf8061222 +LIBPUPDMD_SHA=8dedc8c81ded2f6b8ca4614752d395aae0332c6c if [[ $(uname) == "Linux" ]]; then NUM_PROCS=$(nproc) diff --git a/platforms/ios/arm64/external.sh b/platforms/ios/arm64/external.sh index a8da97c..412fc65 100755 --- a/platforms/ios/arm64/external.sh +++ b/platforms/ios/arm64/external.sh @@ -6,7 +6,7 @@ CARGS_SHA=5949a20a926e902931de4a32adaad9f19c76f251 LIBZEDMD_SHA=42d95ed6f1fe2065ecbd247502d177d7e5eb7e4c LIBSERUM_SHA=b69d2b436bc93570a2e7e78d0946cd3c43f7aed5 SOCKPP_SHA=e6c4688a576d95f42dd7628cefe68092f6c5cd0f -LIBPUPDMD_SHA=5ed99b7c02a3873ba2ef0bd582b6e9fcf8061222 +LIBPUPDMD_SHA=8dedc8c81ded2f6b8ca4614752d395aae0332c6c NUM_PROCS=$(sysctl -n hw.ncpu) diff --git a/platforms/linux/aarch64/external.sh b/platforms/linux/aarch64/external.sh index 2d4c2d2..5dbe20e 100755 --- a/platforms/linux/aarch64/external.sh +++ b/platforms/linux/aarch64/external.sh @@ -6,7 +6,7 @@ CARGS_SHA=5949a20a926e902931de4a32adaad9f19c76f251 LIBZEDMD_SHA=42d95ed6f1fe2065ecbd247502d177d7e5eb7e4c LIBSERUM_SHA=b69d2b436bc93570a2e7e78d0946cd3c43f7aed5 SOCKPP_SHA=e6c4688a576d95f42dd7628cefe68092f6c5cd0f -LIBPUPDMD_SHA=5ed99b7c02a3873ba2ef0bd582b6e9fcf8061222 +LIBPUPDMD_SHA=8dedc8c81ded2f6b8ca4614752d395aae0332c6c NUM_PROCS=$(nproc) diff --git a/platforms/linux/x64/external.sh b/platforms/linux/x64/external.sh index 39d25d8..71dcdbd 100755 --- a/platforms/linux/x64/external.sh +++ b/platforms/linux/x64/external.sh @@ -6,7 +6,7 @@ CARGS_SHA=5949a20a926e902931de4a32adaad9f19c76f251 LIBZEDMD_SHA=42d95ed6f1fe2065ecbd247502d177d7e5eb7e4c LIBSERUM_SHA=b69d2b436bc93570a2e7e78d0946cd3c43f7aed5 SOCKPP_SHA=e6c4688a576d95f42dd7628cefe68092f6c5cd0f -LIBPUPDMD_SHA=5ed99b7c02a3873ba2ef0bd582b6e9fcf8061222 +LIBPUPDMD_SHA=8dedc8c81ded2f6b8ca4614752d395aae0332c6c NUM_PROCS=$(nproc) diff --git a/platforms/macos/arm64/external.sh b/platforms/macos/arm64/external.sh index 823c685..4fb3bf7 100755 --- a/platforms/macos/arm64/external.sh +++ b/platforms/macos/arm64/external.sh @@ -6,7 +6,7 @@ CARGS_SHA=5949a20a926e902931de4a32adaad9f19c76f251 LIBZEDMD_SHA=42d95ed6f1fe2065ecbd247502d177d7e5eb7e4c LIBSERUM_SHA=b69d2b436bc93570a2e7e78d0946cd3c43f7aed5 SOCKPP_SHA=e6c4688a576d95f42dd7628cefe68092f6c5cd0f -LIBPUPDMD_SHA=5ed99b7c02a3873ba2ef0bd582b6e9fcf8061222 +LIBPUPDMD_SHA=8dedc8c81ded2f6b8ca4614752d395aae0332c6c NUM_PROCS=$(sysctl -n hw.ncpu) diff --git a/platforms/macos/x64/external.sh b/platforms/macos/x64/external.sh index a5eea69..ec29cd3 100755 --- a/platforms/macos/x64/external.sh +++ b/platforms/macos/x64/external.sh @@ -6,7 +6,7 @@ CARGS_SHA=5949a20a926e902931de4a32adaad9f19c76f251 LIBZEDMD_SHA=42d95ed6f1fe2065ecbd247502d177d7e5eb7e4c LIBSERUM_SHA=b69d2b436bc93570a2e7e78d0946cd3c43f7aed5 SOCKPP_SHA=e6c4688a576d95f42dd7628cefe68092f6c5cd0f -LIBPUPDMD_SHA=5ed99b7c02a3873ba2ef0bd582b6e9fcf8061222 +LIBPUPDMD_SHA=8dedc8c81ded2f6b8ca4614752d395aae0332c6c NUM_PROCS=$(sysctl -n hw.ncpu) diff --git a/platforms/tvos/arm64/external.sh b/platforms/tvos/arm64/external.sh index ea20b64..0ec573e 100755 --- a/platforms/tvos/arm64/external.sh +++ b/platforms/tvos/arm64/external.sh @@ -6,7 +6,7 @@ CARGS_SHA=5949a20a926e902931de4a32adaad9f19c76f251 LIBZEDMD_SHA=42d95ed6f1fe2065ecbd247502d177d7e5eb7e4c LIBSERUM_SHA=b69d2b436bc93570a2e7e78d0946cd3c43f7aed5 SOCKPP_SHA=e6c4688a576d95f42dd7628cefe68092f6c5cd0f -LIBPUPDMD_SHA=5ed99b7c02a3873ba2ef0bd582b6e9fcf8061222 +LIBPUPDMD_SHA=8dedc8c81ded2f6b8ca4614752d395aae0332c6c NUM_PROCS=$(sysctl -n hw.ncpu) diff --git a/platforms/win/x64/external.sh b/platforms/win/x64/external.sh index cadbd7e..5999d61 100755 --- a/platforms/win/x64/external.sh +++ b/platforms/win/x64/external.sh @@ -6,7 +6,7 @@ CARGS_SHA=5949a20a926e902931de4a32adaad9f19c76f251 LIBZEDMD_SHA=42d95ed6f1fe2065ecbd247502d177d7e5eb7e4c LIBSERUM_SHA=b69d2b436bc93570a2e7e78d0946cd3c43f7aed5 SOCKPP_SHA=e6c4688a576d95f42dd7628cefe68092f6c5cd0f -LIBPUPDMD_SHA=5ed99b7c02a3873ba2ef0bd582b6e9fcf8061222 +LIBPUPDMD_SHA=8dedc8c81ded2f6b8ca4614752d395aae0332c6c echo "Building libraries..." echo " CARGS_SHA: ${CARGS_SHA}" diff --git a/platforms/win/x86/external.sh b/platforms/win/x86/external.sh index ba0d172..03e2797 100755 --- a/platforms/win/x86/external.sh +++ b/platforms/win/x86/external.sh @@ -6,7 +6,7 @@ CARGS_SHA=5949a20a926e902931de4a32adaad9f19c76f251 LIBZEDMD_SHA=42d95ed6f1fe2065ecbd247502d177d7e5eb7e4c LIBSERUM_SHA=b69d2b436bc93570a2e7e78d0946cd3c43f7aed5 SOCKPP_SHA=e6c4688a576d95f42dd7628cefe68092f6c5cd0f -LIBPUPDMD_SHA=5ed99b7c02a3873ba2ef0bd582b6e9fcf8061222 +LIBPUPDMD_SHA=8dedc8c81ded2f6b8ca4614752d395aae0332c6c echo "Building libraries..." echo " CARGS_SHA: ${CARGS_SHA}" diff --git a/src/DMD.cpp b/src/DMD.cpp index 132f452..b18b14e 100644 --- a/src/DMD.cpp +++ b/src/DMD.cpp @@ -745,11 +745,13 @@ void DMD::PixelcadeDMDThread() { if (++bufferPosition >= DMDUTIL_FRAME_BUFFER_SIZE) bufferPosition = 0; - // @todo scaling - if (m_pUpdateBufferQueue[bufferPosition]->width == 128 && m_pUpdateBufferQueue[bufferPosition]->height == 32 && - (m_pUpdateBufferQueue[bufferPosition]->hasData || m_pUpdateBufferQueue[bufferPosition]->hasSegData)) + if (m_pUpdateBufferQueue[bufferPosition]->hasData || m_pUpdateBufferQueue[bufferPosition]->hasSegData) { - int length = m_pUpdateBufferQueue[bufferPosition]->width * m_pUpdateBufferQueue[bufferPosition]->height; + uint16_t width = m_pUpdateBufferQueue[bufferPosition]->width; + uint8_t height = m_pUpdateBufferQueue[bufferPosition]->height; + int length = width * height; + uint8_t depth = m_pUpdateBufferQueue[bufferPosition]->depth; + bool update = false; if (m_pUpdateBufferQueue[bufferPosition]->depth != 24) { @@ -758,7 +760,8 @@ void DMD::PixelcadeDMDThread() m_pUpdateBufferQueue[bufferPosition]->b); } - if (m_pUpdateBufferQueue[bufferPosition]->mode == Mode::RGB24) + // @todo scaling / centering + if (m_pUpdateBufferQueue[bufferPosition]->mode == Mode::RGB24 && width == 128 && height == 32) { uint8_t rgb24Data[128 * 32 * 3]; AdjustRGB24Depth(m_pUpdateBufferQueue[bufferPosition]->data, rgb24Data, length, palette, @@ -774,14 +777,16 @@ void DMD::PixelcadeDMDThread() } update = true; } - else if (m_pUpdateBufferQueue[bufferPosition]->mode == Mode::RGB16) + // @todo scaling / centering + else if (m_pUpdateBufferQueue[bufferPosition]->mode == Mode::RGB16 && width == 128 && height == 32) { memcpy(rgb565Data, m_pUpdateBufferQueue[bufferPosition]->segData, 128 * 32 * sizeof(uint16_t)); update = true; } - else + else if (m_pUpdateBufferQueue[bufferPosition]->mode == Mode::Data || + m_pUpdateBufferQueue[bufferPosition]->mode == Mode::AlphaNumeric) { - uint8_t renderBuffer[128 * 32]; + uint8_t renderBuffer[256 * 64]; if (m_pUpdateBufferQueue[bufferPosition]->mode == Mode::Data) { @@ -805,6 +810,23 @@ void DMD::PixelcadeDMDThread() m_pUpdateBufferQueue[bufferPosition]->width * m_pUpdateBufferQueue[bufferPosition]->height); update = true; } + + if (update) + { + uint8_t scaledBuffer[128 * 32]; + if (width == 128 && height == 32) + memcpy(scaledBuffer, renderBuffer, 128 * 32); + else if (width == 128 && height == 16) + FrameUtil::CenterIndexed(scaledBuffer, 128, 32, renderBuffer, 128, 16); + else if (width == 192 && height == 64) + FrameUtil::ScaleDownIndexed(scaledBuffer, 128, 32, renderBuffer, 192, 64); + else if (width == 256 && height == 64) + FrameUtil::ScaleDownIndexed(scaledBuffer, 128, 32, renderBuffer, 256, 64); + else + continue; + + memcpy(renderBuffer, scaledBuffer, 128 * 32); + } } else if (m_pUpdateBufferQueue[bufferPosition]->mode == Mode::AlphaNumeric) { @@ -1332,33 +1354,45 @@ void DMD::PupDMDThread() } } - // @todo scaling/centering 128x16 and 192x64 or check how PUP deals with it. - if (m_pPUPDMD && m_pUpdateBufferQueue[bufferPosition]->width == 128 && - m_pUpdateBufferQueue[bufferPosition]->height == 32 && m_pUpdateBufferQueue[bufferPosition]->hasData && + if (m_pPUPDMD && m_pUpdateBufferQueue[bufferPosition]->hasData && m_pUpdateBufferQueue[bufferPosition]->mode == Mode::Data && m_pUpdateBufferQueue[bufferPosition]->depth != 24) { - int length = m_pUpdateBufferQueue[bufferPosition]->width * m_pUpdateBufferQueue[bufferPosition]->height; + uint16_t width = m_pUpdateBufferQueue[bufferPosition]->width; + uint8_t height = m_pUpdateBufferQueue[bufferPosition]->height; + int length = width * height; + if (memcmp(renderBuffer, m_pUpdateBufferQueue[bufferPosition]->data, length) != 0) { memcpy(renderBuffer, m_pUpdateBufferQueue[bufferPosition]->data, length); + uint8_t depth = m_pUpdateBufferQueue[bufferPosition]->depth; + + uint8_t scaledBuffer[128 * 32]; + if (width == 128 && height == 32) + memcpy(scaledBuffer, renderBuffer, 128 * 32); + else if (width == 128 && height == 16) + FrameUtil::CenterIndexed(scaledBuffer, 128, 32, renderBuffer, 128, 16); + else if (width == 192 && height == 64) + FrameUtil::ScaleDownPUP(scaledBuffer, 128, 32, renderBuffer, 192, 64); + else + return; uint16_t triggerID = 0; if (Config::GetInstance()->IsPUPExactColorMatch()) { - triggerID = m_pPUPDMD->MatchIndexed(renderBuffer); + triggerID = m_pPUPDMD->MatchIndexed(scaledBuffer, width, height); } else { - UpdatePalette(palette, m_pUpdateBufferQueue[bufferPosition]->depth, m_pUpdateBufferQueue[bufferPosition]->r, - m_pUpdateBufferQueue[bufferPosition]->g, m_pUpdateBufferQueue[bufferPosition]->b); + // apply a standard orange palette + UpdatePalette(palette, depth, 255, 69, 0); uint8_t* pFrame = (uint8_t*)malloc(length * 3); for (uint16_t i = 0; i < length; i++) { - uint16_t pos = renderBuffer[i] * 3; + uint16_t pos = scaledBuffer[i] * 3; memcpy(&pFrame[i * 3], &palette[pos], 3); } - triggerID = m_pPUPDMD->Match(pFrame, false); + triggerID = m_pPUPDMD->Match(pFrame, width, height, false); free(pFrame); } diff --git a/src/FrameUtil.cpp b/src/FrameUtil.cpp index 0b60920..4a94a67 100644 --- a/src/FrameUtil.cpp +++ b/src/FrameUtil.cpp @@ -9,6 +9,7 @@ #include #include #include +#include namespace DMDUtil { @@ -230,4 +231,127 @@ std::string FrameUtil::HexDump(const uint8_t* data, size_t size) return ss.str(); } +void FrameUtil::ScaleDownIndexed(uint8_t* pDestFrame, const uint8_t destWidth, const uint8_t destHeight, + const uint8_t* pSrcFrame, const uint16_t srcWidth, const uint8_t srcHeight) +{ + memset(pDestFrame, 0, destWidth * destHeight); + uint8_t xOffset = (destWidth - (srcWidth / 2)) / 2; + uint8_t yOffset = (destHeight - (srcHeight / 2)) / 2; + + // for half scaling we take the 4 points and look if there is one color repeated + for (uint8_t y = 0; y < srcHeight; y += 2) + { + std::vector row; + row.reserve(srcWidth / 2); + + for (uint16_t x = 0; x < srcWidth; x += 2) + { + uint8_t upper_left = pSrcFrame[y * srcWidth + x]; + uint8_t upper_right = pSrcFrame[y * srcWidth + x + 1]; + uint8_t lower_left = pSrcFrame[(y + 1) * srcWidth + x]; + uint8_t lower_right = pSrcFrame[(y + 1) * srcWidth + x + 1]; + + if (x < srcWidth / 2) + { + if (y < srcHeight / 2) + { + if (upper_left == upper_right || upper_left == lower_left || upper_left == lower_right) + row.push_back(upper_left); + else if (upper_right == lower_left || upper_right == lower_right) + row.push_back(upper_right); + else if (lower_left == lower_right) + row.push_back(lower_left); + else + row.push_back(upper_left); + } + else + { + if (lower_left == lower_right || lower_left == upper_left || lower_left == upper_right) + row.push_back(lower_right); + else if (lower_right == upper_left || lower_right == upper_right) + row.push_back(lower_right); + else if (upper_left == upper_right) + row.push_back(upper_left); + else + row.push_back(lower_left); + } + } + else + { + if (y < srcHeight / 2) + { + if (upper_right == upper_left || upper_right == lower_right || upper_right == lower_left) + row.push_back(upper_right); + else if (upper_left == lower_right || upper_left == lower_left) + row.push_back(upper_left); + else if (lower_right == lower_left) + row.push_back(lower_right); + else + row.push_back(upper_right); + } + else + { + if (lower_right == lower_left || lower_right == upper_right || lower_right == upper_left) + row.push_back(lower_right); + else if (lower_left == upper_right || lower_left == upper_left) + row.push_back(lower_left); + else if (upper_right == upper_left) + row.push_back(upper_right); + else + row.push_back(lower_right); + } + } + } + + memcpy(&pDestFrame[(yOffset + (y / 2)) * destWidth + xOffset], row.data(), srcWidth / 2); + } +} + +void FrameUtil::ScaleDownPUP(uint8_t* pDestFrame, const uint8_t destWidth, const uint8_t destHeight, + const uint8_t* pSrcFrame, const uint8_t srcWidth, const uint8_t srcHeight) +{ + memset(pDestFrame, 0, destWidth * destHeight); + uint8_t xOffset = (destWidth - (srcWidth / 2)) / 2; + uint8_t yOffset = (destHeight - (srcHeight / 2)) / 2; + + // for half scaling we take the 4 points and look if there is one color repeated + for (uint8_t y = 0; y < srcHeight; y += 2) + { + std::vector row; + row.reserve(srcWidth / 2); + + for (uint8_t x = 0; x < srcWidth; x += 2) + { + uint8_t pixel1 = pSrcFrame[y * srcWidth + x]; + uint8_t pixel2 = pSrcFrame[y * srcWidth + x + 1]; + uint8_t pixel3 = pSrcFrame[(y + 1) * srcWidth + x]; + uint8_t pixel4 = pSrcFrame[(y + 1) * srcWidth + x + 1]; + + if (pixel1 == pixel2 || pixel1 == pixel3 || pixel1 == pixel4) + row.push_back(pixel1); + else if (pixel2 == pixel3 || pixel2 == pixel4) + row.push_back(pixel2); + else if (pixel3 == pixel4) + row.push_back(pixel3); + else + row.push_back(pixel1); + } + + memcpy(&pDestFrame[(yOffset + (y / 2)) * destWidth + xOffset], row.data(), srcWidth / 2); + } +} + +void FrameUtil::CenterIndexed(uint8_t* pDestFrame, const uint8_t destWidth, const uint8_t destHeight, + const uint8_t* pSrcFrame, const uint8_t srcWidth, const uint8_t srcHeight) +{ + memset(pDestFrame, 0, destWidth * destHeight); + uint8_t xOffset = (destWidth - srcWidth) / 2; + uint8_t yOffset = (destHeight - srcHeight) / 2; + + for (uint8_t y = 0; y < srcHeight; y++) + { + memcpy(&pDestFrame[(yOffset + y) * destWidth + xOffset], &pSrcFrame[y * srcWidth], srcWidth); + } +} + } // namespace DMDUtil diff --git a/src/FrameUtil.h b/src/FrameUtil.h index 4103319..ed35782 100644 --- a/src/FrameUtil.h +++ b/src/FrameUtil.h @@ -31,6 +31,12 @@ class FrameUtil int destHeight); static float CalcBrightness(float x); static std::string HexDump(const uint8_t* data, size_t size); + static void ScaleDownIndexed(uint8_t* pDestFrame, const uint8_t destWidth, const uint8_t destHeight, + const uint8_t* pSrcFrame, const uint16_t srcWidth, const uint8_t srcHeight); + static void ScaleDownPUP(uint8_t* pDestFrame, const uint8_t destWidth, const uint8_t destHeight, + const uint8_t* pSrcFrame, const uint8_t srcWidth, const uint8_t srcHeight); + static void CenterIndexed(uint8_t* pDestFrame, const uint8_t destWidth, const uint8_t destHeight, + const uint8_t* pSrcFrame, const uint8_t srcWidth, const uint8_t srcHeight); }; } // namespace DMDUtil