From 63b923672b1a63b48c6db2f87ebe3aa9185ff2cc Mon Sep 17 00:00:00 2001 From: Jason Millard Date: Thu, 1 Feb 2024 18:13:55 -0500 Subject: [PATCH] feature: Add new VirtualDMD class and replace RGB32 with RGB24 (#6) --- .github/workflows/libdmdutil.yml | 8 +- CMakeLists.txt | 126 +++++++++++++----------- README.md | 13 ++- include/DMDUtil/DMD.h | 18 ++-- include/DMDUtil/DMDUtil.h | 5 +- include/DMDUtil/VirtualDMD.h | 41 ++++++++ src/DMD.cpp | 102 +++++++++++-------- src/{Pixelcade.cpp => PixelcadeDMD.cpp} | 40 ++++---- src/{Pixelcade.h => PixelcadeDMD.h} | 10 +- src/VirtualDMD.cpp | 56 +++++++++++ 10 files changed, 276 insertions(+), 143 deletions(-) create mode 100644 include/DMDUtil/VirtualDMD.h rename src/{Pixelcade.cpp => PixelcadeDMD.cpp} (80%) rename src/{Pixelcade.h => PixelcadeDMD.h} (76%) create mode 100644 src/VirtualDMD.cpp diff --git a/.github/workflows/libdmdutil.yml b/.github/workflows/libdmdutil.yml index ddd2a23..c929f57 100644 --- a/.github/workflows/libdmdutil.yml +++ b/.github/workflows/libdmdutil.yml @@ -65,7 +65,7 @@ jobs: - uses: actions/checkout@v4 - if: (matrix.platform == 'win') name: Add msbuild to path (win runner) - uses: microsoft/setup-msbuild@v1.1 + uses: microsoft/setup-msbuild@v2 - if: (matrix.platform == 'macos') name: Add autoconf and automake (mac runner) run: | @@ -164,7 +164,7 @@ jobs: fi echo "artifact_path=${ARTIFACT_PATH}" >> $GITHUB_OUTPUT - name: Upload artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: libdmdutil-${{ needs.version.outputs.tag }}-${{ matrix.platform }}-${{ matrix.arch }} path: ${{ steps.artifacts.outputs.artifact_path }} @@ -174,7 +174,7 @@ jobs: needs: [ version, build ] name: Build libdmdutil-macos steps: - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 - name: Unpack artifacts run: | cd libdmdutil-${{ needs.version.outputs.tag }}-macos-x64 @@ -208,7 +208,7 @@ jobs: cd tmp tar -czvf ../libdmdutil-${{ needs.version.outputs.tag }}-macos.tar.gz * - name: Upload artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: libdmdutil-${{ needs.version.outputs.tag }}-macos path: libdmdutil-${{ needs.version.outputs.tag }}-macos.tar.gz diff --git a/CMakeLists.txt b/CMakeLists.txt index 26d70c9..d908267 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,12 +5,14 @@ set(ARCH "x64" CACHE STRING "Arch") option(BUILD_SHARED "Option to build shared library" ON) option(BUILD_STATIC "Option to build static library" ON) +option(POST_BUILD_COPY_EXT_LIBS "Option to copy external libraries to build directory" ON) message(STATUS "PLATFORM: ${PLATFORM}") message(STATUS "ARCH: ${ARCH}") message(STATUS "BUILD_SHARED: ${BUILD_SHARED}") message(STATUS "BUILD_STATIC: ${BUILD_STATIC}") +message(STATUS "POST_BUILD_COPY_EXT_LIBS: ${POST_BUILD_COPY_EXT_LIBS}") if(PLATFORM STREQUAL "ios") set(CMAKE_SYSTEM_NAME iOS) @@ -63,6 +65,7 @@ set(CMAKE_C_VISIBILITY_PRESET hidden) set(DMDUTIL_SOURCES src/Config.cpp src/DMD.cpp + src/VirtualDMD.cpp src/Logger.cpp src/AlphaNumeric.cpp src/FrameUtil.cpp @@ -71,7 +74,7 @@ set(DMDUTIL_SOURCES if(PLATFORM STREQUAL "win" OR PLATFORM STREQUAL "macos" OR PLATFORM STREQUAL "linux") list(APPEND DMDUTIL_SOURCES - src/Pixelcade.cpp + src/PixelcadeDMD.cpp ) endif() @@ -140,38 +143,40 @@ if(BUILD_SHARED) target_link_libraries(dmdutil_test PUBLIC dmdutil_shared) - if(PLATFORM STREQUAL "win") - if(ARCH STREQUAL "x64") + if(POST_BUILD_COPY_EXT_LIBS) + if(PLATFORM STREQUAL "win") + if(ARCH STREQUAL "x64") + add_custom_command(TARGET dmdutil_test POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/build-libs/${PLATFORM}/${ARCH}/zedmd64.lib" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/zedmd64.dll" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/build-libs/${PLATFORM}/${ARCH}/serum64.lib" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/serum64.dll" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/build-libs/${PLATFORM}/${ARCH}/libserialport64.lib" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/libserialport64.dll" "$" + ) + else() + add_custom_command(TARGET dmdutil_test POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/build-libs/${PLATFORM}/${ARCH}/zedmd.lib" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/zedmd.dll" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/build-libs/${PLATFORM}/${ARCH}/serum.lib" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/serum.dll" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/build-libs/${PLATFORM}/${ARCH}/libserialport.lib" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/libserialport.dll" "$" + ) + endif() + elseif(PLATFORM STREQUAL "macos") add_custom_command(TARGET dmdutil_test POST_BUILD - COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/build-libs/${PLATFORM}/${ARCH}/zedmd64.lib" "$" - COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/zedmd64.dll" "$" - COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/build-libs/${PLATFORM}/${ARCH}/serum64.lib" "$" - COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/serum64.dll" "$" - COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/build-libs/${PLATFORM}/${ARCH}/libserialport64.lib" "$" - COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/libserialport64.dll" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/libzedmd.0.5.0.dylib" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/libserum.1.6.2.dylib" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/libserialport.dylib" "$" ) - else() + elseif(PLATFORM STREQUAL "linux") add_custom_command(TARGET dmdutil_test POST_BUILD - COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/build-libs/${PLATFORM}/${ARCH}/zedmd.lib" "$" - COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/zedmd.dll" "$" - COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/build-libs/${PLATFORM}/${ARCH}/serum.lib" "$" - COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/serum.dll" "$" - COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/build-libs/${PLATFORM}/${ARCH}/libserialport.lib" "$" - COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/libserialport.dll" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/libzedmd.so.0.5.0" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/libserum.so.1.6.2" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/libserialport.so.0" "$" ) endif() - elseif(PLATFORM STREQUAL "macos") - add_custom_command(TARGET dmdutil_test POST_BUILD - COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/libzedmd.0.5.0.dylib" "$" - COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/libserum.1.6.2.dylib" "$" - COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/libserialport.dylib" "$" - ) - elseif(PLATFORM STREQUAL "linux") - add_custom_command(TARGET dmdutil_test POST_BUILD - COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/libzedmd.so.0.5.0" "$" - COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/libserum.so.1.6.2" "$" - COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/libserialport.so.0" "$" - ) endif() endif() endif() @@ -206,52 +211,57 @@ if(BUILD_STATIC) third-party/build-libs/${PLATFORM}/${ARCH} third-party/runtime-libs/${PLATFORM}/${ARCH} ) - if(ARCH STREQUAL "x64") target_link_libraries(dmdutil_test_s PUBLIC dmdutil_static zedmd64 serum64 libserialport64 ws2_32) - - add_custom_command(TARGET dmdutil_test_s POST_BUILD - COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/build-libs/${PLATFORM}/${ARCH}/zedmd64.lib" "$" - COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/zedmd64.dll" "$" - COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/build-libs/${PLATFORM}/${ARCH}/serum64.lib" "$" - COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/serum64.dll" "$" - COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/build-libs/${PLATFORM}/${ARCH}/libserialport64.lib" "$" - COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/libserialport64.dll" "$" - ) else() target_link_libraries(dmdutil_test_s PUBLIC dmdutil_static zedmd serum libserialport ws2_32) - - add_custom_command(TARGET dmdutil_test_s POST_BUILD - COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/build-libs/${PLATFORM}/${ARCH}/zedmd.lib" "$" - COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/zedmd.dll" "$" - COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/build-libs/${PLATFORM}/${ARCH}/serum.lib" "$" - COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/serum.dll" "$" - COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/build-libs/${PLATFORM}/${ARCH}/libserialport.lib" "$" - COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/libserialport.dll" "$" - ) endif() elseif(PLATFORM STREQUAL "macos") target_link_directories(dmdutil_test_s PUBLIC third-party/runtime-libs/${PLATFORM}/${ARCH} ) target_link_libraries(dmdutil_test_s PUBLIC dmdutil_static zedmd.0.5.0 serum.1.6.2 serialport) - - add_custom_command(TARGET dmdutil_test_s POST_BUILD - COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/libzedmd.0.5.0.dylib" "$" - COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/libserum.1.6.2.dylib" "$" - COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/libserialport.dylib" "$" - ) elseif(PLATFORM STREQUAL "linux") target_link_directories(dmdutil_test_s PUBLIC third-party/runtime-libs/${PLATFORM}/${ARCH} ) target_link_libraries(dmdutil_test_s PUBLIC dmdutil_static -l:libzedmd.so.0.5.0 -l:libserum.so.1.6.2 -l:libserialport.so.0) + endif() - add_custom_command(TARGET dmdutil_test_s POST_BUILD - COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/libzedmd.so.0.5.0" "$" - COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/libserum.so.1.6.2" "$" - COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/libserialport.so.0" "$" - ) + if(POST_BUILD_COPY_EXT_LIBS) + if(PLATFORM STREQUAL "win") + if(ARCH STREQUAL "x64") + add_custom_command(TARGET dmdutil_test_s POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/build-libs/${PLATFORM}/${ARCH}/zedmd64.lib" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/zedmd64.dll" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/build-libs/${PLATFORM}/${ARCH}/serum64.lib" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/serum64.dll" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/build-libs/${PLATFORM}/${ARCH}/libserialport64.lib" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/libserialport64.dll" "$" + ) + else() + add_custom_command(TARGET dmdutil_test_s POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/build-libs/${PLATFORM}/${ARCH}/zedmd.lib" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/zedmd.dll" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/build-libs/${PLATFORM}/${ARCH}/serum.lib" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/serum.dll" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/build-libs/${PLATFORM}/${ARCH}/libserialport.lib" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/libserialport.dll" "$" + ) + endif() + elseif(PLATFORM STREQUAL "macos") + add_custom_command(TARGET dmdutil_test_s POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/libzedmd.0.5.0.dylib" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/libserum.1.6.2.dylib" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/libserialport.dylib" "$" + ) + else() + add_custom_command(TARGET dmdutil_test_s POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/libzedmd.so.0.5.0" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/libserum.so.1.6.2" "$" + COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_SOURCE_DIR}/third-party/runtime-libs/${PLATFORM}/${ARCH}/libserialport.so.0" "$" + ) + endif() endif() endif() endif() diff --git a/README.md b/README.md index 83bb837..cc9dcfc 100644 --- a/README.md +++ b/README.md @@ -15,18 +15,25 @@ void setup() DMDUtil::Config* pConfig = DMDUtil::Config::GetInstance(); pConfig->SetZeDMD(true); pConfig->SetZeDMDDevice("/dev/cu.usbserial-0001"); - pConfig->SetPixelcade(false); + pConfig->SetPixelcadeDMD(false); } void test() { - uint8_t* pData = (uint8_t*)malloc(128 * 32); DMDUtil::DMD* pDmd = new DMDUtil::DMD(128, 32, false, "t2_l8"); + DMDUtil::VirtualDMD* pVirtualDMD = pDmd->CreateVirtualDMD(); + + uint8_t* pData = (uint8_t*)malloc(128 * 32); . . . pDmd->UpdateData((const UINT8*)pData, 2, 255, 0, 0); - uint32_t* pRGB32Data = pDmd->GetRGB32Data(); + + uint8_t* pRGB24Data = pVirtualDMD->GetRGB24Data(); + + if (pRGB24Data) { + // Render pRGB24Data + } } ``` diff --git a/include/DMDUtil/DMD.h b/include/DMDUtil/DMD.h index 08a332d..8becdf7 100644 --- a/include/DMDUtil/DMD.h +++ b/include/DMDUtil/DMD.h @@ -46,7 +46,8 @@ enum class AlphaNumericLayout class AlphaNumeric; class Serum; -class Pixelcade; +class PixelcadeDMD; +class VirtualDMD; class DMDUTILAPI DMD { @@ -59,14 +60,11 @@ class DMDUTILAPI DMD int GetWidth() const { return m_width; } int GetHeight() const { return m_height; } int GetLength() const { return m_length; } - bool IsUpdated() const { return m_updated; } - void ResetUpdated() { m_updated = false; } + VirtualDMD* CreateVirtualDMD(); void UpdateData(const uint8_t* pData, int depth, uint8_t r, uint8_t g, uint8_t b); void UpdateRGB24Data(const uint8_t* pData, int depth, uint8_t r, uint8_t g, uint8_t b); void UpdateAlphaNumericData(AlphaNumericLayout layout, const uint16_t* pData1, const uint16_t* pData2, uint8_t r, uint8_t g, uint8_t b); - const uint8_t* GetLevelData() const { return m_pLevelData; } - const uint32_t* GetRGB32Data() const { return m_pRGB32Data; } private: enum class DmdMode @@ -107,12 +105,12 @@ class DMDUTILAPI DMD int m_height; int m_length; bool m_sam; - uint8_t* m_pData; - uint8_t* m_pRGB24Data; + uint8_t* m_pBuffer; + uint8_t* m_pRGB24Buffer; uint16_t m_segData1[128]; uint16_t m_segData2[128]; uint8_t* m_pLevelData; - uint32_t* m_pRGB32Data; + uint8_t* m_pRGB24Data; uint16_t* m_pRGB565Data; uint8_t m_palette[192]; AlphaNumeric* m_pAlphaNumeric; @@ -121,9 +119,9 @@ class DMDUTILAPI DMD #if !( \ (defined(__APPLE__) && ((defined(TARGET_OS_IOS) && TARGET_OS_IOS) || (defined(TARGET_OS_TV) && TARGET_OS_TV))) || \ defined(__ANDROID__)) - Pixelcade* m_pPixelcade; + PixelcadeDMD* m_pPixelcadeDMD; #endif - bool m_updated; + std::vector m_virtualDMDs; std::thread* m_pThread; std::queue m_updates; diff --git a/include/DMDUtil/DMDUtil.h b/include/DMDUtil/DMDUtil.h index 22b8580..3a27514 100644 --- a/include/DMDUtil/DMDUtil.h +++ b/include/DMDUtil/DMDUtil.h @@ -1,7 +1,7 @@ #pragma once #define DMDUTIL_VERSION_MAJOR 0 // X Digits -#define DMDUTIL_VERSION_MINOR 1 // Max 2 Digits +#define DMDUTIL_VERSION_MINOR 2 // Max 2 Digits #define DMDUTIL_VERSION_PATCH 0 // Max 2 Digits #define _DMDUTIL_STR(x) #x @@ -12,4 +12,5 @@ #define DMDUTIL_MINOR_VERSION DMDUTIL_STR(DMDUTIL_VERSION_MAJOR) "." DMDUTIL_STR(DMDUTIL_VERSION_MINOR) #include "Config.h" -#include "DMD.h" \ No newline at end of file +#include "DMD.h" +#include "VirtualDMD.h" \ No newline at end of file diff --git a/include/DMDUtil/VirtualDMD.h b/include/DMDUtil/VirtualDMD.h new file mode 100644 index 0000000..7d1c349 --- /dev/null +++ b/include/DMDUtil/VirtualDMD.h @@ -0,0 +1,41 @@ +#pragma once + +#ifdef _MSC_VER +#define DMDUTILAPI __declspec(dllexport) +#define DMDUTILCALLBACK __stdcall +#else +#define DMDUTILAPI __attribute__((visibility("default"))) +#define DMDUTILCALLBACK +#endif + +#include + +namespace DMDUtil +{ + +class DMDUTILAPI VirtualDMD +{ + public: + VirtualDMD(int width, int height); + ~VirtualDMD(); + + void Update(uint8_t* pLevelData, uint8_t* pRGB24Data); + int GetWidth() { return m_width; } + int GetHeight() { return m_height; } + int GetLength() const { return m_length; } + int GetPitch() const { return m_pitch; } + uint8_t* GetLevelData(); + uint8_t* GetRGB24Data(); + + private: + int m_width; + int m_height; + int m_length; + int m_pitch; + int m_update; + + uint8_t* m_pLevelData; + uint8_t* m_pRGB24Data; +}; + +} // namespace DMDUtil \ No newline at end of file diff --git a/src/DMD.cpp b/src/DMD.cpp index acd0580..7bb10c7 100644 --- a/src/DMD.cpp +++ b/src/DMD.cpp @@ -1,11 +1,12 @@ #include "DMDUtil/DMD.h" #include "DMDUtil/Config.h" +#include "DMDUtil/VirtualDMD.h" #if !( \ (defined(__APPLE__) && ((defined(TARGET_OS_IOS) && TARGET_OS_IOS) || (defined(TARGET_OS_TV) && TARGET_OS_TV))) || \ defined(__ANDROID__)) -#include "Pixelcade.h" +#include "PixelcadeDMD.h" #endif #include @@ -34,16 +35,16 @@ DMD::DMD(int width, int height, bool sam, const char* name) m_height = height; m_length = width * height; m_sam = sam; - m_pData = (uint8_t*)malloc(m_length); - memset(m_pData, 0, m_length); - m_pRGB24Data = (uint8_t*)malloc(m_length * 3); - memset(m_pRGB24Data, 0, m_length * 3); + m_pBuffer = (uint8_t*)malloc(m_length); + memset(m_pBuffer, 0, m_length); + m_pRGB24Buffer = (uint8_t*)malloc(m_length * 3); + memset(m_pRGB24Buffer, 0, m_length * 3); memset(m_segData1, 0, 128 * sizeof(uint16_t)); memset(m_segData2, 0, 128 * sizeof(uint16_t)); m_pLevelData = (uint8_t*)malloc(m_length); memset(m_pLevelData, 0, m_length); - m_pRGB32Data = (uint32_t*)malloc(m_length * sizeof(uint32_t)); - memset(m_pRGB32Data, 0, m_length * sizeof(uint32_t)); + m_pRGB24Data = (uint8_t*)malloc(m_length * 3); + memset(m_pRGB24Data, 0, m_length * 3); m_pRGB565Data = (uint16_t*)malloc(m_length * sizeof(uint16_t)); memset(m_pRGB565Data, 0, m_length * sizeof(uint16_t)); memset(m_palette, 0, 192); @@ -53,11 +54,10 @@ DMD::DMD(int width, int height, bool sam, const char* name) #if !( \ (defined(__APPLE__) && ((defined(TARGET_OS_IOS) && TARGET_OS_IOS) || (defined(TARGET_OS_TV) && TARGET_OS_TV))) || \ defined(__ANDROID__)) - m_pPixelcade = nullptr; + m_pPixelcadeDMD = nullptr; #endif m_pThread = nullptr; m_running = false; - m_updated = false; FindDevices(); @@ -84,10 +84,10 @@ DMD::~DMD() delete pUpdate; } - free(m_pData); - free(m_pRGB24Data); + free(m_pBuffer); + free(m_pRGB24Buffer); free(m_pLevelData); - free(m_pRGB32Data); + free(m_pRGB24Data); free(m_pRGB565Data); delete m_pAlphaNumeric; delete m_pSerum; @@ -95,8 +95,10 @@ DMD::~DMD() #if !( \ (defined(__APPLE__) && ((defined(TARGET_OS_IOS) && TARGET_OS_IOS) || (defined(TARGET_OS_TV) && TARGET_OS_TV))) || \ defined(__ANDROID__)) - delete m_pPixelcade; + delete m_pPixelcadeDMD; #endif + + for (VirtualDMD* pVirtualDMD : m_virtualDMDs) delete pVirtualDMD; } bool DMD::IsFinding() { return m_finding; } @@ -106,12 +108,19 @@ bool DMD::HasDisplay() const #if !( \ (defined(__APPLE__) && ((defined(TARGET_OS_IOS) && TARGET_OS_IOS) || (defined(TARGET_OS_TV) && TARGET_OS_TV))) || \ defined(__ANDROID__)) - return (m_pZeDMD != nullptr) || (m_pPixelcade != nullptr); + return (m_pZeDMD != nullptr) || (m_pPixelcadeDMD != nullptr); #else return (m_pZeDMD != nullptr); #endif } +VirtualDMD* DMD::CreateVirtualDMD() +{ + VirtualDMD* const pVirtualDMD = new VirtualDMD(m_width, m_height); + m_virtualDMDs.push_back(pVirtualDMD); + return pVirtualDMD; +} + void DMD::UpdateData(const uint8_t* pData, int depth, uint8_t r, uint8_t g, uint8_t b) { DMDUpdate* const pUpdate = new DMDUpdate(); @@ -192,7 +201,7 @@ void DMD::FindDevices() #if !( \ (defined(__APPLE__) && ((defined(TARGET_OS_IOS) && TARGET_OS_IOS) || (defined(TARGET_OS_TV) && TARGET_OS_TV))) || \ defined(__ANDROID__)) - Pixelcade* pPixelcade = nullptr; + PixelcadeDMD* pPixelcadeDMD = nullptr; #endif Config* const pConfig = Config::GetInstance(); @@ -224,14 +233,15 @@ void DMD::FindDevices() #if !( \ (defined(__APPLE__) && ((defined(TARGET_OS_IOS) && TARGET_OS_IOS) || (defined(TARGET_OS_TV) && TARGET_OS_TV))) || \ defined(__ANDROID__)) - if (pConfig->IsPixelcade()) pPixelcade = Pixelcade::Connect(pConfig->GetPixelcadeDevice(), m_width, m_height); + if (pConfig->IsPixelcade()) + pPixelcadeDMD = PixelcadeDMD::Connect(pConfig->GetPixelcadeDevice(), m_width, m_height); #endif m_pZeDMD = pZeDMD; #if !( \ (defined(__APPLE__) && ((defined(TARGET_OS_IOS) && TARGET_OS_IOS) || (defined(TARGET_OS_TV) && TARGET_OS_TV))) || \ defined(__ANDROID__)) - m_pPixelcade = pPixelcade; + m_pPixelcadeDMD = pPixelcadeDMD; #endif m_finding = false; @@ -342,16 +352,16 @@ void DMD::UpdateData(const DMDUpdate* pUpdate, bool update) { if (pData) { - if (memcmp(m_pData, pData, m_length) != 0) + if (memcmp(m_pBuffer, pData, m_length) != 0) { - memcpy(m_pData, pData, m_length); + memcpy(m_pBuffer, pData, m_length); update = true; } } if (UpdatePalette(pUpdate)) update = true; } - else if (m_pSerum->Convert(pData, m_pData, m_palette)) + else if (m_pSerum->Convert(pData, m_pBuffer, m_palette)) { // if we have serum, run a conversion, and if success, we have an update (needed for rotations) // serum will take care of updating the data buffer @@ -362,12 +372,16 @@ void DMD::UpdateData(const DMDUpdate* pUpdate, bool update) for (int i = 0; i < m_length; i++) { - int pos = m_pData[i] * 3; + int pos = m_pBuffer[i] * 3; uint32_t r = m_palette[pos]; uint32_t g = m_palette[pos + 1]; uint32_t b = m_palette[pos + 2]; - m_pRGB32Data[i] = r | g << 8 | b << 16 | 0xFFu << 24; + pos = i * 3; + m_pRGB24Data[pos] = r; + m_pRGB24Data[pos + 1] = g; + m_pRGB24Data[pos + 2] = b; + m_pRGB565Data[i] = (uint16_t)(((r & 0xF8u) << 8) | ((g & 0xFCu) << 3) | (b >> 3)); } @@ -376,19 +390,19 @@ void DMD::UpdateData(const DMDUpdate* pUpdate, bool update) if (m_pSerum) { m_pZeDMD->SetPalette(m_palette, 64); - m_pZeDMD->RenderColoredGray6(m_pData, nullptr); + m_pZeDMD->RenderColoredGray6(m_pBuffer, nullptr); } else { if (pUpdate->depth == 2) { m_pZeDMD->SetPalette(m_palette, 4); - m_pZeDMD->RenderGray2(m_pData); + m_pZeDMD->RenderGray2(m_pBuffer); } else { m_pZeDMD->SetPalette(m_palette, 16); - m_pZeDMD->RenderGray4(m_pData); + m_pZeDMD->RenderGray4(m_pBuffer); } } } @@ -396,10 +410,10 @@ void DMD::UpdateData(const DMDUpdate* pUpdate, bool update) #if !( \ (defined(__APPLE__) && ((defined(TARGET_OS_IOS) && TARGET_OS_IOS) || (defined(TARGET_OS_TV) && TARGET_OS_TV))) || \ defined(__ANDROID__)) - if (m_pPixelcade) m_pPixelcade->Update(m_pRGB565Data); + if (m_pPixelcadeDMD) m_pPixelcadeDMD->Update(m_pRGB565Data); #endif - m_updated = true; + for (VirtualDMD* pVirtualDMD : m_virtualDMDs) pVirtualDMD->Update(m_pLevelData, m_pRGB24Data); } void DMD::UpdateRGB24Data(const DMDUpdate* pUpdate, bool update) @@ -411,18 +425,18 @@ void DMD::UpdateRGB24Data(const DMDUpdate* pUpdate, bool update) if (UpdatePalette(pUpdate)) update = true; } - if (memcmp(m_pRGB24Data, pData, m_length * 3) != 0) update = true; + if (memcmp(m_pRGB24Buffer, pData, m_length * 3) != 0) update = true; if (!update) return; - memcpy(m_pRGB24Data, pData, m_length * 3); + memcpy(m_pRGB24Buffer, pData, m_length * 3); - int pos = 0; for (int i = 0; i < m_length; i++) { - uint32_t r = m_pRGB24Data[pos++]; - uint32_t g = m_pRGB24Data[pos++]; - uint32_t b = m_pRGB24Data[pos++]; + int pos = i * 3; + uint32_t r = m_pRGB24Buffer[pos]; + uint32_t g = m_pRGB24Buffer[pos + 1]; + uint32_t b = m_pRGB24Buffer[pos + 2]; if (pUpdate->depth != 24) { @@ -438,13 +452,15 @@ void DMD::UpdateRGB24Data(const DMDUpdate* pUpdate, bool update) m_pLevelData[i] = level; int pos2 = level * 3; - r = m_palette[pos2]; g = m_palette[pos2 + 1]; b = m_palette[pos2 + 2]; } - m_pRGB32Data[i] = r | g << 8 | b << 16 | 0xFFu << 24; + m_pRGB24Data[pos] = (uint8_t)r; + m_pRGB24Data[pos + 1] = (uint8_t)g; + m_pRGB24Data[pos + 2] = (uint8_t)b; + m_pRGB565Data[i] = (uint16_t)(((r & 0xF8u) << 8) | ((g & 0xFCu) << 3) | (b >> 3)); } @@ -466,16 +482,16 @@ void DMD::UpdateRGB24Data(const DMDUpdate* pUpdate, bool update) } else if (pUpdate->depth == 24) { - if (m_pZeDMD) m_pZeDMD->RenderRgb24((uint8_t*)m_pRGB24Data); + if (m_pZeDMD) m_pZeDMD->RenderRgb24((uint8_t*)m_pRGB24Buffer); } #if !( \ (defined(__APPLE__) && ((defined(TARGET_OS_IOS) && TARGET_OS_IOS) || (defined(TARGET_OS_TV) && TARGET_OS_TV))) || \ defined(__ANDROID__)) - if (m_pPixelcade) m_pPixelcade->Update(m_pRGB565Data); + if (m_pPixelcadeDMD) m_pPixelcadeDMD->Update(m_pRGB565Data); #endif - m_updated = true; + for (VirtualDMD* pVirtualDMD : m_virtualDMDs) pVirtualDMD->Update(m_pLevelData, m_pRGB24Data); } void DMD::UpdateAlphaNumericData(const DMDUpdate* pUpdate, bool update) @@ -512,7 +528,11 @@ void DMD::UpdateAlphaNumericData(const DMDUpdate* pUpdate, bool update) uint32_t g = m_palette[pos + 1]; uint32_t b = m_palette[pos + 2]; - m_pRGB32Data[i] = r | g << 8 | b << 16 | 0xFFu << 24; + pos = i * 3; + m_pRGB24Data[pos] = (uint8_t)r; + m_pRGB24Data[pos + 1] = (uint8_t)g; + m_pRGB24Data[pos + 2] = (uint8_t)b; + m_pRGB565Data[i] = (uint16_t)(((r & 0xF8u) << 8) | ((g & 0xFCu) << 3) | (b >> 3)); } @@ -525,10 +545,10 @@ void DMD::UpdateAlphaNumericData(const DMDUpdate* pUpdate, bool update) #if !( \ (defined(__APPLE__) && ((defined(TARGET_OS_IOS) && TARGET_OS_IOS) || (defined(TARGET_OS_TV) && TARGET_OS_TV))) || \ defined(__ANDROID__)) - if (m_pPixelcade) m_pPixelcade->Update(m_pRGB565Data); + if (m_pPixelcadeDMD) m_pPixelcadeDMD->Update(m_pRGB565Data); #endif - m_updated = true; + for (VirtualDMD* pVirtualDMD : m_virtualDMDs) pVirtualDMD->Update(m_pLevelData, m_pRGB24Data); } } // namespace DMDUtil \ No newline at end of file diff --git a/src/Pixelcade.cpp b/src/PixelcadeDMD.cpp similarity index 80% rename from src/Pixelcade.cpp rename to src/PixelcadeDMD.cpp index 6df8c6a..9dc634b 100644 --- a/src/Pixelcade.cpp +++ b/src/PixelcadeDMD.cpp @@ -4,7 +4,7 @@ * https://github.com/freezy/dmd-extensions/blob/master/LibDmd/Output/Pixelcade/Pixelcade.cs */ -#include "Pixelcade.h" +#include "PixelcadeDMD.h" #include #include @@ -16,7 +16,7 @@ namespace DMDUtil { -Pixelcade::Pixelcade(struct sp_port* pSerialPort, int width, int height) +PixelcadeDMD::PixelcadeDMD(struct sp_port* pSerialPort, int width, int height) { m_pSerialPort = pSerialPort; m_width = width; @@ -28,7 +28,7 @@ Pixelcade::Pixelcade(struct sp_port* pSerialPort, int width, int height) Run(); } -Pixelcade::~Pixelcade() +PixelcadeDMD::~PixelcadeDMD() { if (m_pThread) { @@ -46,17 +46,17 @@ Pixelcade::~Pixelcade() } } -Pixelcade* Pixelcade::Connect(const char* pDevice, int width, int height) +PixelcadeDMD* PixelcadeDMD::Connect(const char* pDevice, int width, int height) { - Pixelcade* pPixelcade = nullptr; + PixelcadeDMD* pPixelcadeDMD = nullptr; if (pDevice && *pDevice != 0) { Log("Connecting to Pixelcade on %s...", pDevice); - pPixelcade = Open(pDevice, width, height); + pPixelcadeDMD = Open(pDevice, width, height); - if (!pPixelcade) Log("Unable to connect to Pixelcade on %s", pDevice); + if (!pPixelcadeDMD) Log("Unable to connect to Pixelcade on %s", pDevice); } else { @@ -68,19 +68,19 @@ Pixelcade* Pixelcade::Connect(const char* pDevice, int width, int height) { for (int i = 0; ppPorts[i]; i++) { - pPixelcade = Open(sp_get_port_name(ppPorts[i]), width, height); - if (pPixelcade) break; + pPixelcadeDMD = Open(sp_get_port_name(ppPorts[i]), width, height); + if (pPixelcadeDMD) break; } sp_free_port_list(ppPorts); } - if (!pPixelcade) Log("Unable to find Pixelcade"); + if (!pPixelcadeDMD) Log("Unable to find Pixelcade"); } - return pPixelcade; + return pPixelcadeDMD; } -Pixelcade* Pixelcade::Open(const char* pDevice, int width, int height) +PixelcadeDMD* PixelcadeDMD::Open(const char* pDevice, int width, int height) { struct sp_port* pSerialPort = nullptr; enum sp_return result = sp_get_port_by_name(pDevice, &pSerialPort); @@ -115,7 +115,7 @@ Pixelcade* Pixelcade::Open(const char* pDevice, int width, int height) { sp_close(pSerialPort); sp_free_port(pSerialPort); - // Log("Pixelcade: expected new connection to return 0x0, but got 0x%02d", response[0]); + // Log("Pixelcade expected new connection to return 0x0, but got 0x%02d", response[0]); return nullptr; } @@ -123,7 +123,7 @@ Pixelcade* Pixelcade::Open(const char* pDevice, int width, int height) { sp_close(pSerialPort); sp_free_port(pSerialPort); - // Log("Pixelcade: expected magic code to equal IOIO but got %c%c%c%c", response[1], response[2], response[3], + // Log("Pixelcade expected magic code to equal IOIO but got %c%c%c%c", response[1], response[2], response[3], // response[4]); return nullptr; } @@ -140,10 +140,10 @@ Pixelcade* Pixelcade::Open(const char* pDevice, int width, int height) Log("Pixelcade found: device=%s, Hardware ID=%s, Bootloader ID=%s, Firmware=%s", pDevice, hardwareId, bootloaderId, firmware); - return new Pixelcade(pSerialPort, width, height); + return new PixelcadeDMD(pSerialPort, width, height); } -void Pixelcade::Update(uint16_t* pData) +void PixelcadeDMD::Update(uint16_t* pData) { uint16_t* pFrame = (uint16_t*)malloc(m_length * sizeof(uint16_t)); memcpy(pFrame, pData, m_length * sizeof(uint16_t)); @@ -154,14 +154,14 @@ void Pixelcade::Update(uint16_t* pData) } } -void Pixelcade::EnableRgbLedMatrix(int shifterLen32, int rows) +void PixelcadeDMD::EnableRgbLedMatrix(int shifterLen32, int rows) { uint8_t data[2] = {PIXELCADE_COMMAND_RGB_LED_MATRIX_ENABLE, (uint8_t)((shifterLen32 & 0x0F) | ((rows == 8 ? 0 : 1) << 4))}; sp_blocking_write(m_pSerialPort, data, 2, 0); } -void Pixelcade::Run() +void PixelcadeDMD::Run() { if (m_running) return; @@ -170,7 +170,7 @@ void Pixelcade::Run() m_pThread = new std::thread( [this]() { - Log("Pixelcade run thread starting"); + Log("PixelcadeDMD run thread starting"); EnableRgbLedMatrix(4, 16); int errors = 0; @@ -255,7 +255,7 @@ void Pixelcade::Run() m_pSerialPort = nullptr; - Log("Pixelcade run thread finished"); + Log("PixelcadeDMD run thread finished"); }); } diff --git a/src/Pixelcade.h b/src/PixelcadeDMD.h similarity index 76% rename from src/Pixelcade.h rename to src/PixelcadeDMD.h index 9a1b17c..f78e817 100644 --- a/src/Pixelcade.h +++ b/src/PixelcadeDMD.h @@ -24,17 +24,17 @@ namespace DMDUtil { -class Pixelcade +class PixelcadeDMD { public: - Pixelcade(struct sp_port* pSerialPort, int width, int height); - ~Pixelcade(); + PixelcadeDMD(struct sp_port* pSerialPort, int width, int height); + ~PixelcadeDMD(); - static Pixelcade* Connect(const char* pDevice, int width, int height); + static PixelcadeDMD* Connect(const char* pDevice, int width, int height); void Update(uint16_t* pData); private: - static Pixelcade* Open(const char* pDevice, int width, int height); + static PixelcadeDMD* Open(const char* pDevice, int width, int height); void Run(); void EnableRgbLedMatrix(int shifterLen32, int rows); diff --git a/src/VirtualDMD.cpp b/src/VirtualDMD.cpp new file mode 100644 index 0000000..1e3bf01 --- /dev/null +++ b/src/VirtualDMD.cpp @@ -0,0 +1,56 @@ +#include "DMDUtil/VirtualDMD.h" + +#include +#include +#include + +namespace DMDUtil +{ + +VirtualDMD::VirtualDMD(int width, int height) +{ + m_width = width; + m_height = height; + m_length = width * height; + m_pitch = width * 3; + + m_pLevelData = (uint8_t*)malloc(m_length); + memset(m_pLevelData, 0, m_length); + + m_pRGB24Data = (uint8_t*)malloc(m_length * 3); + memset(m_pRGB24Data, 0, m_length * 3); + + m_update = false; +} + +VirtualDMD::~VirtualDMD() +{ + free(m_pLevelData); + free(m_pRGB24Data); +} + +void VirtualDMD::Update(uint8_t* pLevelData, uint8_t* pRGB24Data) +{ + memcpy(m_pLevelData, pLevelData, m_length); + memcpy(m_pRGB24Data, pRGB24Data, m_length * 3); + + m_update = true; +} + +uint8_t* VirtualDMD::GetLevelData() +{ + if (!m_update) return nullptr; + + m_update = false; + return m_pLevelData; +} + +uint8_t* VirtualDMD::GetRGB24Data() +{ + if (!m_update) return nullptr; + + m_update = false; + return m_pRGB24Data; +} + +} // namespace DMDUtil \ No newline at end of file