Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
253c6f1
use a sparse vector for color rotations to reduce memory usage
mkalkbrenner Apr 18, 2025
b4eed38
fixed ac_pos_in_file
mkalkbrenner Apr 18, 2025
49b0b4d
fixed formatting
mkalkbrenner Apr 19, 2025
74cc11c
simplified code and usage
mkalkbrenner Apr 19, 2025
cd62677
handle dynamasks, framesprites, framespriteBB, backgroundmask
mkalkbrenner Apr 19, 2025
85b3aa5
fixed some compile errors
mkalkbrenner Apr 19, 2025
1d38023
moced sparsevector to a header file
mkalkbrenner Apr 20, 2025
1ea1f34
formatting
mkalkbrenner Apr 20, 2025
d6d2575
formatting
mkalkbrenner Apr 20, 2025
2382990
formatting
mkalkbrenner Apr 20, 2025
38e1959
formatting
mkalkbrenner Apr 20, 2025
871c3da
formatting
mkalkbrenner Apr 20, 2025
1d9647e
accept parent SparseVector to detect valid values, prepared compression
mkalkbrenner Apr 21, 2025
d146ab6
fixed template U
mkalkbrenner Apr 21, 2025
6d930de
removed redundant miniz
mkalkbrenner Apr 21, 2025
5d8b939
fixed type cast
mkalkbrenner Apr 21, 2025
b489322
refactored SparseVector
mkalkbrenner Apr 23, 2025
c8dbf26
disabled compression
mkalkbrenner Apr 23, 2025
3f2b72a
e SparseVector for TriggerIDs
mkalkbrenner Apr 23, 2025
4461630
more SparseVectors
mkalkbrenner Apr 23, 2025
44b78bd
avoid some memsets
mkalkbrenner Apr 23, 2025
c9ff092
use SparseVector for cnframes, bugfixes
mkalkbrenner Apr 23, 2025
a4d3786
only load extra famre data if extra frames are requested
mkalkbrenner Apr 23, 2025
c46454f
updated README
mkalkbrenner Apr 23, 2025
0e90728
concentrate version numbers
mkalkbrenner Apr 23, 2025
25e9e0f
fixed CMakeList
mkalkbrenner Apr 23, 2025
677fbe5
macOs packaging
mkalkbrenner Apr 23, 2025
7081833
fixed output
mkalkbrenner Apr 23, 2025
f741cf5
Update README.md
mkalkbrenner Apr 23, 2025
fe54a76
more SparseVectors, fixed loading in case extra resolution is not req…
mkalkbrenner Apr 24, 2025
8e5e8ca
SparseVector for v1 colorrotations
mkalkbrenner Apr 24, 2025
56abc67
fixed color rotations in SD only mode
mkalkbrenner Apr 24, 2025
7f46cf2
optimizations for v1
mkalkbrenner Apr 24, 2025
6840e02
removed compression support in SparseVector
mkalkbrenner Apr 24, 2025
39706cc
fixed index handling in SparseVector
mkalkbrenner Apr 25, 2025
532064e
fixed dynamic shadows
mkalkbrenner Apr 25, 2025
f7276cd
fixed sgefault in SparseVector index
mkalkbrenner Apr 25, 2025
9f86be9
more robust reading of index from file
mkalkbrenner Apr 25, 2025
a4f91ec
Update README.md
mkalkbrenner Apr 25, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 18 additions & 5 deletions .github/workflows/libserum.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ jobs:
runs-on: ubuntu-latest
outputs:
tag: ${{ steps.version.outputs.tag }}
serumversion: ${{ steps.version.outputs.serumversion }}
steps:
- uses: actions/checkout@v4
with:
Expand All @@ -22,9 +23,21 @@ jobs:
VERSION_MAJOR=$(grep -Eo "SERUM_VERSION_MAJOR\s+[0-9]+" src/serum-version.h | grep -Eo "[0-9]+")
VERSION_MINOR=$(grep -Eo "SERUM_VERSION_MINOR\s+[0-9]+" src/serum-version.h | grep -Eo "[0-9]+")
VERSION_PATCH=$(grep -Eo "SERUM_VERSION_PATCH\s+[0-9]+" src/serum-version.h | grep -Eo "[0-9]+")
TAG="${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}"
VERSION_CONCENTRATE=$(grep -Eo "SERUM_CONCENTRATE_VERSION\s+[0-9]+" src/serum-version.h | grep -Eo "[0-9]+")
SERUM_VERSION="${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}"
TAG="${SERUM_VERSION}-concentrate.${VERSION_CONCENTRATE}"
echo "${TAG}"
echo "tag=${TAG}" >> $GITHUB_OUTPUT
echo "serumversion=${SERUM_VERSION}" >> $GITHUB_OUTPUT
- name: Check git tag
if: startsWith(github.ref, 'refs/tags/v')
run: |
GIT_TAG="${GITHUB_REF#refs/tags/}"
EXPECTED_TAG="v${{ steps.version.outputs.tag }}"
if [[ "${GIT_TAG}" != "${EXPECTED_TAG}" ]]; then
echo "Error: Git tag (${GIT_TAG}) does not match version from serum-version.h (v${{ steps.version.outputs.tag }})"
exit 1
fi

build:
name: Build libserum-${{ matrix.platform }}-${{ matrix.arch }}
Expand Down Expand Up @@ -73,7 +86,7 @@ jobs:
if [[ "${{ matrix.arch }}" == "x86" ]]; then
cmake -G "Visual Studio 17 2022" -A Win32 -DPLATFORM=${{ matrix.platform }} -DARCH=${{ matrix.arch }} -B build
else
cmake -G "Visual Studio 17 2022" -DPLATFORM=${{ matrix.platform }} -DARCH=${{ matrix.arch }} -B build
cmake -G "Visual Studio 17 2022" -DPLATFORM=${{ matrix.platform }} -DARCH=${{ matrix.arch }} -B build
fi
cmake --build build --config Release
else
Expand Down Expand Up @@ -138,7 +151,7 @@ jobs:
cd tmp
tar -czvf ../${ARTIFACT_PATH} *
fi
echo "artifact_path=${ARTIFACT_PATH}" >> $GITHUB_OUTPUT
echo "artifact_path=${ARTIFACT_PATH}" >> $GITHUB_OUTPUT
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
Expand All @@ -162,8 +175,8 @@ jobs:
run: |
mkdir tmp
lipo -create -output tmp/libserum-${{ needs.version.outputs.tag }}.dylib \
libserum-${{ needs.version.outputs.tag }}-macos-arm64/libserum.${{ needs.version.outputs.tag }}.dylib \
libserum-${{ needs.version.outputs.tag }}-macos-x64/libserum.${{ needs.version.outputs.tag }}.dylib
libserum-${{ needs.version.outputs.tag }}-macos-arm64/libserum.${{ needs.version.outputs.serumversion }}.dylib \
libserum-${{ needs.version.outputs.tag }}-macos-x64/libserum.${{ needs.version.outputs.serumversion }}.dylib
lipo -create -output tmp/serum_test \
libserum-${{ needs.version.outputs.tag }}-macos-arm64/serum_test \
libserum-${{ needs.version.outputs.tag }}-macos-x64/serum_test
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/build/
/.vs/
/.vscode/
/out/
CMakeSettings.json
4 changes: 3 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,11 @@ string(REGEX MATCH "SERUM_VERSION_MINOR[ ]+([0-9]+)" _tmp ${version})
set(VERSION_MINOR "${CMAKE_MATCH_1}")
string(REGEX MATCH "SERUM_VERSION_PATCH[ ]+([0-9]+)" _tmp ${version})
set(VERSION_PATCH "${CMAKE_MATCH_1}")
string(REGEX MATCH "SERUM_CONCENTRATE_VERSION[ ]+([0-9]+)" _tmp ${version})
set(VERSION_CONCENTRATE "${CMAKE_MATCH_1}")

project(serum VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}"
DESCRIPTION "Cross-platform library for decoding Serum files, a colorization format for pinball ROMs.")
DESCRIPTION "Cross-platform library for decoding Serum files, a colorization format for pinball ROMs. Concentrate version: ${VERSION_CONCENTRATE}")

if(PLATFORM STREQUAL "win")
if(ARCH STREQUAL "x86")
Expand Down
166 changes: 10 additions & 156 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,159 +1,13 @@
# libserum
This is a cross-platform library for decoding Serum files, a colorization format for pinball ROMs.
# libserum (concentrate)
This is a (friendly) fork of [libserum](https://github.com/zesinger/libserum), the great cross-platform library for decoding Serum files, a colorization format for pinball ROMs, created and maintained by [Zed](https://github.com/zesinger).

Thanks to Markus Kalkbrenner for all the Github stuff I am not very good at and the tests on other platforms than Windows.
While the main development still happens in libserum itself, libserum (concentrate) is a drop-in replacement, especially for low-memory devices like mobile devices, VR headsets or real pinball machines.

## Usage ingame
## Disclaimer
The code is a bit more complicated, might not always be up-to-date with the original and might introduce new bugs.
libserum (concentrate) is not meant to replace libserum entirely.

### 1/ Format Description

All the content is memory allocated internally and stored in a structure `Serum_Frame_Struc`.
A pointer to that structure is returned by the `Serum_Load(...)` function. After colorizations and color rotations steps, this structure will provide the needed data to update your display.

Here is the description of this structure defined in `serum.h`, the not documented lines are used internally:
```
typedef struct _Serum_Frame_Struc
{
// data for v1 Serum format
uint8_t* frame; // return the colorized frame
uint8_t* palette; // and its palette
uint8_t* rotations; // and its color rotations
// data for v2 Serum format
// the frame (frame32 or frame64) corresponding to the resolution of the ROM must ALWAYS be defined
// if a frame pointer is defined, its width, rotations and rotationsinframe pointers must be defined
uint16_t* frame32;
uint32_t width32; // 0 is returned if the 32p colorized frame is not available for this frame
uint16_t* rotations32;
uint16_t* rotationsinframe32; // [width32*32*2] precalculated array to tell if a color is in a color rotations of the frame ([X*Y*0]=0xffff if not part of a rotation)
uint8_t* modifiedelements32; // (optional) 32P pixels modified during the last rotation
uint16_t* frame64;
uint32_t width64; // 0 is returned if the 64p colorized frame is not available for this frame
uint16_t* rotations64;
uint16_t* rotationsinframe64; // [width64*64*2] precalculated array to tell if a color is in a color rotations of the frame ([X*Y*0]=0xffff if not part of a rotation)
uint8_t* modifiedelements64; // (optional) 64P pixels modified during the last rotation
// common data
uint32_t SerumVersion; // SERUM_V1 or SERUM_V2
/// <summary>
/// flags for v2 return:
/// if flags & 1 : frame32 has been filled
/// if flags & 2 : frame64 has been filled
/// if none of them, display the original frame
/// </summary>
uint8_t flags;
uint32_t nocolors; // number of shades of orange in the ROM
uint32_t ntriggers; // number of triggers in the Serum file
uint32_t triggerID; // return 0xffff if no trigger for that frame, the ID of the trigger if one is set for that frame
uint32_t frameID; // for CDMD ingame tester
uint32_t rotationtimer;
}Serum_Frame_Struc;

```

### 2/ Code example

There is a minimal code example with information on how to use the returned data given here:
https://github.com/zesinger/libserum/blob/main/Minimal-code-example.md

## License
The code in this directory and all sub-directories is licenced under **GPLv2+** with only a restriction on names (see below), except if a different license is
mentioned in a file's header or in a sub-directory. Be aware of the fact that your own enhancements of libserum need to
be licenced under a compatible licence.

Any code, device or whatever linked to libserum or using the file format it defines, must provide a link to https://github.com/zesinger/libserum in its description.
If you find issues within libserum or have ideas for enhancements, we encourage you to contribute to libserum by creating PRs (GitHub Pull Requests) instead of maintaining your own copy.

Due to complicated dependency management on different platforms, these libraries are included as source code copy:
* [miniz](https://github.com/richgel999/miniz)

## Compiling

#### Windows (x64)
Use Visual Studio.

or

```shell
cmake -G "Visual Studio 17 2022" -DPLATFORM=win -DARCH=x64 -B build
cmake --build build --config Release
```

#### Windows (x86)
Use Visual Studio.

or

```shell
cmake -G "Visual Studio 17 2022" -A Win32 -DPLATFORM=win -DARCH=x86 -B build
cmake --build build --config Release
```

#### Linux (x64)
```shell
cmake -DPLATFORM=linux -DARCH=x64 -DCMAKE_BUILD_TYPE=Release -B build
cmake --build build
```

#### Linux (aarch64)
```shell
cmake -DPLATFORM=linux -DARCH=aarch64 -DCMAKE_BUILD_TYPE=Release -B build
cmake --build build
```

#### MacOS (arm64)
```shell
cmake -DPLATFORM=macos -DARCH=arm64 -DCMAKE_BUILD_TYPE=Release -B build
cmake --build build
```

#### MacOS (x64)
```shell
cmake -DPLATFORM=macos -DARCH=arm64 -DCMAKE_BUILD_TYPE=Release -B build
cmake --build build
```

#### iOS (arm64)
```shell
cmake -DPLATFORM=ios -DARCH=arm64 -DCMAKE_BUILD_TYPE=Release -B build
cmake --build build
```

#### iOS Simulator (arm64)
```shell
cmake -DPLATFORM=ios-simulator -DARCH=arm64 -DCMAKE_BUILD_TYPE=Release -B build
cmake --build build
```

#### tvOS (arm64)
```shell
cmake -DPLATFORM=tvos -DARCH=arm64 -DCMAKE_BUILD_TYPE=Release -B build
cmake --build build
```

#### Android (arm64-v8a)
```shell
cmake -DPLATFORM=android -DARCH=arm64-v8a -DCMAKE_BUILD_TYPE=Release -B build
cmake --build build
```

#### For C# code
If you want to include Serum colorization in your C# project, declare things this way:

```
[DllImport("serum.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern bool Serum_Load(string altcolorpath, string romname,ref int width, ref int height, ref uint nocolors);

[DllImport("serum.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern void Serum_Colorize(Byte[] frame, int width, int height, byte[] palette, byte[] rotations);

[DllImport("serum.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern void Serum_Dispose();
```

Then, to call Serum_Colorize(...):

```
// "frame" is a byte[frame_width * frame_height] containing the PinMame frame
byte[] pal = new byte[64 * 3];
byte[] rotations = new byte[MAX_COLOR_ROTATIONS * 3];
Serum_Colorize(frame, frame_width, frame_height, pal, rotations);
```
## Usage
VPX Standlone and all PPUC projects will now use libserum (concentrate) by default. So you should get it as part of an update.
If you want to use it on Windows in combination with DMDExt, just download the appropriate version of the [latest release](https://github.com/PPUC/libserum_concentrate/releases/latest) and extract serum.dll and/or serum64.dll into your VPinMAME folder.
Don't forget to unblock the DLL(s). DMDext will automatically pick-up and use these DLLs, dynamically replacing the serum.dll enbedded in dmddevice.dll.
Loading