Compare commits

...
57 Commits
Author SHA1 Message Date
dkeruza f677f1cd3f Merge pull request #76 from nadenislamarre/fixevdevarrays
evdev: add array allocation checks on snprintf and for loops
2025-03-29 15:22:39 -04:00
Nicolas Adenis-Lamarre 3cd8e7019f evdev: add array allocation checks on snprintf and for loops
Signed-off-by: Nicolas Adenis-Lamarre <nicolas.adenis.lamarre@gmail.com>
2025-03-26 08:00:31 +01:00
Nicolas Adenis-Lamarre 38643436f2 Revert Reverted reverse axis and shake in evdev.
Signed-off-by: Nicolas Adenis-Lamarre <nicolas.adenis.lamarre@gmail.com>
2025-03-26 07:59:11 +01:00
dkeruza-neo 527bdc418f Fixed LGJ, VT3 and ID4/ID5 JVS passthrough. 2025-03-25 15:36:26 -04:00
Bobby Dilley a3e3f51003 Attempt to fix LGJ with JVS 2025-03-25 18:50:16 +00:00
dkeruza-neo a96b1fcf30 Reverted reverse axis and shake in evdev. 2025-03-13 20:07:29 -04:00
dkeruza-neo 6e751f16f0 Fixed bug in ABC res patch after cleaning up code. 2025-03-09 16:19:41 -04:00
dkeruza-neo 03ccfd3449 Forgot to uncomment code. 2025-03-09 03:42:05 -04:00
dkeruza-neo 4e82f6fdef Again 2025-03-09 01:53:29 -05:00
dkeruza-neo ccf54ab6ad Fix release number? 2025-03-09 01:50:41 -05:00
dkeruza-neo 1fb45a1e5c Fixed autobuild script. 2025-03-09 00:49:25 -05:00
dkeruza-neo 9bbc0f983e Check the changelog. 2025-03-09 00:44:55 -05:00
dkeruza cc500aa7ef Merge pull request #62 from nadenislamarre/evdev-keys
evdev: add technical input values
2025-03-08 16:00:54 -05:00
dkeruza cafd6276c3 Workaround 6 2025-02-27 16:26:25 -05:00
dkeruza a2dbf1cbda Workaround 5 2025-02-27 15:43:56 -05:00
dkeruza 74d61985ec Workaround 4 2025-02-27 15:41:17 -05:00
dkeruza 4d0996b905 Workaround 3 2025-02-27 15:29:33 -05:00
dkeruza 52cb3eaf6b Workaround 2 2025-02-27 14:42:30 -05:00
dkeruza 8b6604efc5 Workaround - Ups2 2025-02-27 00:13:27 -05:00
dkeruza 7b426f0d11 Workaround - Ups 2025-02-27 00:11:06 -05:00
dkeruza 442d03b144 Update lindbergh.cWorkaround 2025-02-26 22:14:11 -05:00
dkeruza 50a1a35f7f Workaround 2025-02-26 22:05:53 -05:00
dkeruza 728c308835 Workaround 2025-02-17 22:14:12 -05:00
dkeruza 543ebe4817 Workaround 2025-02-17 22:12:40 -05:00
dkeruza 3c3f0f5eb5 Update ci.yml 2025-02-03 16:05:21 -05:00
dkeruza-neo fe2c749bb0 Fixes. Added ELF clean checker. 2025-02-02 17:51:24 +01:00
Nicolas Adenis-Lamarre 1f20a51aba evdev: add abs to key mapping
Signed-off-by: Nicolas Adenis-Lamarre <nicolas.adenis.lamarre@gmail.com>
2025-02-01 10:24:22 +01:00
Bobby Dilley d3e6027139 Update guide.md 2025-01-28 17:42:07 +00:00
Bobby Dilley 565a9208b7 Update guide.md 2025-01-28 15:36:05 +00:00
Bobby Dilley be78a23a31 Make dkeruza happy 2025-01-28 15:24:06 +00:00
Bobby Dilley 8942c510ec Look for /dev/dsp and /dev/dsp1 2025-01-28 10:45:35 +00:00
Bobby Dilley 685d569a08 Remove not needed message 2025-01-28 10:16:06 +00:00
Bobby Dilley 5f19cdc44c Fix wrong error message 2025-01-28 10:11:55 +00:00
Bobby Dilley be1b88b92f Merge remote-tracking branch 'caviar/master' 2025-01-28 10:01:27 +00:00
Nicolas Adenis-Lamarre 8347b61468 evdev: add shake special event
Signed-off-by: Nicolas Adenis-Lamarre <nicolas.adenis.lamarre@gmail.com>
2025-01-27 21:47:52 +01:00
dkeruza-neo 93927ef8c9 Fixes and ID5 SBRY support. 2025-01-27 15:09:52 +01:00
dkeruza-neo f67f30cbcd Fixed a bug in LGJ when GPU was nVidia and Mesa was set as shader patches. 2025-01-26 03:58:41 +01:00
dkeruza-neo 7ea08b3db3 Cleaned up commented code. 2025-01-26 03:58:41 +01:00
dkeruza dde7cc7b56 Update lindbergh.conf
typo
2025-01-25 00:29:58 +01:00
Nicolas Adenis-Lamarre 3642e2392b evdev: add technical input values
Signed-off-by: Nicolas Adenis-Lamarre <nicolas.adenis.lamarre@gmail.com>
2025-01-24 22:35:38 +01:00
dkeruza 6ff5d0b590 Update lindbergh.conf
typo
2025-01-24 10:59:45 +01:00
dkeruza a4cbbdaa97 Update patch.c
typo
2025-01-24 10:58:54 +01:00
dkeruza 2810022d1d Update config.h
typo
2025-01-24 10:53:19 +01:00
dkeruza b092b79331 Update config.c
typo
2025-01-24 10:52:23 +01:00
dkeruza-neo 1068fd5a1e Too many to list here. 2025-01-23 17:04:41 +01:00
Bobby Dilley ae61839826 Merge pull request #53 from Tovarichtch/dbresgames
add native resolution to games
2025-01-23 09:29:02 +00:00
Bobby Dilley 5786cdc37d Merge pull request #58 from lindbergh-loader/bobbydilley-patch-1
Update ci.yml
2025-01-16 10:37:32 +00:00
Bobby Dilley 5f90591690 Update ci.yml 2025-01-16 10:36:59 +00:00
Tovarichtch 9ee32e1fb0 ABC SDX was 16:9
https://www.gamoover.net/Forums/index.php?topic=44545.0
2025-01-13 22:18:05 -05:00
Tovarichtch 00a8279ce7 add config width/height 2025-01-13 20:50:55 -05:00
Tovarichtch ab7fbb7d5f ABC SDX
SDX cabinets of After Burner Climax were widescreen, clearly not 640x480. Can't locate native resolution.
2025-01-12 14:54:50 -05:00
Tovarichtch 69c0156e57 add native res to games 2025-01-11 10:39:07 -05:00
Synth_Magic 51eaec106c Do changes as requested 2025-01-10 22:03:06 +08:00
Synth Magic dcae95fe03 rename linux/limits.h to limits.h 2025-01-10 20:54:24 +08:00
Synth_Magic fbc76dfe5e Add config path sepcification 2025-01-10 20:52:07 +08:00
Bobby Dilley a3d476c584 Update ci.yml 2025-01-09 11:34:34 +00:00
Bobby Dilley 6d799d7524 Update ci.yml 2025-01-09 11:30:00 +00:00
50 changed files with 22633 additions and 5043 deletions
-63
View File
@@ -1,63 +0,0 @@
name: Build and Release Lindbergh
on:
push:
branches:
- master
pull_request:
branches:
- master
permissions:
contents: write
jobs:
build-and-release:
runs-on: ubuntu-latest
steps:
# Checkout the repository
- name: Checkout repository
uses: actions/checkout@v3
# Set up Docker Buildx
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
# Build the Docker image
- name: Build Docker image
run: |
docker build --target lindbergh-build -t lindbergh-loader .
- name: Extract build artifacts
run: |
docker create --name lindbergh-builder lindbergh-loader
docker cp lindbergh-builder:/output ./build
docker rm lindbergh-builder
- name: Archive build directory
uses: actions/upload-artifact@v3
with:
name: build-output
path: ./build
# Create a GitHub release and upload the artifact
- name: Create Release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: v${{ github.run_number }}
release_name: "Build v${{ github.run_number }}"
draft: false
prerelease: false
- name: Upload Release Asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./build
asset_name: build.tar.gz
asset_content_type: application/gzip
+44
View File
@@ -0,0 +1,44 @@
name: 📦 Linux Flatpak
on:
workflow_call:
workflow_dispatch:
jobs:
linux-flatpak-build:
name: "Build"
runs-on: ubuntu-latest
container:
image: ghcr.io/flathub-infra/flatpak-github-actions:kde-6.8
options: --privileged
timeout-minutes: 60
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
set-safe-directory: ${{ env.GITHUB_WORKSPACE }}
# Work around container ownership issue
- name: Set Safe Directory
shell: bash
run: git config --global --add safe.directory "*"
- name: Build Flatpak
uses: flathub-infra/flatpak-github-actions/flatpak-builder@master
with:
bundle: lindbergh-loader.flatpak
upload-artifact: false
manifest-path: scripts/flatpak/com.github.lindberghloader.yml
build-bundle: true
verbose: true
branch: stable
cache: true
restore-cache: true
cache-key: flatpak-${{ hashFiles('scripts/flatpak/*.yaml') }}
- name: Upload Flatpak
uses: actions/upload-artifact@v4
with:
name: "linux-flatpak"
path: "lindbergh-loader.flatpak"
+45
View File
@@ -0,0 +1,45 @@
name: Build and Release Lindbergh
on:
workflow_call:
workflow_dispatch:
permissions:
contents: write
jobs:
build-and-release:
runs-on: ubuntu-latest
steps:
# Checkout the repository
- name: Checkout repository
uses: actions/checkout@v3
# Set up Docker Buildx
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
# Build the Docker image
- name: Build Docker image
run: |
docker build --target lindbergh-build -t lindbergh-loader .
# Extract build artifacts
- name: Extract build artifacts
run: |
docker create --name lindbergh-builder lindbergh-loader
docker cp lindbergh-builder:/output ./build
docker rm lindbergh-builder
# Compress the build directory
- name: Compress build directory
run: tar -czvf build.tar.gz -C ./build .
# Archive the build directory as an artifact for debugging
- name: Archive build directory
uses: actions/upload-artifact@v4
with:
name: linux-build
path: build.tar.gz
+53
View File
@@ -0,0 +1,53 @@
name: Automated Builds
on:
workflow_dispatch:
pull_request:
paths-ignore:
- '**.md'
- '.github/ISSUE_TEMPLATE/*'
push:
branches:
- master
paths-ignore:
- '**.md'
- '.github/ISSUE_TEMPLATE/*'
jobs:
linux-build:
name: 💻 Linux
uses: "./.github/workflows/linux-build.yml"
linux-flatpak:
name: 📦 Linux Flatpak
uses: "./.github/workflows/flatpak-build.yml"
create-release:
name: 📤 Create Release
needs: [linux-build, linux-flatpak]
runs-on: ubuntu-22.04
if: github.ref == 'refs/heads/master'
steps:
- name: Download Artifacts
uses: actions/download-artifact@v4
with:
path: ./artifacts/
- name: Display Downloaded Artifacts
run: find ./artifacts/
- name: Add 161 to github.run_number
run: |
NEW_RUN_NUMBER=$(( ${{ github.run_number }} + 161 ))
echo "NEW_RUN_NUMBER=$NEW_RUN_NUMBER" >> $GITHUB_ENV
- name: Create Preview Release
if: github.ref == 'refs/heads/master'
uses: "marvinpinto/action-automatic-releases@latest"
with:
repo_token: "${{ secrets.GITHUB_TOKEN }}"
automatic_release_tag: v${{ env.NEW_RUN_NUMBER }}
prerelease: false
title: "Build v${{ env.NEW_RUN_NUMBER }}"
files: |
./artifacts/linux-flatpak/lindbergh-loader.flatpak
./artifacts/linux-build/build.tar.gz
+21 -9
View File
@@ -1,7 +1,8 @@
CC = gcc -m32 -pthread
CFLAGS = -g -fPIC -m32 -Wall -Werror -Wno-unused-but-set-variable -Wno-unused-variable -Wno-unused-function -D_GNU_SOURCE -Wno-char-subscripts
LD = gcc -m32
LDFLAGS = -Wl,-z,defs -rdynamic -static-libgcc -lc -ldl -lGL -lglut -lX11 -lSDL2 -lm -lpthread -shared -nostdlib -lasound -L./src/libxdiff -lxdiff
CC ?= gcc
CFLAGS = -g -fPIC -m32 -pthread -Wall -Werror -Wno-misleading-indentation -Wno-unused-but-set-variable -Wno-unused-variable -Wno-unused-function -D_GNU_SOURCE -Wno-char-subscripts
CXX ?= g++
LD = $(CXX)
LDFLAGS = -m32 -Wl,-z,defs -rdynamic -static-libgcc -lc -ldl -lGL -lglut -lX11 -lXcursor -lSDL2 -lm -lpthread -shared -nostdlib -lasound -L./src/libxdiff -lxdiff -L/app/lib32
BUILD = build
@@ -17,14 +18,14 @@ all: lindbergh libxdiff.a lindbergh.so libsegaapi.so libkswapapi.so libposixtime
lindbergh: src/lindbergh/lindbergh.c src/lindbergh/log.c src/lindbergh/log.h src/lindbergh/jvs.c src/lindbergh/jvs.h src/lindbergh/config.h src/lindbergh/config.c src/lindbergh/evdevinput.h src/lindbergh/evdevinput.c
mkdir -p $(BUILD)
$(CC) src/lindbergh/lindbergh.c src/lindbergh/log.h src/lindbergh/log.c src/lindbergh/jvs.h src/lindbergh/jvs.c src/lindbergh/config.h src/lindbergh/config.c src/lindbergh/evdevinput.c src/lindbergh/evdevinput.h -o $(BUILD)/lindbergh -lm
$(CC) -m32 src/lindbergh/lindbergh.c src/lindbergh/log.h src/lindbergh/log.c src/lindbergh/jvs.h src/lindbergh/jvs.c src/lindbergh/config.h src/lindbergh/config.c src/lindbergh/evdevinput.c src/lindbergh/evdevinput.h -o $(BUILD)/lindbergh -lm
libxdiff.a: $(XDIFF_OBJS)
mkdir -p $(BUILD)
ar rcs src/libxdiff/libxdiff.a $(XDIFF_OBJS)
src/libxdiff/xdiff/%.o: src/libxdiff/xdiff/%.c
$(CC) -DHAVE_CONFIG_H -fPIC -c $< -o $@
$(CC) -m32 -DHAVE_CONFIG_H -fPIC -c $< -o $@
lindbergh.so: $(OBJS)
mkdir -p $(BUILD)
@@ -34,18 +35,29 @@ lindbergh.so: $(OBJS)
$(CC) $(CFLAGS) -c $< -o $@
libsegaapi.so: src/libsegaapi/libsegaapi.o
gcc -m32 -O0 -g src/libsegaapi/libsegaapi.c -lFAudio -fPIC -shared -o $(BUILD)/libsegaapi.so
$(CC) -m32 -O0 -g src/libsegaapi/libsegaapi.c -lFAudio -L/app/lib32 -fPIC -shared -o $(BUILD)/libsegaapi.so
libkswapapi.so: src/libkswapapi/libkswapapi.o
$(CC) src/libkswapapi/libkswapapi.o -fPIC -shared -o $(BUILD)/libkswapapi.so
$(CC) -m32 src/libkswapapi/libkswapapi.o -fPIC -shared -o $(BUILD)/libkswapapi.so
libposixtime.so:
$(CC) src/libposixtime/libposixtime.c src/libposixtime/libposixtime.h -m32 -shared -o $(BUILD)/libposixtime.so
$(CC) -m32 src/libposixtime/libposixtime.c src/libposixtime/libposixtime.h -m32 -shared -o $(BUILD)/libposixtime.so
ln -s -f libposixtime.so $(BUILD)/libposixtime.so.1
ln -s -f libposixtime.so $(BUILD)/libposixtime.so.2.4
# Clean rule
clean:
rm -f $(BUILD)/lindbergh.so
rm -f $(BUILD)/libsegaapi.so
rm -f $(BUILD)/lindbergh
rm -f src/lindbergh/*.o
rm -f src/libsegaapi/*.o
#clean all rule
cleanall:
rm -rf $(BUILD)
rm -f src/lindbergh/*.o
rm -f src/libsegaapi/*.o
rm -f src/libkswapapi/*.o
rm -f src/libxdiff/*.a
rm -f src/libxdiff/xdiff/*.o
+64
View File
@@ -0,0 +1,64 @@
# Changelog
All notable changes to this project will be documented in this file.
## [2.0.5]
### Fixed
- Fixed LGJ, VT3 and ID4/ID5 JVS passthrough.
## [2.0.4]
### Added
- Boost render res option for Rambo, LGJ, HOD4, HOD-EX, ID4/ID5, 2Spicy and Harley.
- Flatpak build as a bundle. (For installation, read the guide in docs folder.)
- Add COINS with evdev for player 2.
- Merged code that adds support for COINS with evdev.
- Makefile, lindbergh.c and shader_patches.c changes to support Flatpak.
- "--zink" option in lindbergh elf to run the games using Zink.
- "--nvidia" option in lindbergh elf to force the secondary nVidia GPU in laptops.
- Click and drag in PH touchscreen.
- Hide custom crosshair cursor in PH when not needed.
- Custom mouse cursors working with X11, GLX and Glut.
- Custom mouse cursor in Primeval Hunt TouchScreen.
- TouchScreen emulation fro Primeval Hunt
- Display a warning if the distro you are running is not based on Debian.
- Cleaned up most of the code changing Ifs to Switch and sorting Alphabetically.
- Let's go Jungle and Let's go Jungle Special resolution patches.
## [2.0.3] 2025-02-02
### Added
- Display a warning when loading an Elf that is not clean.
- Added to the lib folder, common libraries that are usually missing.
### Fixed
- Missing patch in HOD-EX.
- Alows to run a game that does not support Card reader if option enabled in conf file.
## [2.0.2] 2025-01-27
### Added
- InitialD 5 SBRY added.
- HOD4 SP CPU Frequency fix.
### Fixed
- Fixed a bug when a game uses GLUT and the conf was set to NO_SDL 1
- Fixed a bug in Let's go Jungle when GPU was nVidia and Mesa was set as shader patches.
- Exclude resolution patches when the resolution is the game's original resolution.
- Reload with Right mouse click for Rambo and 2Spicy with SDL.
### [2.0.1] 2025-01-23
### Added
- HOD4 Custom crosshair.
- HOD4 CPU frequency fix (Configurable via config file).
- HOD4 New resolution patch that fixes Boss battle and scales from 1280x768 instead of the lower resolution.
- Built in Logos and fonts (no more nee to use Lucida/SEGA_KakuGothic-DB-Roman_12 and logo.tga).
- Outrun 2 Easy network config from the conf file (can set your IP address in the config file and the loader will set it in the eeprom for you).
- Card Emulation for VT3 and R-tuned.
- All the now games work inside an SDL window now, unless it is disabled in the conf file.
## [2.0] - 2024-12-24
### Initial Release
- First official public release.
- Features of the loader:
- Dynamic shader modification allowing games to work on Intel, nVidia and AMD
- 5.1 Surround Sound Support
- Dynamic resolution patching allowing most games to scale properly in HD
- Original cabinet support with pass through of JVS and FFB
- Network play
- Both simple X11 and advanced evdev input system allowing for ready-to-play keyboard and mouse support or mapping of any controller
+129 -25
View File
@@ -4,31 +4,67 @@
The follow list of games are supported. It is worth noting that there are multiple releases of these games, and some specific releases may not be supported.
| Game Name | Game ID | DVP | NVidia | Intel (Mesa) | AMD (Mesa) | AMD (proprietary) |
|---------------------------------|---------|----------|--------|--------------|------------|-------------------|
| 2 Spicy | SBMV | DVP-0027 | ✓ | ✓ | ✓ | ✓ |
| After Burner Climax | SBLR | DVP-0009 | ✓ | ✓ | ✓ | |
| Ghost Squad Evolution | SBNJ | DVP-0029 | ✓ | ✓ | ✓ | ✓ |
| Harley Davidson | SBRG | DVP-5007 | ✓ | ✓ | ✓ | ✓ |
| Hummer Extreme | SBST | DVP-0079 | ✓ | ✓ | ✓ | ✓ |
| Hummer | SBQN | DVP-0057 | ✓ | ✓ | ✓ | ✓ |
| Let's Go Jungle | SBLU | DVP-0011 | ✓ | ✓ | ✓ | |
| Let's Go Jungle Special | SBNR | DVP-0036 | ✓ | ✓ | ✓ | |
| Outrun 2 SP SDX | SBMB | DVP-0015 | ✓ | ✓ | ✓ | ✓ |
| R-Tuned | SBQW | DVP-0060 | ✓ | ✓ | ✓ | ✓ |
| Race TV | SBPF | DVP-0044 | ✓ | ✓ | ✓ | ✓ |
| Rambo | SBQL | DVP-0069 | ✓ | ✓ | ✓ | ✓ |
| The House of the Dead 4 | SBLC | DVP-0003 | ✓ | ✓ | ✓ | ✓ |
| The House of the Dead 4 Special | SBLS | DVP-0010 | ✓ | ✓ | ✓ | ✓ |
| The House of the Dead Ex | SBRC | DVP-0063 | ✓ | ✓ | ✓ | ✓ |
| Virtua Fighter 5 | SBLM | DVP-0008 | ✓ | ✓ | ✓ | ✓ |
| Virtua Fighter 5 R | SBQU | DVP-5004 | ✓ | ✓ | ✓ | ✓ |
| Virtua Fighter 5 FS | SBUV | DVP-5019 | ✓ | ✓ | ✓ | ✓ |
| Initial D 4 | SBNK | DVP-0030 | ✓ | ✓ | ✓ | ✓ |
| Initial D 5 | SBTS | DVP-0075 | ✓ | ✓ | ✓ | |
| Virtua Tennis 3 | SBKX | DVP-0005 | ✓ | ✓ | ✓ | ✓ |
| Primeval Hunt | SBPP | DVP-0048 | ✓ | ✓ | ✓ | ✓ |
| Game Name | Game ID | DVP | NVidia | Intel (Mesa) | AMD (Mesa) | AMD (proprietary) |
|--------------------------------------------------|---------|-----------|--------|--------------|------------|-------------------|
| After Burner Climax | SBLR | DVP-0009 | ✓ | ✓ | ✓ | |
| After Burner Climax Rev A | SBLR | DVP-0009A | ✓ | ✓ | ✓ | |
| After Burner Climax Rev B | SBLR | DVP-0009B | ✓ | ✓ | ✓ | |
| After Burner Climax SDX | SBMN | DVP-0018 | ✓ | ✓ | ✓ | |
| After Burner Climax SDX Rev A | SBMN | DVP-0018A | ✓ | ✓ | ✓ | |
| After Burner Climax SE | SBLR | DVP-0031 | ✓ | ✓ | ✓ | |
| After Burner Climax SE Rev A | SBLR | DVP-0031A | ✓ | ✓ | ✓ | |
| Ghost Squad Evolution | SBNJ | DVP-0029 | ✓ | ✓ | ✓ | ✓ |
| Harley Davidson | SBRG | DVP-5007 | ✓ | ✓ | ✓ | ✓ |
| Hummer | SBQN | DVP-0057B | ✓ | ✓ | ✓ | ✓ |
| Hummer SDLX | SBST | DVP-0057 | ✓ | ✓ | ✓ | ✓ |
| Hummer Extreme | SBST | DVP-0079 | ✓ | ✓ | ✓ | ✓ |
| Hummer Extreme MDX | SBST | DVP-0083 | ✓ | ✓ | ✓ | ✓ |
| Initial D Arcade Stage 4 Rev A | SBML | DVP-0019A | ✓ | ✓ | ✓ | ✓ |
| Initial D Arcade Stage 4 Rev B | SBML | DVP-0019B | ✓ | ✓ | ✓ | ✓ |
| Initial D Arcade Stage 4 Rev C | SBML | DVP-0019C | ✓ | ✓ | ✓ | ✓ |
| Initial D Arcade Stage 4 Rev D | SBML | DVP-0019D | ✓ | ✓ | ✓ | ✓ |
| Initial D Arcade Stage 4 Rev G | SBML | DVP-0019G | ✓ | ✓ | ✓ | ✓ |
| Initial D Arcade Stage 4 Export Rev B | SBNK | DVP-0030B | ✓ | ✓ | ✓ | ✓ |
| Initial D Arcade Stage 4 Export Rev C | SBNK | DVP-0030C | ✓ | ✓ | ✓ | ✓ |
| Initial D Arcade Stage 4 Export Rev D | SBNK | DVP-0030D | ✓ | ✓ | ✓ | ✓ |
| Initial D 5 EXP | SBRY | DVP-0075 | ✓ | ✓ | ✓ | |
| Initial D 5 EXP 2.0 | SBTS | DVP-0084 | ✓ | ✓ | ✓ | |
| Initial D 5 EXP 2.0 Rev A | SBQN | DVP-0084A | ✓ | ✓ | ✓ | |
| Initial D Arcade Stage 5 Rev A | SBQZ | DVP-0070A | ✓ | ✓ | ✓ | |
| Initial D Arcade Stage 5 Rev F | SBQZ | DVP-0070F | ✓ | ✓ | ✓ | |
| Let's Go Jungle | SBLU | DVP-0011 | ✓ | ✓ | ✓ | |
| Let's Go Jungle! Rev A | SBLU | DVP-0011A | ✓ | ✓ | ✓ | |
| Let's Go Jungle Special | SBNR | DVP-0036 | ✓ | ✓ | ✓ | |
| SEGA Network Taisen Mahjong MJ4 | SBPN | DVP-0049G | ✓ | ✓ | ✓ | ✓ |
| SEGA Network Taisen Mahjong MJ4 Evolution | SBTA | DVP-0081 | ✓ | ✓ | ✓ | ✓ |
| Outrun 2 SP SDX | SBMB | DVP-0015 | ✓ | ✓ | ✓ | ✓ |
| Outrun 2 SP SDX Rev A | SBMB | DVP-0015A | ✓ | ✓ | ✓ | ✓ |
| Primeval Hunt | SBPP | DVP-0048 | ✓ | ✓ | ✓ | ✓ |
| Rambo | SBQL | DVP-0069 | ✓ | ✓ | ✓ | ✓ |
| R-Tuned | SBQW | DVP-0060 | ✓ | ✓ | ✓ | ✓ |
| Sega Race TV | SBPF | DVP-0044 | ✓ | ✓ | ✓ | ✓ |
| The House of the Dead 4 Rev A | SBLC | DVP-0003A | ✓ | ✓ | ✓ | ✓ |
| The House of the Dead 4 Rev B | SBLC | DVP-0003B | ✓ | ✓ | ✓ | ✓ |
| The House of the Dead 4 Rev C | SBLC | DVP-0003C | ✓ | ✓ | ✓ | ✓ |
| The House of the Dead 4 Special | SBLS | DVP-0010 | ✓ | ✓ | ✓ | ✓ |
| The House of the Dead 4 Special Rev B | SBLS | DVP-0010B | ✓ | ✓ | ✓ | ✓ |
| The House of the Dead Ex | SBRC | DVP-0063 | ✓ | ✓ | ✓ | ✓ |
| Too Spicy | SBMV | DVP-0027 | ✓ | ✓ | ✓ | ✓ |
| Virtua Fighter 5 | SBLM | DVP-0008 | ✓ | ✓ | ✓ | ✓ |
| Virtua Fighter 5 Rev A | SBLM | DVP-0008A | ✓ | ✓ | ✓ | ✓ |
| Virtua Fighter 5 Rev B | SBLM | DVP-0008B | ✓ | ✓ | ✓ | ✓ |
| Virtua Fighter 5 Rev E (Public Version C) | SBLM | DVP-0008E | ✓ | ✓ | ✓ | ✓ |
| Virtua Fighter 5 Export | SBLM | DVP-0043 | ✓ | ✓ | ✓ | ✓ |
| Virtua Fighter 5 Final Showdown REV A | SBUV | DVP-5019 | ✓ | ✓ | ✓ | ✓ |
| Virtua Fighter 5 Final Showdown REV B | SBXX | DVP-5020 | ✓ | ✓ | ✓ | ✓ |
| Virtua Fighter 5 Final Showdown REV B ver 6.0000 | SBXX | DVP-5020 | ✓ | ✓ | ✓ | ✓ |
| Virtua Fighter 5 R | SBQU | DVP-5004 | ✓ | ✓ | ✓ | ✓ |
| Virtua Fighter 5 R Rev D | SBQU | DVP-5004D | ✓ | ✓ | ✓ | ✓ |
| Virtua Fighter 5 R Rev G | SBQU | DVP-5004G | ✓ | ✓ | ✓ | ✓ |
| Virtua Tennis 3 | SBKX | DVP-0005 | ✓ | ✓ | ✓ | ✓ |
| Virtua Tennis 3 Rev A | SBKX | DVP-0005A | ✓ | ✓ | ✓ | ✓ |
| Virtua Tennis 3 Rev B | SBKX | DVP-0005B | ✓ | ✓ | ✓ | ✓ |
| Virtua Tennis 3 Rev C | SBKX | DVP-0005C | ✓ | ✓ | ✓ | ✓ |
## Game Issues & Fixes
@@ -54,6 +90,10 @@ sudo ln -s /lib/i386-linux-gnu/libglut.so /lib/i386-linux-gnu/libglut.so.3
- You need to set `SKIP_OUTRUN_CABINET_CHECK` to 1 in `lindbergh.conf` to play in DX, SDX or Standard cabinet types.
### Hummer (all versions)
The games will ask for libGLcore.so.1 and libnvidia-tls.so.1 you can copy for example libkswapapi.so as libGLcore.so.1 and libnvidia-tls.so.1 and the game will work fine.
## Configuration File : lindbergh.conf
All configurable options are set and explained in the [`lindbergh.conf`](lindbergh.conf) file itself, and should be reasonably easy to understand. This chapter further explains some of those setup options.
@@ -120,3 +160,67 @@ Will cause input on analogue input 1 to be clamped as follows:
There are currently no audio options that you can set. If you have a stereo sound card installed then the audio will be downmixed to stereo. If you have a 5.1 sound card installed and the game supports surround sound, each surround channel should be passed through properly and should play sound as it was originally intended.
## Installing and Running the Flatpak
### Prerequisites
Before installing the main package, ensure that Flatpak is set up on your system. If Flatpak is not installed, follow the official [Flatpak setup guide](https://flatpak.org/setup/).
### Installation
Once downloaded, install Lindbergh Loader by running the following command in your terminal:
```
flatpak install lindbergh-loader-dev.flatpak
```
Additionally, install the required dependencies:
```
flatpak install org.freedesktop.Platform.Compat.i386//24.08
flatpak install org.freedesktop.Platform.GL32.default//24.08
```
Intel GPU Users (VAAPI Support):
```
flatpak install org.freedesktop.Platform.VAAPI.Intel.i386//24.08
```
NVIDIA GPU Users (Driver Support):
If your system uses an NVIDIA GPU, you need to install the matching NVIDIA driver package for your system.
To check your NVIDIA driver version, run:
```
nvidia-smi
```
Then, install the corresponding Flatpak package, replacing 570-86-16 with your actual driver version:
```
flatpak install org.freedesktop.Platform.GL32.nvidia-570-86-16
```
### Running Lindbergh Loader
Once installed, launch the application with:
```
flatpak run com.github.lindberghloader.dev
```
### Managing Game Locations
By default, games should be added to:
```
~/Games
```
If you need to add more locations, install Flatseal:
```
flatpak install com.github.tchx84.Flatseal
```
Then, run Flatseal and grant Lindbergh Loader access to additional directories.
+77 -28
View File
@@ -1,5 +1,5 @@
# SEGA Lindbergh Emulator Configuration File
# By the Lindbergh Development Team
# By the Lindbergh Development Team 2024-2025
# Set the requested dip switch width here
WIDTH AUTO
@@ -7,28 +7,31 @@ WIDTH AUTO
# Set the requested dip switch height here
HEIGHT AUTO
# Boost render resolution in HOD4/2Spicy/Harley/Rambo/HOD-EX/ID4/ID5 and LGJ
# BOOST_RENDER_RES 1
# Set if the emulator should go full screen
FULLSCREEN 0
# FULLSCREEN 0
# Sets the Input Mode
# Mode 0: will use both SDL/X11 and EVDEV inputs (default)
# Mode 1: will use SDL/X11 inputs only
# Mode 2: will use EVDEV raw inputs only, which should be configured at the bottom of the settings file
INPUT_MODE 0
# INPUT_MODE 0
# Set to 1 if you want to disable SDL (Fixes SRTV boost bar)
NO_SDL 0
# NO_SDL 0
# Set the Region ( JP/US/EX )
REGION EX
# REGION EX
# Set if you want the game to be Free Play
FREEPLAY 1
# FREEPLAY 1
# Set if the emulator should emulate JVS and use the keyboard/mouse for controls.
# If this is set to 0, then the emulator will route the traffic to the serial device
# defined in JVS_PATH if it has been defined.
EMULATE_JVS 1
# EMULATE_JVS 1
# Set if the emulator should emulate the rideboard used in the special games here
# If this is set to 0, then the emulator will route the traffic to one of the serial ports
@@ -42,72 +45,118 @@ EMULATE_DRIVEBOARD AUTO
# If this is set to 0, then the emulator will route the traffic to one of the serial ports
EMULATE_MOTIONBOARD AUTO
# Set if the loader should emulate the card reader in Virtua Tenis 3
EMULATE_CARDREADER AUTO
# Set to 1 if the loader should emulate the touchscreen with the mouse in PH.
# EMULATE_TOUCHSCREEN 1
# Card File for reader 1
# CARDFILE_01 Card_01.crd
# Card File for reader 2
# CARDFILE_02 Card_02.crd
# Define the path to pass the JVS packets to if JVS is not being emulated.
JVS_PATH /dev/ttyUSB0
# JVS_PATH /dev/ttyUSB0
# Define the path to pass the first serial port to if it's not being emulated.
SERIAL_1_PATH /dev/ttyUSB0
# SERIAL_1_PATH /dev/ttyUSB0
# Define the path to pass the second serial port to if it's not being emulated.
SERIAL_2_PATH /dev/ttyUSB0
# SERIAL_2_PATH /dev/ttyUSB0
# Define the path to the sram.bin file
SRAM_PATH sram.bin
# SRAM_PATH sram.bin
# Define the path to the eeprom.bin file
EEPROM_PATH eeprom.bin
# EEPROM_PATH eeprom.bin
# Set the GPU vendor (0 = Autodetect / 1 = NVidia / 2 = AMD / 3 = ATI(AMD-PRO) / 4 = Intel / 5 = Unknown)
GPU_VENDOR 0
# GPU_VENDOR 0
# Set if you want to see debug messages in the console
DEBUG_MSGS 0
# DEBUG_MSGS 0
# Set if you'd like to add a border for optical light gun tracking
BORDER_ENABLED 0
# BORDER_ENABLED 0
# Set the thickness of the white border as a percentage of the width of the screen
WHITE_BORDER_PERCENTAGE 2
# WHITE_BORDER_PERCENTAGE 2
# Set the thickness of the black border which sits around the
# white border as a percentage of the width of the screen
BLACK_BORDER_PERCENTAGE 0
# BLACK_BORDER_PERCENTAGE 0
# Set to true if you experience flickering in hummer
HUMMER_FLICKER_FIX 0
# HUMMER_FLICKER_FIX 0
# Set to keep the aspect ratio (4:3) in games like Sega Race TV and Primeval Hunt
KEEP_ASPECT_RATIO 0
# KEEP_ASPECT_RATIO 0
# Set to 0 if you want to disable the Glare effect in OutRun
OUTRUN_LENS_GLARE_ENABLED 1
# OUTRUN_LENS_GLARE_ENABLED 1
# Set to 1 to bypass cabinet checks including drive board and tower in Outrun 2 SP SDX
SKIP_OUTRUN_CABINET_CHECK 0
# SKIP_OUTRUN_CABINET_CHECK 0
# Set to 1 if you want to limit the FPS in games that are not limited like OutRun2
FPS_LIMITER_ENABLED 0
# FPS_LIMITER_ENABLED 0
# Set the target FPS (will only work if FPS_LIMITER_ENABLED = 1)
FPS_TARGET 60
# FPS_TARGET 60
# Set to 1 if you want to render LGJ using the mesa patches instead of nVidia (fixes some glitches)
LGJ_RENDER_WITH_MESA 1
# LGJ_RENDER_WITH_MESA 1
# Set the Primeval Hunt mode
# Mode 0: Leaves everything as default
# Mode 1: No touch screen (Default mode)
# Mode 0: Default (Side by Side)
# Mode 1: No touch screen
# Mode 2: Side by Side
# Mode 3: 3ds mode 1 (Touch screen to the right)
# Mode 4: 3ds mode 2 (Touch screen to the bottom)
PRIMEVAL_HUNT_MODE 1
# PRIMEVAL_HUNT_MODE 1
# Disble to use the original fonts instead of the built in font in the loader
# DISABLE_BUILTIN_FONT 0
# Disble to use the original logos instead of the built in logos in the loader
# DISABLE_BUILTIN_LOGOS 0
# Set to 0 to enable the mouse pointer/Cursor
# HIDE_CURSOR 1
# Set the custom mouse pointer from a PNG file (Usefull for shooting games)
# CUSTOM_CURSOR myCustomCursor.png
# Set the width of the custom cursor
# CUSTOM_CURSOR_WIDTH 32
# Set the height of the custom cursor
# CUSTOM_CURSOR_HEIGHT 32
# Set a custom cursor for the touch screen in Primeval Hunt
# PH_TOUCH_CURSOR myCustomHandCursor.png
# Set the width of the custom cursor
# PH_TOUCH_CURSOR_WIDTH 32
# Set the height of the custom cursor
# PH_TOUCH_CURSOR_HEIGHT 32
# Hacky way to make MJ4 work at prohibited times?
# MJ4_ENABLED_ALL_THE_TIME 1
# Sets the IP address in the eeprom for Outrun link (you have to put your NIC ip)
# OR2_IP 192.168.1.2
# OR2_NETMASK 255.255.255.0
# House of the dead 4 speed fix set the frequency of your CPU in Ghz (The speed reported by the manufacturer)
# CPU_FREQ_GHZ 4.0
# Set the colour of the lindbergh to change the Segaboot logo
# Possible colours are: YELLOW, RED, BLUE, SILVER, REDEX
LINDBERGH_COLOUR YELLOW
# LINDBERGH_COLOUR YELLOW
# X11 MODE (Input Mode 1)
# To find the value pairs for these run `xev` on linux
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+4
View File
@@ -0,0 +1,4 @@
.flatpak-builder/
build/
repo/
*.flatpak
+4
View File
@@ -0,0 +1,4 @@
# We just make any GL32 extension have higher priority
include /run/flatpak/ld.so.conf.d/app-*-org.freedesktop.Platform.GL32.*.conf
/app/lib32
/app/lib/i386-linux-gnu
Binary file not shown.
+36
View File
@@ -0,0 +1,36 @@
diff --color -ruN ncurses-5.9.orig/c++/cursesf.h ncurses-5.9/c++/cursesf.h
--- ncurses-5.9.orig/c++/cursesf.h 2005-08-13 20:08:24.000000000 +0200
+++ ncurses-5.9/c++/cursesf.h 2025-02-21 14:45:57.002814632 +0100
@@ -703,7 +703,7 @@
virtual ~NCursesUserForm() {
};
- inline T* UserData (void) const {
+ inline T* UserData (void) {
return reinterpret_cast<T*>(get_user ());
};
diff --color -ruN ncurses-5.9.orig/c++/cursesm.h ncurses-5.9/c++/cursesm.h
--- ncurses-5.9.orig/c++/cursesm.h 2005-08-13 20:10:36.000000000 +0200
+++ ncurses-5.9/c++/cursesm.h 2025-02-21 14:47:21.238076003 +0100
@@ -659,7 +659,7 @@
virtual ~NCursesUserMenu() {
};
- inline T* UserData (void) const {
+ inline T* UserData (void) {
return reinterpret_cast<T*>(get_user ());
};
diff --color -ruN ncurses-5.9.orig/c++/cursesp.h ncurses-5.9/c++/cursesp.h
--- ncurses-5.9.orig/c++/cursesp.h 2008-08-16 19:20:23.000000000 +0200
+++ ncurses-5.9/c++/cursesp.h 2025-02-21 14:45:19.718735744 +0100
@@ -251,7 +251,7 @@
virtual ~NCursesUserPanel() {};
- T* UserData (void) const
+ T* UserData (void)
{
return reinterpret_cast<T*>(get_user ());
};
@@ -0,0 +1,323 @@
app-id: com.github.lindberghloader
runtime: org.freedesktop.Platform
runtime-version: &runtime-version '24.08'
x-gl-version: &gl-version '1.4'
x-gl-versions: &gl-versions 24.08;1.4
x-gl-merge-dirs: &gl-merge-dirs vulkan/icd.d;glvnd/egl_vendor.d;egl/egl_external_platform.d;OpenCL/vendors;lib/dri;lib/d3d;lib/gbm;vulkan/explicit_layer.d;vulkan/implicit_layer.d
sdk: org.freedesktop.Sdk
command: lindbergh
sdk-extensions:
- org.freedesktop.Sdk.Extension.toolchain-i386
- org.freedesktop.Sdk.Compat.i386
x-arch-build-options:
i386: &i386-build-options
libdir: /app/lib32
env:
CC: /usr/lib/sdk/toolchain-i386/bin/i686-unknown-linux-gnu-gcc
CXX: /usr/lib/sdk/toolchain-i386/bin/i686-unknown-linux-gnu-g++
LD: /usr/lib/sdk/toolchain-i386/bin/i686-unknown-linux-gnu-ld
LDFLAGS: "-L/app/lib32"
finish-args:
- --env=LD_LIBRARY_PATH=/app/lib32:$LD_LIBRARY_PATH
- --env=LDFLAGS="-L/app/lib32"
- --env=PATH=/app/bin:/usr/bin
- --allow=multiarch
- --share=ipc
- --share=network
- --socket=x11
- --socket=wayland
- --device=all
- --socket=pulseaudio
- --filesystem=~/Games
add-extensions:
org.freedesktop.Platform.Compat.i386:
directory: lib/i386-linux-gnu
version: *runtime-version
no-autodownload: true
org.freedesktop.Platform.Compat.i386.Debug:
directory: lib/debug/lib/i386-linux-gnu
version: *runtime-version
no-autodownload: true
org.freedesktop.Platform.GL32:
directory: lib/i386-linux-gnu/GL
version: *gl-version
versions: *gl-versions
subdirectories: true
no-autodownload: true
autodelete: false
add-ld-path: lib
merge-dirs: *gl-merge-dirs
download-if: active-gl-driver
enable-if: active-gl-driver
autoprune-unless: active-gl-driver
org.freedesktop.Platform.GL32.Debug:
directory: lib/debug/lib/i386-linux-gnu/GL
version: *gl-version
versions: *gl-versions
subdirectories: true
no-autodownload: true
merge-dirs: *gl-merge-dirs
enable-if: active-gl-driver
autoprune-unless: active-gl-driver
modules:
- name: libstdcxx5
buildsystem: simple
build-commands:
- mkdir -p /app/lib32
- install -Dm644 libstdc++.so.5 /app/lib32/libstdc++.so.5
sources:
- type: file
path: ./assets/libstdc++.so.5
- name: libGLU
buildsystem: autotools
config-opts:
- --host=i686-unknown-linux-gnu
- --prefix=/app
build-options:
arch:
x86_64: *i386-build-options
sources:
- type: archive
url: https://mesa.freedesktop.org/archive/glu/glu-9.0.2.tar.xz
sha256: 6e7280ff585c6a1d9dfcdf2fca489251634b3377bfc33c29e4002466a38d02d4
- name: freeglut
buildsystem: cmake
config-opts:
- -DCMAKE_BUILD_TYPE=Release
- -DCMAKE_INSTALL_PREFIX=/app
sources:
- type: archive
url: https://downloads.sourceforge.net/freeglut/freeglut-3.2.2.tar.gz
sha256: c5944a082df0bba96b5756dddb1f75d0cd72ce27b5395c6c1dde85c2ff297a50
build-options:
arch:
x86_64: *i386-build-options
- name: libFAudio-Dynamic
buildsystem: cmake-ninja
config-opts:
- -DCMAKE_BUILD_TYPE=Release
- -DCMAKE_INSTALL_PREFIX=/app
- -DBUILD_SDL3=off
- -DCMAKE_INSTALL_LIBDIR=/app/lib32
build-options:
arch:
x86_64: *i386-build-options
env:
CFLAGS: "-m32 -mstackrealign"
CXXFLAGS: "-m32 -mstackrealign"
sources:
- type: git
url: https://github.com/FNA-XNA/FAudio.git
tag: "24.12"
- name: libxmu
buildsystem: autotools
config-opts:
- --libdir=/app/lib32
- --with-shared
sources:
- type: archive
url: https://xorg.freedesktop.org/releases/individual/lib/libXmu-1.2.1.tar.gz
sha256: bf0902583dd1123856c11e0a5085bd3c6e9886fbbd44954464975fd7d52eb599
build-options:
# arch:
# x86_64: *i386-build-options
env:
CC: /usr/lib/sdk/toolchain-i386/bin/i686-unknown-linux-gnu-gcc
CXX: /usr/lib/sdk/toolchain-i386/bin/i686-unknown-linux-gnu-g++
LD: /usr/lib/sdk/toolchain-i386/bin/i686-unknown-linux-gnu-ld
libdir: /app/lib32
- name: libmd
buildsystem: autotools
config-opts:
- --libdir=/app/lib32
sources:
- type: archive
url: https://archive.hadrons.org/software/libmd/libmd-1.1.0.tar.xz
sha256: 1bd6aa42275313af3141c7cf2e5b964e8b1fd488025caf2f971f43b00776b332
build-options:
arch:
x86_64: *i386-build-options
- name: libbsd
buildsystem: autotools
config-opts:
- --libdir=/app/lib32
sources:
- type: archive
url: https://libbsd.freedesktop.org/releases/libbsd-0.12.2.tar.xz
sha256: b88cc9163d0c652aaf39a99991d974ddba1c3a9711db8f1b5838af2a14731014
build-options:
arch:
x86_64: *i386-build-options
- name: ncurses
buildsystem: autotools
config-opts:
- --libdir=/app/lib32
- --with-shared
- --without-debug
sources:
- type: archive
url: https://ftp.gnu.org/pub/gnu/ncurses/ncurses-5.9.tar.gz
sha256: 9046298fb440324c9d4135ecea7879ffed8546dd1b58e59430ea07a4633f563b
- type: patch
path: ./assets/ncurses-5.9.patch
build-options:
arch:
x86_64: *i386-build-options
env:
CPPFLAGS: "-P"
CXXFLAGS: "-std=c++14"
- name: nvidia-cg-toolkit
buildsystem: simple
build-commands:
- install -Dm755 usr/lib/libCg.so /app/lib32/libCg.so
- install -Dm755 usr/lib/libCgGL.so /app/lib32/libCgGL.so
sources:
- type: archive
url: http://developer.download.nvidia.com/cg/Cg_3.1/Cg-3.1_April2012_x86.tgz
sha256: cef3591e436f528852db0e8c145d3842f920e0c89bcfb219c466797cb7b18879
- name: libsndio-dynamic
buildsystem: autotools
config-opts:
- --libdir=/app/lib32
- --enable-dynamic
- --enable-alsa
sources:
- type: archive
url: https://www.sndio.org/sndio-1.10.0.tar.gz
sha256: bebd3bfd01c50c9376cf3e7814b9379bed9e17d0393b5113b7eb7a3d0d038c54
build-options:
arch:
x86_64: *i386-build-options
- name: libsndio-static
buildsystem: autotools
config-opts:
- --libdir=/app/lib32
- --enable-static
- --enable-alsa
sources:
- type: archive
url: https://www.sndio.org/sndio-1.10.0.tar.gz
sha256: bebd3bfd01c50c9376cf3e7814b9379bed9e17d0393b5113b7eb7a3d0d038c54
build-options:
arch:
x86_64: *i386-build-options
- name: libopenal
buildsystem: cmake
config-opts:
- -DCMAKE_INSTALL_LIBDIR=/app/lib32
- -DALSOFT_BACKEND_PULSEAUDIO=ON
- -DALSOFT_BACKEND_ALSA=ON
- -DALSOFT_BACKEND_JACK=OFF
- -DALSOFT_BACKEND_SNDIO=ON
- -DSOUNDIO_INCLUDE_DIR=/app/include
- -DSOUNDIO_LIBRARY=/app/lib32/libsndio.so
sources:
- type: archive
url: https://github.com/kcat/openal-soft/archive/refs/tags/openal-soft-1.17.2.tar.gz
sha256: 11ea176f6cbf9763dbce0953dd77ab72d032b4ad95f07afffb91844abb174033
build-options:
arch:
x86_64: *i386-build-options
env:
CFLAGS: "-m32 -mstackrealign"
CXXFLAGS: "-m32 -std=c++14 -mstackrealign"
- name: openssl
buildsystem: simple
build-commands:
- ./Configure --prefix=/app --openssldir=/app/etc/ssl shared 386 no-asm no-krb5 linux-pentium
- make CC=/usr/lib/sdk/toolchain-i386/bin/i686-unknown-linux-gnu-gcc RANLIB=/usr/lib/sdk/toolchain-i386/bin/i686-unknown-linux-gnu-ranlib
- mv libcrypto.* /app/lib32
- mv libssl.* /app/lib32
sources:
- type: archive
url: https://github.com/openssl/openssl/archive/refs/tags/OpenSSL_0_9_7.tar.gz
sha256: 14e3a90f75994689e8c1bef098a97021f225a1a1623a7b8012079bd8b2eca1e8
- name: libpcsclite
buildsystem: meson
config-opts:
- --libdir=/app/lib32
- -Dpolkit=false
- -Dlibsystemd=false
build-options:
arch:
x86_64: *i386-build-options
env:
CFLAGS: "-m32"
CXXFLAGS: "-m32"
LDFLAGS: "-m32"
PKG_CONFIG_PATH: "/app/lib32/pkgconfig:/usr/lib/i386-linux-gnu/pkgconfig"
LD_LIBRARY_PATH: "/app/lib32:/usr/lib/i386-linux-gnu/pkgconfig:$LD_LIBRARY_PATH"
sources:
- type: archive
url: https://pcsclite.apdu.fr/files/pcsc-lite-2.3.1.tar.xz
sha256: a641d44d57affe1edd8365dd75307afc307e7eefb4e7ad839f6f146baa41ed56
- name: lindbergh-loader
buildsystem: simple
build-commands:
- export LD_LIBRARY_PATH=/app/lib32:$LD_LIBRARY_PATH
- make
- mkdir -p /app/bin
- mkdir -p /app/lib/i386-linux-gnu
- mkdir -p /app/lib/i386-linux-gnu/GL
- install -Dm755 ./build/lindbergh /app/bin/
- install -Dm755 ./build/lindbergh.so /app/lib32/
- install -Dm755 ./build/libsegaapi.so /app/lib32/
- install -Dm755 ./build/libkswapapi.so /app/lib32/
- install -Dm755 ./build/libposixtime.so /app/lib32/
- install -Dm755 ./libs/libCg.so /app/lib32/libCg2.so
- ln -s -f libposixtime.so /app/lib32/libposixtime.so.1
- ln -s -f libposixtime.so /app/lib32/libposixtime.so.2.4
- ln -s -f libopenal.so /app/lib32/libopenal.so.0
- ln -s -f libkswapapi.so /app/lib32/libGLcore.so.1
- ln -s -f libkswapapi.so /app/lib32/libnvidia-tls.so.1
- mv /app/lib/libopenal* /app/lib32/
build-options:
arch:
x86_64: *i386-build-options
sources:
- type: dir
path: ../..
- name: bundle-setup
buildsystem: simple
build-commands:
- install -Dm644 -t /app/etc ld.so.conf
sources:
- type: file
path: ./assets/ld.so.conf
- name: cleanup
buildsystem: simple
build-commands:
- find /app/lib /app/lib32 -name '*.a' -type f -delete
- find /app/lib /app/lib32 -name '*.la' -type f -delete
- find /app/bin -mindepth 1 ! -name "lindbergh*" -exec rm -f {} \;
- rm -d /app/lib/terminfo
- rm -rf /app/lib/pkgconfig /app/lib32/pkgconfig /app/share/pkgconfig /app/lib32/cmake /app/lib/debug /app/include /app/man /app/share
- rm /app/lib32/libmenu.*
- rm /app/lib32/libform.*
- rm /app/lib32/libpanel.*
- rm /app/lib32/libXmuu.*
- rm /app/lib32/libbsd.so
+250
View File
@@ -0,0 +1,250 @@
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include "config.h"
#include "card_reader.h"
#define BLOCKSIZE 8
extern uint32_t gId;
uint8_t cardHeader[] = {0x08, 0x00, 0x00, 0x00, 0x81, 0x00, 0x59, 0xda, 0x00, 0x00, 0x54, 0x4d, 0x50, 0x06, 0x03, 0x23, 0x10, 0x41, 0x62,
0xad, 0x00, 0x2b, 0x0b, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0x71, 0x52, 0x70, 0x00, 0x00,
0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfd, 0xd2};
SerialFD serialFD[2];
WriteCommand writeCmd[2];
ReadCommand readCmd[2];
void initReadCmd(int fdIdx)
{
readCmd[fdIdx].cmd = 0;
readCmd[fdIdx].cmdCompleted = false;
readCmd[fdIdx].cmdLen = 0;
readCmd[fdIdx].sentBytes = 0;
memset(&readCmd[fdIdx].sendBuffer, '\0', 256);
}
void initWriteCmd(int fdIdx)
{
writeCmd[fdIdx].cmdCompleted = false;
writeCmd[fdIdx].packetLen = 0;
writeCmd[fdIdx].recBytes = 0;
memset(&writeCmd[fdIdx].recBuffer, '\0', sizeof(uint8_t));
}
int initCardReader()
{
EmulatorConfig *config = getConfig();
switch (gId)
{
case R_TUNED:
case VIRTUA_TENNIS_3:
case VIRTUA_TENNIS_3_TEST:
case VIRTUA_TENNIS_3_REVA:
case VIRTUA_TENNIS_3_REVA_TEST:
case VIRTUA_TENNIS_3_REVB:
case VIRTUA_TENNIS_3_REVB_TEST:
case VIRTUA_TENNIS_3_REVC:
case VIRTUA_TENNIS_3_REVC_TEST:
// Code for supported games
break;
default:
printf("Warning: This Game does not support Card Reader, I will disable the card reader for you.\n");
config->emulateCardreader = 0;
return 0;
}
if (getConfig()->emulateCardreader && getConfig()->emulateDriveboard && gId != R_TUNED)
{
printf("Warning: This Game does not support Card Reader and Driver Board emulation enabled at the same time.\n");
printf("Please disable Drive Board emulations in the config file.\n");
return -1;
}
initReadCmd(0);
initReadCmd(1);
initWriteCmd(0);
initWriteCmd(1);
return 0;
}
int carReaderGetFdIdx(int fd)
{
if (fd == serialFD[0].fd)
return 0;
return 1;
}
uint8_t cardReaderGenChecksum(int fdIdx)
{
int checksum = 0;
for (int i = 0; i < readCmd[fdIdx].cmdLen - 1; i++)
{
checksum ^= readCmd[fdIdx].sendBuffer[i];
}
return checksum;
}
void buildOutputBuffer(int fdIdx, uint8_t cmd)
{
uint16_t packetLen = 0;
readCmd[fdIdx].sendBuffer[0] = 0x10;
readCmd[fdIdx].sendBuffer[1] = cmd;
switch (cmd)
{
case 0x10:
{
readCmd[fdIdx].sendBuffer[5] = 0x20;
}
case 0x11:
{
if (writeCmd[fdIdx].recBuffer[5] == 0x04)
{
initWriteCmd(fdIdx);
return;
}
}
case 0x14:
case 0x15:
case 0x20:
{
if (cmd == 0x20 && writeCmd[fdIdx].recBuffer[5] == 0x00)
readCmd[fdIdx].sendBuffer[4] = 0x80;
}
case 0x26:
case 0x27:
{
packetLen = 0x02;
readCmd[fdIdx].sendBuffer[3] = packetLen;
}
break;
case 0x21:
{
packetLen = 0x0a;
readCmd[fdIdx].sendBuffer[3] = packetLen;
readCmd[fdIdx].sendBuffer[6] = 0x81;
readCmd[fdIdx].sendBuffer[8] = 0x59;
readCmd[fdIdx].sendBuffer[9] = 0xda;
}
break;
case 0x22:
{
packetLen = 0x0a;
readCmd[fdIdx].sendBuffer[3] = packetLen;
readCmd[fdIdx].sendBuffer[7] = 0x08;
}
break;
case 0x33:
{
packetLen = 0x0a;
readCmd[fdIdx].sendBuffer[3] = packetLen;
readCmd[fdIdx].sendBuffer[6] = 0xff;
readCmd[fdIdx].sendBuffer[7] = 0xff;
}
break;
case 0x34:
{
uint16_t blockStart = (writeCmd[fdIdx].recBuffer[6] << 8) | writeCmd[fdIdx].recBuffer[7];
uint16_t blocksToRead = (writeCmd[fdIdx].recBuffer[8] << 8) | writeCmd[fdIdx].recBuffer[9];
packetLen = (BLOCKSIZE * blocksToRead) + 2;
readCmd[fdIdx].sendBuffer[3] = packetLen;
FILE *crdFile = fopen(serialFD[fdIdx].cardFilename, "rb");
fseek(crdFile, BLOCKSIZE * blockStart, SEEK_SET);
fread(readCmd[fdIdx].sendBuffer + 6, 1, packetLen - 2, crdFile);
fclose(crdFile);
}
break;
case 0x35:
{
readCmd[fdIdx].sendBuffer[3] = 0x02;
uint16_t blockStart = (writeCmd[fdIdx].recBuffer[6] << 8) | writeCmd[fdIdx].recBuffer[7];
uint16_t blocksToWrite = (writeCmd[fdIdx].recBuffer[8] << 8) | writeCmd[fdIdx].recBuffer[9];
packetLen = BLOCKSIZE * blocksToWrite;
FILE *crdFile = fopen(serialFD[fdIdx].cardFilename, "rb+");
fseek(crdFile, BLOCKSIZE * blockStart, SEEK_SET);
fwrite(writeCmd[fdIdx].recBuffer + 10, 1, packetLen, crdFile);
fclose(crdFile);
packetLen = 0x02;
}
break;
default:
{
printf("Command not supported.\n");
}
}
readCmd[fdIdx].cmdLen = packetLen + 5;
readCmd[fdIdx].sendBuffer[readCmd[fdIdx].cmdLen - 1] = cardReaderGenChecksum(fdIdx);
}
size_t cardReaderWrite(int fd, const void *buf, size_t count)
{
int fdIdx = carReaderGetFdIdx(fd);
if (writeCmd[fdIdx].cmdCompleted)
{
printf("Something went wrong, a write command was issued after the command was completed.\n");
}
if (writeCmd[fdIdx].recBytes == 4)
{
writeCmd[fdIdx].packetLen = (writeCmd[fdIdx].recBuffer[2] << 8) | writeCmd[fdIdx].recBuffer[3];
}
writeCmd[fdIdx].recBuffer[writeCmd[fdIdx].recBytes] = *((u_int8_t *)buf);
writeCmd[fdIdx].recBytes++;
if (writeCmd[fdIdx].recBytes == writeCmd[fdIdx].packetLen + 5)
{
writeCmd[fdIdx].cmdCompleted = true;
initReadCmd(fdIdx);
buildOutputBuffer(fdIdx, writeCmd[fdIdx].recBuffer[1]);
}
return count;
}
size_t cardReaderRead(int fd, void *buf, size_t count)
{
int fdIdx = carReaderGetFdIdx(fd);
if (!writeCmd[fdIdx].cmdCompleted || readCmd[fdIdx].cmdCompleted)
return -1;
if (readCmd[fdIdx].cmdLen == readCmd[fdIdx].sentBytes)
{
readCmd[fdIdx].cmdCompleted = true;
initWriteCmd(fdIdx);
return -1;
}
memcpy(buf, &readCmd[fdIdx].sendBuffer[readCmd[fdIdx].sentBytes], sizeof(uint8_t));
readCmd[fdIdx].sentBytes++;
return 1;
}
void cardReaderSetFd(int serial, int fd, char *fName)
{
serialFD[serial].fd = fd;
serialFD[serial].cardFilename = fName;
if (access(fName, F_OK) != 0)
{
FILE *crdFile = fopen(fName, "wb+");
if (getConfig()->crc32 == R_TUNED)
{
cardHeader[0x22] = 0x02;
cardHeader[0x23] = 0x60;
}
fwrite(cardHeader, 1, 56, crdFile);
uint8_t z = 0;
fseek(crdFile, 0x7c7, SEEK_CUR);
fwrite(&z, 1, 1, crdFile);
fclose(crdFile);
printf("Cardfile %s created.\n", fName);
}
}
+36
View File
@@ -0,0 +1,36 @@
#ifndef CARD_READER_H
#define CARD_READER_H
#include <stdint.h>
#include <sys/types.h>
typedef struct
{
int fd;
char *cardFilename;
} SerialFD;
typedef struct
{
bool cmdCompleted;
uint16_t packetLen;
uint8_t recBytes;
uint8_t recBuffer[256];
} WriteCommand;
typedef struct
{
uint8_t cmd;
bool cmdCompleted;
uint8_t cmdLen;
uint8_t sentBytes;
uint8_t sendBuffer[256];
} ReadCommand;
int initCardReader();
size_t cardReaderWrite(int fd, const void *buf, size_t count);
size_t cardReaderRead(int fd, void *buf, size_t count);
void cardReaderSetFd(int serial, int fd, char *fName);
#endif
+851 -652
View File
File diff suppressed because it is too large Load Diff
+26 -5
View File
@@ -2,6 +2,7 @@
#define CONFIG_H
#include <stdint.h>
#include <sys/types.h>
#define MAX_PATH_LENGTH 1024
#define INPUT_STRING_LENGTH 256
@@ -29,8 +30,9 @@
#define INITIALD_4_EXP_REVD 0x62cc73a9 // DVP-0030D
#define INITIALD_5_JAP_REVA 0xb3183112 // DVP-0070A
#define INITIALD_5_JAP_REVF 0xfc3dc85d // DVP-0070F
#define INITIALD_5_EXP_30 0x77c6b58b // DVP-0075 and DVP-0084????
#define INITIALD_5_EXP_40 0xd4910e75 // DVP-0084A
#define INITIALD_5_EXP 0x701b88cf // DVP-0075
#define INITIALD_5_EXP_20 0x77c6b58b // DVP-0084
#define INITIALD_5_EXP_20A 0xd4910e75 // DVP-0084A
#define LETS_GO_JUNGLE 0xb1c8c901 // DVP-0011
#define LETS_GO_JUNGLE_REVA 0xc697c4fb // DVP-0011A
#define LETS_GO_JUNGLE_SPECIAL 0x240beedc // DVP-0036A
@@ -70,7 +72,6 @@
#define VIRTUA_FIGHTER_5_REVB 0x8953bd52 // DVP-0008B
#define VIRTUA_FIGHTER_5_REVE 0x4c2edbf6 // DVP-0008E
#define VIRTUA_FIGHTER_5_EXPORT 0xec474630 // DVP-0043
#define VIRTUA_FIGHTER_5_FINAL_SHOWDOWN 0x48 // DVP-5019 or does not exist
#define VIRTUA_FIGHTER_5_FINAL_SHOWDOWN_REVA 0xbae2be62 // DVP-5019A
#define VIRTUA_FIGHTER_5_FINAL_SHOWDOWN_REVB 0x7cee1d81 // DVP-5020
#define VIRTUA_FIGHTER_5_FINAL_SHOWDOWN_REVB_6000 0x34c0d02 // DVP-5020 ver 6.00 (Weird public version)
@@ -182,6 +183,7 @@ typedef struct {
char player1_button_8[INPUT_STRING_LENGTH];
char player1_button_9[INPUT_STRING_LENGTH];
char player1_button_10[INPUT_STRING_LENGTH];
char player1_coin[INPUT_STRING_LENGTH];
// Player 2 controls
char player2_button_start[INPUT_STRING_LENGTH];
@@ -200,7 +202,8 @@ typedef struct {
char player2_button_8[INPUT_STRING_LENGTH];
char player2_button_9[INPUT_STRING_LENGTH];
char player2_button_10[INPUT_STRING_LENGTH];
char player2_coin[INPUT_STRING_LENGTH];
// Analogue inputs
char analogue_1[INPUT_STRING_LENGTH];
char analogue_2[INPUT_STRING_LENGTH];
@@ -222,6 +225,10 @@ typedef struct
int emulateRideboard;
int emulateDriveboard;
int emulateMotionboard;
int emulateCardreader;
int emulateTouchscreen;
char cardFile1[MAX_PATH_LENGTH];
char cardFile2[MAX_PATH_LENGTH];
int emulateJVS;
int fullscreen;
char eepromPath[MAX_PATH_LENGTH];
@@ -231,6 +238,7 @@ typedef struct
char serial2Path[MAX_PATH_LENGTH];
int width;
int height;
int boostRenderRes;
Colour lindberghColour;
GameStatus gameStatus;
GameType gameType;
@@ -257,7 +265,19 @@ typedef struct
int lgjRenderWithMesa;
int noSDL;
int phMode;
int disableBuiltinFont;
int disableBuiltinLogos;
int hideCursor;
char customCursor[MAX_PATH_LENGTH];
int customCursorWidth;
int customCursorHeight;
char phTouchCursor[MAX_PATH_LENGTH];
int phTouchCursorWidth;
int phTouchCursorHeight;
int mj4EnabledAtT;
char or2IP[16];
char or2Netmask[16];
float cpuFreqGhz;
ArcadeInputs arcadeInputs;
int inputMode; // 0 = both, 1 = SDL/X11 only, 2 = EVDEV only
int skipOutrunCabinetCheck;
@@ -266,8 +286,9 @@ typedef struct
int borderEnabled;
} EmulatorConfig;
uint32_t get_crc32(const char *s, ssize_t n);
KeyMapping getDefaultKeymap();
int initConfig();
int initConfig(const char* configFilePath);
EmulatorConfig *getConfig();
char *getGameName();
char *getDVPName();
+229
View File
@@ -0,0 +1,229 @@
#include <SDL2/SDL_events.h>
#include <SDL2/SDL_mouse.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#define STBI_ONLY_PNG
#define STBI_SUPPORT_ZLIB
#define STBI_NO_SIMD
#include <SDL2/SDL.h>
#include <X11/Xlib.h>
#include <X11/Xcursor/Xcursor.h>
#include "config.h"
extern Display *x11Display;
extern Window window;
void *customCursor;
void *phTouchCursor;
void *blankCursor;
SDL_Surface *createSurfaceFromStb(unsigned char *data, int width, int height, int channels)
{
Uint32 rmask, gmask, bmask, amask;
if (channels == 4)
{
rmask = 0x000000FF;
gmask = 0x0000FF00;
bmask = 0x00FF0000;
amask = 0xFF000000;
}
else if (channels == 3)
{
rmask = 0x000000FF;
gmask = 0x0000FF00;
bmask = 0x00FF0000;
amask = 0;
}
else
{
fprintf(stderr, "Unsupported image format with %d channels.\n", channels);
return NULL;
}
return SDL_CreateRGBSurfaceFrom(data, width, height, channels * 8, width * channels, rmask, gmask, bmask, amask);
}
int loadNewCursor(const char *cursorFileName, void **cursor, int customWidth, int customHeight)
{
int width, height, channels;
unsigned char *imageData = stbi_load(cursorFileName, &width, &height, &channels, 0);
if (!imageData)
{
fprintf(stderr, "Failed to load image: %s\n", cursorFileName);
return 0;
}
SDL_Surface *originalSurface = createSurfaceFromStb(imageData, width, height, channels);
if (!originalSurface)
{
stbi_image_free(imageData);
return 0;
}
SDL_Surface *resizedSurface =
SDL_CreateRGBSurface(0, customWidth, customHeight, originalSurface->format->BitsPerPixel, originalSurface->format->Rmask,
originalSurface->format->Gmask, originalSurface->format->Bmask, originalSurface->format->Amask);
if (!resizedSurface)
{
fprintf(stderr, "SDL_CreateRGBSurface Error: %s\n", SDL_GetError());
SDL_FreeSurface(originalSurface);
stbi_image_free(imageData);
return 0;
}
SDL_Rect srcRect = {0, 0, originalSurface->w, originalSurface->h};
SDL_Rect destRect = {0, 0, customWidth, customHeight};
if (SDL_BlitScaled(originalSurface, &srcRect, resizedSurface, &destRect) != 0)
{
fprintf(stderr, "SDL_BlitScaled Error: %s\n", SDL_GetError());
SDL_FreeSurface(resizedSurface);
SDL_FreeSurface(originalSurface);
stbi_image_free(imageData);
return 0;
}
if (getConfig()->noSDL == 0)
{
*cursor = SDL_CreateColorCursor(resizedSurface, customWidth / 2, customHeight / 2);
if (!*cursor)
{
fprintf(stderr, "SDL_CreateColorCursor Error: %s\n", SDL_GetError());
SDL_FreeSurface(resizedSurface);
SDL_FreeSurface(originalSurface);
stbi_image_free(imageData);
return 0;
}
SDL_FreeSurface(resizedSurface);
SDL_FreeSurface(originalSurface);
}
else
{
XcursorImage *xcursor = XcursorImageCreate(resizedSurface->w, resizedSurface->h);
if (!xcursor)
return None;
xcursor->xhot = customWidth / 2;
xcursor->yhot = customHeight / 2;
xcursor->width = resizedSurface->w;
xcursor->height = resizedSurface->h;
// Convert SDL surface to Xcursor format (32-bit ARGB)
for (int y = 0; y < resizedSurface->h; ++y)
{
for (int x = 0; x < resizedSurface->w; ++x)
{
Uint32 pixel = ((Uint32 *)resizedSurface->pixels)[y * resizedSurface->w + x];
Uint8 r, g, b, a;
SDL_GetRGBA(pixel, resizedSurface->format, &r, &g, &b, &a);
xcursor->pixels[y * resizedSurface->w + x] = (a << 24) | (r << 16) | (g << 8) | b;
}
}
*cursor = (void*)XcursorImageLoadCursor(x11Display, xcursor);
XcursorImageDestroy(xcursor);
}
return 1;
}
void loadCursors()
{
if (strcmp(getConfig()->customCursor, "") != 0)
{
if (!loadNewCursor(getConfig()->customCursor, (void *)&customCursor, getConfig()->customCursorWidth,
getConfig()->customCursorHeight))
{
fprintf(stderr, "Custom cursor could not be loaded!\n");
exit(1);
}
}
if (strcmp(getConfig()->phTouchCursor, "") != 0)
{
if (!loadNewCursor(getConfig()->phTouchCursor, (void *)&phTouchCursor, getConfig()->phTouchCursorWidth,
getConfig()->phTouchCursorHeight))
{
fprintf(stderr, "Custom cursor could not be loaded!\n");
exit(1);
}
}
if(getConfig()->noSDL)
{
XColor dummyColor;
Pixmap blankPixmap;
blankPixmap = XCreatePixmap(x11Display, window, 1, 1, 1);
if (!blankPixmap)
{
fprintf(stderr, "Failed to create blank pixmap\n");
}
blankCursor = (void*)XCreatePixmapCursor(x11Display, blankPixmap, blankPixmap, &dummyColor, &dummyColor, 0, 0);
if (!blankCursor)
{
fprintf(stderr, "Failed to create blank cursor\n");
XFreePixmap(x11Display, blankPixmap);
}
}
}
void setCursor(void *cursor)
{
if (getConfig()->noSDL == 0)
{
if (SDL_GetCursor() != NULL)
SDL_SetCursor(cursor);
}
else
{
XDefineCursor(x11Display, window, (Cursor)cursor);
XFlush(x11Display);
}
}
void hideCursor()
{
if (getConfig()->noSDL == 0)
{
SDL_ShowCursor(SDL_DISABLE);
}
else
{
XDefineCursor(x11Display, window, (Cursor)blankCursor);
XFlush(x11Display);
}
}
void showCursor()
{
if (getConfig()->noSDL == 0)
{
SDL_ShowCursor(SDL_ENABLE);
}
else
{
XDefineCursor(x11Display, window, (Cursor)customCursor);
XFlush(x11Display);
}
}
void showPhCursor()
{
if (getConfig()->noSDL == 0)
{
SDL_ShowCursor(SDL_ENABLE);
}
else
{
XDefineCursor(x11Display, window, (Cursor)phTouchCursor);
XFlush(x11Display);
}
}
+10
View File
@@ -0,0 +1,10 @@
#ifndef CUSTOM_CURSORS_H
#define CUSTOM_CURSORS_H
int loadNewCursor(const char *cursorFileName, void **cursor, int customWidth, int customHeight);
void loadCursors();
void setCursor(void *cursor);
void hideCursor();
void showCursor();
void showPhCursor();
#endif
+25 -8
View File
@@ -1,6 +1,7 @@
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "config.h"
#include "eeprom.h"
@@ -15,6 +16,8 @@
#define I2C_SEEK 2
#define I2C_WRITE 3
extern uint32_t gId;
union i2c_smbus_data {
uint8_t byte;
uint16_t word;
@@ -67,27 +70,41 @@ int initEeprom()
setFreeplay(eeprom, getConfig()->freeplay);
}
if ((getConfig()->crc32 == LETS_GO_JUNGLE_SPECIAL) || (getConfig()->crc32 == THE_HOUSE_OF_THE_DEAD_EX) ||
(getConfig()->crc32 == THE_HOUSE_OF_THE_DEAD_4_SPECIAL) ||
(getConfig()->crc32 == THE_HOUSE_OF_THE_DEAD_4_SPECIAL_REVB))
switch (gId)
{
case LETS_GO_JUNGLE_SPECIAL:
case THE_HOUSE_OF_THE_DEAD_EX:
case THE_HOUSE_OF_THE_DEAD_4_SPECIAL:
case THE_HOUSE_OF_THE_DEAD_4_SPECIAL_REVB:
if (fixCreditSection(eeprom) != 0)
{
printf("Error initializing eeprom settings.");
fclose(eeprom);
return 1;
}
}
if (getConfig()->crc32 == HUMMER || getConfig()->crc32 == HUMMER_SDLX || getConfig()->crc32 == HUMMER_EXTREME ||
getConfig()->crc32 == HUMMER_EXTREME_MDX)
{
break;
case HUMMER:
case HUMMER_SDLX:
case HUMMER_EXTREME:
case HUMMER_EXTREME_MDX:
if (fixCoinAssignmentsHummer(eeprom) != 0)
{
printf("Error initializing eeprom settings.");
fclose(eeprom);
return 1;
}
break;
case OUTRUN_2_SP_SDX:
case OUTRUN_2_SP_SDX_REVA:
if (strcmp(getConfig()->or2IP, "") != 0)
{
if (setIP(eeprom, getConfig()->or2IP, getConfig()->or2Netmask) != 0)
{
printf("Error setting the new IP address.");
fclose(eeprom);
return 1;
}
}
}
fseek(eeprom, 0, SEEK_SET);
+17 -1
View File
@@ -3,7 +3,6 @@
#include <stdlib.h>
#include <string.h>
#include "config.h"
#include "eeprom_settings.h"
uint32_t crc32_table[255];
@@ -226,6 +225,23 @@ int fixCoinAssignmentsHummer(FILE *eeprom)
return 0;
}
int setIP(FILE *eeprom, char *ipAddress, char *netMask)
{
uint32_t ipHex = inet_addr(ipAddress);
uint32_t nMask = inet_addr(netMask);
uint32_t dhcp = 0;
memcpy(&eepromBuffer[eepromOffsetTable[ETH0].offset + 8], &dhcp, sizeof(uint32_t));
memcpy(&eepromBuffer[eepromOffsetTable[ETH0].offset + 12], &ipHex, sizeof(uint32_t));
memcpy(&eepromBuffer[eepromOffsetTable[ETH0].offset + 16], &nMask, sizeof(uint32_t));
addCRCtoBuffer(ETH0);
if (writeSectiontoFile(eeprom, ETH0) != 0)
{
printf("Error writing to eeprom.");
return 1;
}
return 0;
}
int eepromSettingsInit( FILE *eeprom)
{
build_crc32_table();
+3 -1
View File
@@ -1,7 +1,9 @@
#include <stdio.h>
int eepromSettingsInit(FILE *eeprom);
int getRegion();
int getFreeplay();
int setRegion(FILE *eeprom, int region);
int setFreeplay(FILE *eeprom, int freeplay);
int fixCreditSection(FILE *eeprom);
int fixCoinAssignmentsHummer(FILE *eeprom);
int fixCoinAssignmentsHummer(FILE *eeprom);
int setIP(FILE *eeprom, char *ipAddress, char *netMask);
+175 -32
View File
@@ -41,6 +41,7 @@ ArcadeInput arcadeInputs[] = {{"TEST_BUTTON", 0, BUTTON_TEST, 1},
{"PLAYER_1_BUTTON_8", 1, BUTTON_8, 1},
{"PLAYER_1_BUTTON_9", 1, BUTTON_9, 1},
{"PLAYER_1_BUTTON_10", 1, BUTTON_10, 1},
{"PLAYER_1_COIN", 1, COIN, 1},
{"PLAYER_2_BUTTON_START", 2, BUTTON_START, 1},
{"PLAYER_2_BUTTON_SERVICE", 2, BUTTON_SERVICE, 1},
@@ -58,6 +59,7 @@ ArcadeInput arcadeInputs[] = {{"TEST_BUTTON", 0, BUTTON_TEST, 1},
{"PLAYER_2_BUTTON_8", 2, BUTTON_8, 1},
{"PLAYER_2_BUTTON_9", 2, BUTTON_9, 1},
{"PLAYER_2_BUTTON_10", 2, BUTTON_10, 1},
{"PLAYER_2_COIN", 2, COIN, 1},
{"ANALOGUE_1", 0, ANALOGUE_1, 1},
{"ANALOGUE_2", 0, ANALOGUE_2, 1},
@@ -860,7 +862,7 @@ static ControllerStatus listControllers(Controllers *controllers)
int controller = open(controllers->controller[i].path, O_RDONLY);
if (controller < 0)
{
strcpy(controllers->controller[i].name, "Unknown");
strncpy(controllers->controller[i].name, "Unknown", SIZE);
continue;
}
@@ -910,16 +912,26 @@ static ControllerStatus listControllers(Controllers *controllers)
{
if (test_bit(code, bit[EV_KEY]))
{
if(controllers->controller[i].inputCount >= MAX_INPUTS) { // the number of input is limited
fprintf(stderr, "warning, maximum number of inputs reached !\n");
break;
}
controllers->controller[i].enabled = 1;
ControllerInput *controllerInput =
&controllers->controller[i].inputs[controllers->controller[i].inputCount++];
controllerInput->evType = EV_KEY;
controllerInput->evCode = code;
controllerInput->specialFunction = NO_SPECIAL_FUNCTION;
strcpy(controllerInput->inputName, controllers->controller[i].name);
strncpy(controllerInput->inputName, controllers->controller[i].name, SIZE);
strcat(controllerInput->inputName, "_");
strcat(controllerInput->inputName, codename(EV_KEY, code));
normaliseName(controllerInput->inputName);
if (snprintf(controllerInput->inputTechName, SIZE, "%s:KEY:%i", controllers->controller[i].path, code) >= 1024)
{
// hum ok, truncated value
}
strncpy(controllerInput->inputTechNegName, "-", SIZE); // unassignable value (not "" while some conf are empty)
}
}
}
@@ -937,31 +949,70 @@ static ControllerStatus listControllers(Controllers *controllers)
controllerInput->evType = EV_ABS;
controllerInput->evCode = code;
controllerInput->specialFunction = NO_SPECIAL_FUNCTION;
strcpy(controllerInput->inputName, controllers->controller[i].name);
strncpy(controllerInput->inputName, controllers->controller[i].name, SIZE);
strcat(controllerInput->inputName, "_");
strcat(controllerInput->inputName, codename(EV_ABS, code));
normaliseName(controllerInput->inputName);
if (snprintf(controllerInput->inputTechName, SIZE, "%s:ABS:%i", controllers->controller[i].path, code) >= 1024)
{
// hum ok, truncated value
}
if (snprintf(controllerInput->inputTechNegName, SIZE, "%s:ABS_NEG:%i", controllers->controller[i].path, code) >= 1024)
{
// hum ok, truncated value
}
ControllerInput *minControllerInput =
&controllers->controller[i].inputs[controllers->controller[i].inputCount++];
minControllerInput->evType = EV_ABS;
minControllerInput->evCode = code;
minControllerInput->specialFunction = ANALOGUE_TO_DIGITAL_MIN;
strcpy(minControllerInput->inputName, controllerInput->inputName);
strncpy(minControllerInput->inputName, controllerInput->inputName, SIZE);
strcat(minControllerInput->inputName, "_MIN");
if (snprintf(minControllerInput->inputTechName, SIZE, "%s:ABS:%i:MIN", controllers->controller[i].path, code) >= 1024)
{
// hum ok, truncated value
}
if (snprintf(minControllerInput->inputTechNegName, SIZE, "%s:ABS_NEG:%i:MIN", controllers->controller[i].path, code) >=
1024)
{
// hum ok, truncated value
}
ControllerInput *maxControllerInput =
&controllers->controller[i].inputs[controllers->controller[i].inputCount++];
maxControllerInput->evType = EV_ABS;
maxControllerInput->evCode = code;
maxControllerInput->specialFunction = ANALOGUE_TO_DIGITAL_MAX;
strcpy(maxControllerInput->inputName, controllerInput->inputName);
strncpy(maxControllerInput->inputName, controllerInput->inputName, SIZE);
strcat(maxControllerInput->inputName, "_MAX");
if (snprintf(maxControllerInput->inputTechName, SIZE, "%s:ABS:%i:MAX", controllers->controller[i].path, code) >= 1024)
{
// hum ok, truncated value
}
if (snprintf(maxControllerInput->inputTechNegName, SIZE, "%s:ABS_NEG:%i:MAX", controllers->controller[i].path, code) >=
1024)
{
// hum ok, truncated value
}
ControllerInput *shakeControllerInput = &controllers->controller[i].inputs[controllers->controller[i].inputCount++];
shakeControllerInput->evType = EV_ABS;
shakeControllerInput->evCode = code;
shakeControllerInput->specialFunction = ANALOGUE_SHAKE;
strncpy(shakeControllerInput->inputName, controllerInput->inputName, SIZE);
strcat(shakeControllerInput->inputName, "_SHAKE");
if (snprintf(shakeControllerInput->inputTechName, SIZE, "%s:ABS:%i:SHAKE", controllers->controller[i].path, code) >=
1024)
{
// hum ok, truncated value
}
struct input_absinfo absoluteFeatures;
ioctl(controller, EVIOCGABS(code), &absoluteFeatures);
controllers->controller[i].absMin[code] = absoluteFeatures.minimum;
controllers->controller[i].absMax[code] = absoluteFeatures.maximum;
}
}
}
@@ -1048,8 +1099,13 @@ void *controllerThread(void *_args)
continue;
}
setSwitch(args->controller->keyTriggers[event.code].player,
args->controller->keyTriggers[event.code].channel, event.value == 0 ? 0 : 1);
if(args->controller->keyTriggers[event.code].isCoin == 1) {
if(event.value == 1)
incrementCoin(args->controller->keyTriggers[event.code].player, 1);
} else
setSwitch(args->controller->keyTriggers[event.code].player,
args->controller->keyTriggers[event.code].channel, event.value == 0 ? 0 : 1);
}
break;
@@ -1059,31 +1115,67 @@ void *controllerThread(void *_args)
((double)event.value - (double)args->controller->absMin[event.code]) /
((double)args->controller->absMax[event.code] - (double)args->controller->absMin[event.code]);
if(args->controller->absTriggers[event.code].isNeg == 1) {
scaled = 1.0 - scaled;
}
if (args->controller->absTriggers[event.code].enabled)
{
int channel = args->controller->absTriggers[event.code].channel;
// Deadzone handling
if (scaled < analogue_deadzones[channel].start_max)
if (args->controller->absTriggers[event.code].isAnalogue) {
// Deadzone handling
if (scaled < analogue_deadzones[channel].start_max)
scaled = 0.0;
if (scaled > analogue_deadzones[channel].middle_min && scaled < analogue_deadzones[channel].middle_max)
if (scaled > analogue_deadzones[channel].middle_min && scaled < analogue_deadzones[channel].middle_max)
scaled = 0.5;
if (scaled > analogue_deadzones[channel].end_min)
if (scaled > analogue_deadzones[channel].end_min)
scaled = 1.0;
setAnalogue(channel, scaled * (pow(2, jvsBits) - 1));
setAnalogue(channel, scaled * (pow(2, jvsBits) - 1));
} else {
setSwitch(args->controller->absTriggers[event.code].player,
args->controller->absTriggers[event.code].channel, scaled < 0.8 ? 0 : 1);
}
}
if (args->controller->absTriggers[event.code].minEnabled)
{
setSwitch(args->controller->absTriggers[event.code].minPlayer,
args->controller->absTriggers[event.code].minChannel, scaled < 0.2);
if(event.value <= ((args->controller->absMin[event.code] + args->controller->absMax[event.code]) / 2)) {
if (args->controller->absTriggers[event.code].minEnabled)
{
int channel = args->controller->absTriggers[event.code].minChannel;
if (args->controller->absTriggers[event.code].isAnalogue) {
setAnalogue(channel, scaled < 0.2 ? 0.0 : pow(2, jvsBits) * 1.0);
} else {
setSwitch(args->controller->absTriggers[event.code].minPlayer,
args->controller->absTriggers[event.code].minChannel, scaled < 0.2 ? 1 : 0);
}
}
}
if (args->controller->absTriggers[event.code].maxEnabled)
{
setSwitch(args->controller->absTriggers[event.code].maxPlayer,
args->controller->absTriggers[event.code].maxChannel, scaled > 0.8);
if(event.value >= ((args->controller->absMin[event.code] + args->controller->absMax[event.code]) / 2)) {
if (args->controller->absTriggers[event.code].maxEnabled)
{
int channel = args->controller->absTriggers[event.code].maxChannel;
if (args->controller->absTriggers[event.code].isAnalogue) {
setAnalogue(channel, scaled > 0.8 ? pow(2, jvsBits) : 0.0);
} else {
setSwitch(args->controller->absTriggers[event.code].maxPlayer,
args->controller->absTriggers[event.code].maxChannel, scaled > 0.8 ? 1 : 0);
}
}
}
if (args->controller->absTriggers[event.code].shakeEnabled)
{
int channel = args->controller->absTriggers[event.code].shakeChannel;
if( (scaled > args->controller->absTriggers[event.code].shakePreviousScaled && scaled - args->controller->absTriggers[event.code].shakePreviousScaled > 0.1) ||
(scaled < args->controller->absTriggers[event.code].shakePreviousScaled && -scaled + args->controller->absTriggers[event.code].shakePreviousScaled > 0.1)) {
setAnalogue(channel, 0);
} else {
setAnalogue(channel, pow(2, jvsBits) / 2);
}
args->controller->absTriggers[event.code].shakePreviousScaled = scaled;
}
}
break;
@@ -1106,6 +1198,10 @@ char *getMapping(char *mapping)
// Test button
if (strcmp(mapping, config->arcadeInputs.test) == 0)
return "TEST_BUTTON";
if (strcmp(mapping, config->arcadeInputs.player1_coin) == 0)
return "PLAYER_1_COIN";
if (strcmp(mapping, config->arcadeInputs.player2_coin) == 0)
return "PLAYER_2_COIN";
// Player 1 controls
if (strcmp(mapping, config->arcadeInputs.player1_button_start) == 0)
@@ -1204,7 +1300,7 @@ ControllerStatus getArcadeInputByName(char *name, ArcadeInput *input)
{
if (strcmp(tempName, name) == 0)
{
strcpy(input->name, arcadeInputs[index].name);
strncpy(input->name, arcadeInputs[index].name, SIZE);
input->channel = arcadeInputs[index].channel;
input->player = arcadeInputs[index].player;
return CONTROLLER_STATUS_SUCCESS;
@@ -1232,19 +1328,35 @@ ControllerStatus startControllerThreads(Controllers *controllers)
controllers->controller[i].absTriggers[j].enabled = 0;
controllers->controller[i].absTriggers[j].minEnabled = 0;
controllers->controller[i].absTriggers[j].maxEnabled = 0;
controllers->controller[i].absTriggers[j].shakeEnabled = 0;
controllers->controller[i].absTriggers[j].isNeg = 0;
controllers->controller[i].absTriggers[j].isAnalogue = 1;
}
for (int j = 0; j < KEY_MAX; j++)
{
controllers->controller[i].keyTriggers[j].enabled = 0;
controllers->controller[i].keyTriggers[j].isAnalogue = 0;
controllers->controller[i].keyTriggers[j].isCoin = 0;
}
for (int j = 0; j < controllers->controller[i].inputCount; j++)
{
char *mapping = getMapping(controllers->controller[i].inputs[j].inputName);
if (mapping == NULL)
continue;
int negabs = 0;
if (mapping == NULL) {
// give a 2nd chance with a techninal mapping
mapping = getMapping(controllers->controller[i].inputs[j].inputTechName);
if (mapping == NULL) {
// give a 3rd change with negativ technical mapping
mapping = getMapping(controllers->controller[i].inputs[j].inputTechNegName);
negabs = 1;
if (mapping == NULL) {
continue;
}
}
}
ArcadeInput input = {0};
ControllerStatus status = getArcadeInputByName(mapping, &input);
@@ -1265,10 +1377,13 @@ ControllerStatus startControllerThreads(Controllers *controllers)
controllers->controller[i].absTriggers[controllers->controller[i].inputs[j].evCode].enabled = 1;
controllers->controller[i].absTriggers[controllers->controller[i].inputs[j].evCode].channel =
input.channel;
strcpy(controllers->controller[i].absTriggers[controllers->controller[i].inputs[j].evCode].name,
input.name);
strncpy(controllers->controller[i].absTriggers[controllers->controller[i].inputs[j].evCode].name,
input.name, SIZE);
controllers->controller[i].absTriggers[controllers->controller[i].inputs[j].evCode].player =
input.player;
controllers->controller[i].absTriggers[controllers->controller[i].inputs[j].evCode].isNeg = negabs;
if (strstr(input.name, "ANALOGUE") == NULL)
controllers->controller[i].absTriggers[controllers->controller[i].inputs[j].evCode].isAnalogue = 0;
}
break;
@@ -1277,10 +1392,13 @@ ControllerStatus startControllerThreads(Controllers *controllers)
controllers->controller[i].absTriggers[controllers->controller[i].inputs[j].evCode].maxEnabled = 1;
controllers->controller[i].absTriggers[controllers->controller[i].inputs[j].evCode].maxChannel =
input.channel;
strcpy(controllers->controller[i].absTriggers[controllers->controller[i].inputs[j].evCode].maxName,
input.name);
strncpy(controllers->controller[i].absTriggers[controllers->controller[i].inputs[j].evCode].maxName,
input.name, SIZE);
controllers->controller[i].absTriggers[controllers->controller[i].inputs[j].evCode].maxPlayer =
input.player;
controllers->controller[i].absTriggers[controllers->controller[i].inputs[j].evCode].isNeg = negabs;
if (strstr(input.name, "ANALOGUE") == NULL)
controllers->controller[i].absTriggers[controllers->controller[i].inputs[j].evCode].isAnalogue = 0;
}
break;
@@ -1289,10 +1407,25 @@ ControllerStatus startControllerThreads(Controllers *controllers)
controllers->controller[i].absTriggers[controllers->controller[i].inputs[j].evCode].minEnabled = 1;
controllers->controller[i].absTriggers[controllers->controller[i].inputs[j].evCode].minChannel =
input.channel;
strcpy(controllers->controller[i].absTriggers[controllers->controller[i].inputs[j].evCode].minName,
input.name);
strncpy(controllers->controller[i].absTriggers[controllers->controller[i].inputs[j].evCode].minName,
input.name, SIZE);
controllers->controller[i].absTriggers[controllers->controller[i].inputs[j].evCode].minPlayer =
input.player;
controllers->controller[i].absTriggers[controllers->controller[i].inputs[j].evCode].isNeg = negabs;
if (strstr(input.name, "ANALOGUE") == NULL)
controllers->controller[i].absTriggers[controllers->controller[i].inputs[j].evCode].isAnalogue = 0;
}
break;
case ANALOGUE_SHAKE:
{
controllers->controller[i].absTriggers[controllers->controller[i].inputs[j].evCode].shakeEnabled = 1;
controllers->controller[i].absTriggers[controllers->controller[i].inputs[j].evCode].shakeChannel =
input.channel;
strncpy(controllers->controller[i].absTriggers[controllers->controller[i].inputs[j].evCode].shakeName,
input.name, SIZE);
controllers->controller[i].absTriggers[controllers->controller[i].inputs[j].evCode].shakePlayer =
input.player;
}
break;
@@ -1307,13 +1440,23 @@ ControllerStatus startControllerThreads(Controllers *controllers)
controllers->controller[i].keyTriggers[controllers->controller[i].inputs[j].evCode].enabled = 1;
controllers->controller[i].keyTriggers[controllers->controller[i].inputs[j].evCode].channel =
input.channel;
strcpy(controllers->controller[i].keyTriggers[controllers->controller[i].inputs[j].evCode].name,
input.name);
strncpy(controllers->controller[i].keyTriggers[controllers->controller[i].inputs[j].evCode].name,
input.name, SIZE);
controllers->controller[i].keyTriggers[controllers->controller[i].inputs[j].evCode].player =
input.player;
if (strstr(input.name, "ANALOGUE") != NULL)
controllers->controller[i].keyTriggers[controllers->controller[i].inputs[j].evCode].isAnalogue = 1;
if (strcmp(input.name, "PLAYER_1_COIN") == 0)
{
controllers->controller[i].keyTriggers[controllers->controller[i].inputs[j].evCode].isCoin = 1;
}
if (strcmp(input.name, "PLAYER_2_COIN") == 0)
{
controllers->controller[i].keyTriggers[controllers->controller[i].inputs[j].evCode].isCoin = 1;
}
}
break;
+16 -4
View File
@@ -2,9 +2,9 @@
#include <linux/input-event-codes.h>
#define SIZE 1024
#define SIZE 300
#define CONTROLLER_THREAD_MAX 256
#define MAX_INPUTS 512
typedef struct
{
@@ -31,6 +31,15 @@ typedef struct
int maxEnabled;
int isAnalogue;
int isNeg; // reversed axis
char shakeName[SIZE];
int shakeChannel;
int shakeEnabled;
int shakePlayer;
double shakePreviousScaled;
int isCoin;
} ArcadeInput;
typedef enum
@@ -43,12 +52,15 @@ typedef enum {
NO_SPECIAL_FUNCTION = 0,
ANALOGUE_TO_DIGITAL_MAX,
ANALOGUE_TO_DIGITAL_MIN,
DIGITAL_TO_ANALOGUE
DIGITAL_TO_ANALOGUE,
ANALOGUE_SHAKE
} SpecialFunction;
typedef struct
{
char inputName[SIZE];
char inputTechName[SIZE];
char inputTechNegName[SIZE];
int evType;
int evCode;
SpecialFunction specialFunction;
@@ -62,7 +74,7 @@ typedef struct
int absMax[ABS_MAX];
int absMin[ABS_MAX];
ControllerInput inputs[SIZE];
ControllerInput inputs[MAX_INPUTS];
int inputCount;
ArcadeInput keyTriggers[KEY_MAX];
+46 -22
View File
@@ -22,10 +22,13 @@
#include "fps_limiter.h"
#include "sdlcalls.h"
#include "border.h"
#include "resolution.h"
extern uint32_t gId;
extern SDL_Window *SDLwindow;
extern char SDLgameTitle[];
extern fps_limit fpsLimit;
bool GLUTGame = false;
void *displayFunc = NULL;
void *reshapeFunc = NULL;
@@ -34,19 +37,26 @@ void *idleFunc = NULL;
void FGAPIENTRY glutInit(int *argcp, char **argv)
{
if (*argcp > 1 && getConfig()->crc32 == SEGA_RACE_TV)
void FGAPIENTRY (*_glutInit)(int *argcp, char **argv) = dlsym(RTLD_NEXT, "glutInit");
if (*argcp > 1 && gId == SEGA_RACE_TV)
{
for (int x = 0; x < *argcp; x++)
if (isTestMode())
{
if (strcmp(argv[x], "-t") == 0)
{
EmulatorConfig *config = getConfig();
config->noSDL = 0;
printf("Forced to use SDL to make Test mode render fine.");
}
EmulatorConfig *config = getConfig();
config->noSDL = 0;
printf("Forced to use SDL to make Test mode render fine.\n");
}
}
glutInitSDL(argcp, argv);
if (getConfig()->noSDL)
{
_glutInit(argcp, argv);
return;
}
GLUTGame = true;
initSDL(argcp, argv);
}
void FGAPIENTRY glutMainLoop(void)
@@ -101,10 +111,13 @@ void FGAPIENTRY glutSwapBuffers(void)
return;
}
int gId = config->crc32;
if (gId == OUTRUN_2_SP_SDX || gId == OUTRUN_2_SP_SDX_REVA || gId == OUTRUN_2_SP_SDX_REVA_TEST || gId == OUTRUN_2_SP_SDX_REVA_TEST2 ||
gId == OUTRUN_2_SP_SDX_TEST)
switch (gId)
{
case OUTRUN_2_SP_SDX:
case OUTRUN_2_SP_SDX_REVA:
case OUTRUN_2_SP_SDX_REVA_TEST:
case OUTRUN_2_SP_SDX_REVA_TEST2:
case OUTRUN_2_SP_SDX_TEST:
pollEvents();
}
@@ -173,11 +186,15 @@ void FGAPIENTRY glutSetCursor(int glutCursor)
if (getConfig()->noSDL)
{
void FGAPIENTRY (*_glutSetCursor)(int glutCursor) = dlsym(RTLD_NEXT, "glutSetCursor");
_glutSetCursor(glutCursor);
if(strcmp(getConfig()->customCursor, "") == 0)
_glutSetCursor(glutCursor);
return;
}
SDL_Cursor *cursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW);
SDL_SetCursor(cursor);
if (strcmp(getConfig()->customCursor, "") == 0)
{
SDL_Cursor *cursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW);
SDL_SetCursor(cursor);
}
}
void FGAPIENTRY glutDisplayFunc(void (*callback)(void))
@@ -296,7 +313,8 @@ void FGAPIENTRY glutKeyboardFunc(void (*callback)(unsigned char, int, int))
{
if (getConfig()->noSDL)
{
void FGAPIENTRY (*_glutKeyboardFunc)(void (*callback)(unsigned char, int, int)) = dlsym(RTLD_NEXT, "glutKeyboardFunc");
void FGAPIENTRY (*_glutKeyboardFunc)(void (*callback)(unsigned char, int, int)) =
dlsym(RTLD_NEXT, "glutKeyboardFunc");
_glutKeyboardFunc(callback);
return;
}
@@ -307,7 +325,8 @@ void FGAPIENTRY glutKeyboardUpFunc(void (*callback)(unsigned char, int, int))
{
if (getConfig()->noSDL)
{
void FGAPIENTRY (*_glutKeyboardUpFunc)(void (*callback)(unsigned char, int, int)) = dlsym(RTLD_NEXT, "glutKeyboardUpFunc");
void FGAPIENTRY (*_glutKeyboardUpFunc)(void (*callback)(unsigned char, int, int)) =
dlsym(RTLD_NEXT, "glutKeyboardUpFunc");
_glutKeyboardUpFunc(callback);
return;
}
@@ -362,7 +381,8 @@ void FGAPIENTRY glutPassiveMotionFunc(void (*callback)(int, int))
{
if (getConfig()->noSDL)
{
void FGAPIENTRY (*_glutPassiveMotionFunc)(void (*callback)(int, int)) = dlsym(RTLD_NEXT, "glutPassiveMotionFunc");
void FGAPIENTRY (*_glutPassiveMotionFunc)(void (*callback)(int, int)) =
dlsym(RTLD_NEXT, "glutPassiveMotionFunc");
_glutPassiveMotionFunc(callback);
return;
}
@@ -417,7 +437,8 @@ void FGAPIENTRY glutSolidSphere(double radius, GLint slices, GLint stacks)
{
if (getConfig()->noSDL)
{
void FGAPIENTRY (*_glutSolidSphere)(double radius, GLint slices, GLint stacks) = dlsym(RTLD_NEXT, "glutSolidSphere");
void FGAPIENTRY (*_glutSolidSphere)(double radius, GLint slices, GLint stacks) =
dlsym(RTLD_NEXT, "glutSolidSphere");
_glutSolidSphere(radius, slices, stacks);
return;
}
@@ -428,7 +449,8 @@ void FGAPIENTRY glutWireSphere(double radius, GLint slices, GLint stacks)
{
if (getConfig()->noSDL)
{
void FGAPIENTRY (*_glutWireSphere)(double radius, GLint slices, GLint stacks) = dlsym(RTLD_NEXT, "glutWireSphere");
void FGAPIENTRY (*_glutWireSphere)(double radius, GLint slices, GLint stacks) =
dlsym(RTLD_NEXT, "glutWireSphere");
_glutWireSphere(radius, slices, stacks);
return;
}
@@ -439,7 +461,8 @@ void FGAPIENTRY glutWireCone(double base, double height, GLint slices, GLint sta
{
if (getConfig()->noSDL)
{
void FGAPIENTRY (*_glutWireCone)(double base, double height, GLint slices, GLint stacks) = dlsym(RTLD_NEXT, "glutWireCone");
void FGAPIENTRY (*_glutWireCone)(double base, double height, GLint slices, GLint stacks) =
dlsym(RTLD_NEXT, "glutWireCone");
_glutWireCone(base, height, slices, stacks);
return;
}
@@ -450,7 +473,8 @@ void FGAPIENTRY glutSolidCone(double base, double height, GLint slices, GLint st
{
if (getConfig()->noSDL)
{
void FGAPIENTRY (*_glutSolidCone)(double base, double height, GLint slices, GLint stacks) = dlsym(RTLD_NEXT, "glutSolidCone");
void FGAPIENTRY (*_glutSolidCone)(double base, double height, GLint slices, GLint stacks) =
dlsym(RTLD_NEXT, "glutSolidCone");
_glutSolidCone(base, height, slices, stacks);
return;
}
-25
View File
@@ -1,29 +1,4 @@
#ifndef GLUTHOOKS_H
#define GLUTHOOKS_H
#include <GL/glx.h>
int myCreateWindow(int *param1);
void hod4glXSwapBuffers(Display *dpy, GLXDrawable drawable);
#endif
// #include <GL/freeglut.h>
// /* The bitmap font structure taken from freeglut*/
// typedef struct tagSFG_Font SFG_Font;
// struct tagSFG_Font
// {
// char *Name; /* The source font name */
// int Quantity; /* Number of chars in font */
// int Height; /* Height of the characters */
// const GLubyte **Characters; /* The characters mapping */
// float xorig, yorig; /* Relative origin of the character */
// };
// extern SFG_Font fgFontFixed8x13;
// extern SFG_Font fgFontFixed9x15;
// extern SFG_Font fgFontHelvetica10;
// extern SFG_Font fgFontHelvetica12;
// extern SFG_Font fgFontHelvetica18;
// extern SFG_Font fgFontTimesRoman10;
// extern SFG_Font fgFontTimesRoman24;
+125 -61
View File
@@ -19,6 +19,7 @@
#include <dlfcn.h>
#include <SDL2/SDL.h>
#include <sys/time.h>
#include <stdio.h>
#include "fps_limiter.h"
#include "sdlcalls.h"
@@ -27,27 +28,66 @@
#include "border.h"
bool sdlGame = false;
extern uint32_t gId;
extern SDL_Window *SDLwindow;
extern SDL_GLContext SDLcontext;
extern char SDLgameTitle[];
extern fps_limit fpsLimit;
extern Window win;
extern Window window;
void glXToSDLSwapBuffers(Display *dpy, GLXDrawable drawable)
void glXSwapBuffers(Display *dpy, GLXDrawable drawable)
{
pollEvents();
void (*_glXSwapBuffers)(Display *dpy, GLXDrawable drawable) = dlsym(RTLD_NEXT, "glXSwapBuffers");
EmulatorConfig *config = getConfig();
if (config->borderEnabled)
drawGameBorder(config->width, config->height, config->whiteBorderPercentage, config->blackBorderPercentage);
SDL_GL_SwapWindow(SDLwindow);
if (getConfig()->noSDL)
{
switch (gId)
{
case OUTRUN_2_SP_SDX:
case OUTRUN_2_SP_SDX_REVA:
case OUTRUN_2_SP_SDX_REVA_TEST:
case OUTRUN_2_SP_SDX_REVA_TEST2:
case OUTRUN_2_SP_SDX_TEST:
{
XEvent event;
while (XPending(dpy))
{
XNextEvent(dpy, &event);
}
}
}
}
else
{
pollEvents();
}
if (getConfig()->noSDL)
{
_glXSwapBuffers(dpy, drawable);
}
else
{
SDL_GL_SwapWindow(SDLwindow);
}
if (getConfig()->fpsLimiter)
{
fpsLimit.frameStart = Clock_now();
FpsLimiter(&fpsLimit);
fpsLimit.frameEnd = Clock_now();
}
if (getConfig()->noSDL)
{
XStoreName(dpy, window, "");
return;
}
char windowTitle[512];
sprintf(windowTitle, "%s - FPS: %.2f", SDLgameTitle, calculateFps());
SDL_SetWindowTitle(SDLwindow, windowTitle);
@@ -55,7 +95,7 @@ void glXToSDLSwapBuffers(Display *dpy, GLXDrawable drawable)
int glxSDLmyCreateWindow(int *param1)
{
glutInitSDL(0, 0);
initSDL(0, 0);
char *buf = malloc(512);
memset(buf, '\0', 512);
// param1[0x17] = (intptr_t)(void *)buf; // window;
@@ -63,16 +103,37 @@ int glxSDLmyCreateWindow(int *param1)
return 1;
}
static int nVidiaAttribs[] = {GLX_RGBA,
GLX_DOUBLEBUFFER,
GLX_RED_SIZE,
8,
GLX_GREEN_SIZE,
8,
GLX_BLUE_SIZE,
8,
GLX_ALPHA_SIZE,
8,
GLX_DEPTH_SIZE,
16,
GLX_STENCIL_SIZE,
8,
None};
XVisualInfo *glXChooseVisual(Display *dpy, int screen, int *attribList)
{
XVisualInfo *(*_glXChooseVisual)(Display *dpy, int screen, int *attribList) = dlsym(RTLD_NEXT, "glXChooseVisual");
if (sdlGame)
return 0;
if (getConfig()->GPUVendor == NVIDIA_GPU)
{
return _glXChooseVisual(dpy, screen, nVidiaAttribs);
}
return _glXChooseVisual(dpy, screen, attribList);
}
void GLAPIENTRY openglDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message,
const void *userParam)
void GLAPIENTRY openglDebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length,
const GLchar *message, const void *userParam)
{
if (id == 1099)
return;
@@ -91,35 +152,6 @@ void GLAPIENTRY openglDebugCallback(GLenum source, GLenum type, GLuint id, GLenu
}
}
void glXSwapBuffers(Display *dpy, GLXDrawable drawable)
{
void (*_glXSwapBuffers)(Display *dpy, GLXDrawable drawable) = dlsym(RTLD_NEXT, "glXSwapBuffers");
EmulatorConfig *config = getConfig();
if (config->borderEnabled)
drawGameBorder(config->width, config->height, config->whiteBorderPercentage, config->blackBorderPercentage);
int gId = config->crc32;
if (getConfig()->noSDL && (gId == OUTRUN_2_SP_SDX || gId == OUTRUN_2_SP_SDX_REVA || gId == OUTRUN_2_SP_SDX_REVA_TEST ||
gId == OUTRUN_2_SP_SDX_REVA_TEST2 || gId == OUTRUN_2_SP_SDX_TEST))
{
XEvent event;
while (XPending(dpy))
{
XNextEvent(dpy, &event);
}
}
_glXSwapBuffers(dpy, drawable);
if (config->fpsLimiter)
{
fpsLimit.frameStart = Clock_now();
FpsLimiter(&fpsLimit);
fpsLimit.frameEnd = Clock_now();
}
XStoreName(dpy, win, "");
}
GLXContext glXCreateContext(Display *dpy, XVisualInfo *vis, GLXContext shareList, Bool direct)
{
GLXContext (*_glXCreateContext)(Display *dpy, XVisualInfo *vis, GLXContext shareList, Bool direct) =
@@ -150,7 +182,8 @@ GLXContext glXGetCurrentContext()
GLXPbuffer glXCreatePbuffer(Display *dpy, GLXFBConfig config, const int *attrib_list)
{
GLXPbuffer (*_glXCreatePbuffer)(Display *dpy, GLXFBConfig config, const int *attrib_list) = dlsym(RTLD_NEXT, "glXCreatePbuffer");
GLXPbuffer (*_glXCreatePbuffer)(Display *dpy, GLXFBConfig config, const int *attrib_list) =
dlsym(RTLD_NEXT, "glXCreatePbuffer");
if (sdlGame)
return 0;
return _glXCreatePbuffer(dpy, config, attrib_list);
@@ -174,7 +207,8 @@ void glXDestroyPbuffer(Display *dpy, GLXPbuffer pbuf)
XVisualInfo *glXGetVisualFromFBConfig(Display *dpy, GLXFBConfig config)
{
XVisualInfo *(*_glXGetVisualFromFBConfig)(Display *dpy, GLXFBConfig config) = dlsym(RTLD_NEXT, "glXGetVisualFromFBConfig");
XVisualInfo *(*_glXGetVisualFromFBConfig)(Display *dpy, GLXFBConfig config) =
dlsym(RTLD_NEXT, "glXGetVisualFromFBConfig");
if (sdlGame)
return 0;
return _glXGetVisualFromFBConfig(dpy, config);
@@ -204,35 +238,44 @@ GLXFBConfig *glXChooseFBConfig(Display *dpy, int screen, const int *attrib_list,
GLXFBConfig *(*_glXChooseFBConfig)(Display *dpy, int screen, const int *attrib_list, int *nelements) =
dlsym(RTLD_NEXT, "glXChooseFBConfig");
int gId = getConfig()->crc32;
char *__GLX_VENDOR_LIBRARY_NAME = getenv("__GLX_VENDOR_LIBRARY_NAME");
char *__NV_PRIME_RENDER_OFFLOAD = getenv("__NV_PRIME_RENDER_OFFLOAD");
if (__GLX_VENDOR_LIBRARY_NAME == NULL)
__GLX_VENDOR_LIBRARY_NAME = " ";
if (__NV_PRIME_RENDER_OFFLOAD == NULL)
__NV_PRIME_RENDER_OFFLOAD = " ";
if ((strcmp(__GLX_VENDOR_LIBRARY_NAME, "nvidia") == 0) && (strcmp(__NV_PRIME_RENDER_OFFLOAD, "1") == 0) &&
((gId == THE_HOUSE_OF_THE_DEAD_4_REVA) || (gId == THE_HOUSE_OF_THE_DEAD_4_REVB) || (gId == THE_HOUSE_OF_THE_DEAD_4_REVC) ||
(gId == THE_HOUSE_OF_THE_DEAD_4_SPECIAL) || (gId == THE_HOUSE_OF_THE_DEAD_4_SPECIAL_REVB) || (gId == THE_HOUSE_OF_THE_DEAD_EX) ||
(gId == TOO_SPICY)))
switch (gId)
{
for (int i = 0; attrib_list[i] != None; i += 2)
case THE_HOUSE_OF_THE_DEAD_4_REVA:
case THE_HOUSE_OF_THE_DEAD_4_REVB:
case THE_HOUSE_OF_THE_DEAD_4_REVC:
case THE_HOUSE_OF_THE_DEAD_4_SPECIAL:
case THE_HOUSE_OF_THE_DEAD_4_SPECIAL_REVB:
case THE_HOUSE_OF_THE_DEAD_EX:
case TOO_SPICY:
{
if (strcmp(__GLX_VENDOR_LIBRARY_NAME, "nvidia") == 0 && strcmp(__NV_PRIME_RENDER_OFFLOAD, "1") == 0)
{
if (attrib_list[i] == GLX_DOUBLEBUFFER)
for (int i = 0; attrib_list[i] != None; i += 2)
{
int *ptr = (int *)&attrib_list[i + 1];
patchMemory((intptr_t)ptr, "01");
setVariable((intptr_t)ptr, GLX_DONT_CARE);
if (attrib_list[i] == GLX_DOUBLEBUFFER)
{
int *ptr = (int *)&attrib_list[i + 1];
patchMemory((intptr_t)ptr, "01");
setVariable((intptr_t)ptr, GLX_DONT_CARE);
}
}
}
}
}
return _glXChooseFBConfig(dpy, screen, attrib_list, nelements);
}
GLXContext glXCreateNewContext(Display *dpy, GLXFBConfig config, int render_type, GLXContext share_list, Bool direct)
{
GLXContext (*_glXCreateNewContext)(Display *dpy, GLXFBConfig config, int render_type, GLXContext share_list, Bool direct) =
dlsym(RTLD_NEXT, "glXCreateNewContext");
GLXContext (*_glXCreateNewContext)(Display *dpy, GLXFBConfig config, int render_type, GLXContext share_list,
Bool direct) = dlsym(RTLD_NEXT, "glXCreateNewContext");
GLXContext ctx = _glXCreateNewContext(dpy, config, render_type, share_list, direct);
@@ -246,12 +289,20 @@ GLXContext glXCreateNewContext(Display *dpy, GLXFBConfig config, int render_type
return ctx;
}
GLXPbuffer glXCreateGLXPbufferSGIX(Display *dpy, GLXFBConfigSGIX config, unsigned int width, unsigned int height, int *attrib_list)
GLXPbuffer glXCreateGLXPbufferSGIX(Display *dpy, GLXFBConfigSGIX config, unsigned int width, unsigned int height,
int *attrib_list)
{
if (sdlGame)
return 0;
int pbufferAttribs[] = {
GLX_PBUFFER_WIDTH, width, GLX_PBUFFER_HEIGHT, height, GLX_PRESERVED_CONTENTS, true, GLX_LARGEST_PBUFFER, true, None};
int pbufferAttribs[] = {GLX_PBUFFER_WIDTH,
width,
GLX_PBUFFER_HEIGHT,
height,
GLX_PRESERVED_CONTENTS,
true,
GLX_LARGEST_PBUFFER,
true,
None};
return glXCreatePbuffer(dpy, config, pbufferAttribs);
}
@@ -273,19 +324,31 @@ GLXFBConfigSGIX *glXChooseFBConfigSGIX(Display *dpy, int screen, int *attrib_lis
__GLX_VENDOR_LIBRARY_NAME = " ";
if (__NV_PRIME_RENDER_OFFLOAD == NULL)
__NV_PRIME_RENDER_OFFLOAD = " ";
if ((strcmp(__GLX_VENDOR_LIBRARY_NAME, "nvidia") == 0) && (strcmp(__NV_PRIME_RENDER_OFFLOAD, "1") == 0) &&
((gId == INITIALD_4_REVA) || (gId == INITIALD_4_REVB) || (gId == INITIALD_4_REVC) || (gId == INITIALD_4_REVD) ||
(gId == INITIALD_4_REVG) || (gId == INITIALD_4_EXP_REVB) || (gId == INITIALD_4_EXP_REVC) || gId == INITIALD_4_EXP_REVD))
switch (gId)
{
for (int i = 0; attrib_list[i] != None; i += 2)
case INITIALD_4_REVA:
case INITIALD_4_REVB:
case INITIALD_4_REVC:
case INITIALD_4_REVD:
case INITIALD_4_REVG:
case INITIALD_4_EXP_REVB:
case INITIALD_4_EXP_REVC:
case INITIALD_4_EXP_REVD:
{
if (strcmp(__GLX_VENDOR_LIBRARY_NAME, "nvidia") == 0 && strcmp(__NV_PRIME_RENDER_OFFLOAD, "1") == 0)
{
if (attrib_list[i] == GLX_DOUBLEBUFFER)
for (int i = 0; attrib_list[i] != None; i += 2)
{
int *ptr = (int *)&attrib_list[i + 1];
patchMemory((intptr_t)ptr, "01");
if (attrib_list[i] == GLX_DOUBLEBUFFER)
{
int *ptr = (int *)&attrib_list[i + 1];
patchMemory((intptr_t)ptr, "01");
}
}
}
}
}
return glXChooseFBConfig(dpy, screen, attrib_list, nelements);
}
@@ -296,7 +359,8 @@ int glXGetFBConfigAttribSGIX(Display *dpy, GLXFBConfigSGIX config, int attribute
return glXGetFBConfigAttrib(dpy, config, attribute, value);
}
GLXContext glXCreateContextWithConfigSGIX(Display *dpy, GLXFBConfigSGIX config, int render_type, GLXContext share_list, Bool direct)
GLXContext glXCreateContextWithConfigSGIX(Display *dpy, GLXFBConfigSGIX config, int render_type, GLXContext share_list,
Bool direct)
{
if (sdlGame)
return 0;
+477 -128
View File
@@ -1,6 +1,7 @@
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#include <libgen.h>
#include <stdint.h>
#include <time.h>
#endif
@@ -11,7 +12,6 @@
#undef __x86_64__
#include <arpa/inet.h>
#include <dlfcn.h>
#include <errno.h>
#include <link.h>
#include <linux/sockios.h>
#include <math.h>
@@ -30,8 +30,6 @@
#include <ifaddrs.h>
#include <dirent.h>
#include "hook.h"
#include "baseboard.h"
#include "config.h"
#include "driveboard.h"
@@ -47,7 +45,11 @@
#include "shader_patches.h"
#include "fps_limiter.h"
#include "evdevinput.h"
#include "card_reader.h"
#include "touchscreen.h"
#include "log.h"
#include "resources/font.h"
#include "resources/logo.h"
#define HOOK_FILE_NAME "/dev/zero"
@@ -63,17 +65,28 @@
#define FILE_RW1 3
#define FILE_RW2 4
#define FILE_HARLEY 5
#define FILE_FONT_ABC 6
#define FILE_FONT_TGA 7
#define FILE_LOGO_TGA 8
#define ROUTE 9
int hooks[5] = {-1, -1, -1, -1, -1};
FILE *fileHooks[6] = {NULL, NULL, NULL, NULL, NULL, NULL};
int fileRead[6] = {0, 0, 0, 0, 0, 0};
FILE *fileHooks[10] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
int fileRead[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
char envpath[100];
int fontABCidx = 0;
int fontTGAidx = 0;
int logoTGAidx = 0;
uint32_t elf_crc = 0;
uint32_t gId = 0;
extern int hummerExtremeShaderFileIndex;
extern bool cachedShaderFilesLoaded;
extern char vf5StageNameAbbr[5];
bool phShowCursorInGame = false;
extern fps_limit fpsLimit;
Controllers controllers = {0};
@@ -93,7 +106,9 @@ static void handleSegfault(int signal, siginfo_t *info, void *ptr)
ucontext_t *ctx = ptr;
// Get the address of the instruction causing the segfault
uint8_t *code = (uint8_t *)ctx->uc_mcontext.gregs[REG_EIP];
// uint8_t *code = (uint8_t *)ctx->uc_mcontext.gregs[REG_EIP];
greg_t eip_value = ctx->uc_mcontext.gregs[REG_EIP];
uint8_t *code = (uint8_t *)(uintptr_t)eip_value; // Use uintptr_t to ensure proper alignment
switch (*code)
{
@@ -162,9 +177,36 @@ static void handleSegfault(int signal, siginfo_t *info, void *ptr)
}
}
char *checkIDlike()
{
FILE *file = fopen("/etc/os-release", "r");
if (!file)
{
perror("Failed to open /etc/os-release");
return NULL;
}
char line[256];
char *result = NULL;
while (fgets(line, sizeof(line), file))
{
if (strncmp(line, "ID_LIKE=", 8) == 0)
{
char *id_like = strchr(line, '=');
if (id_like)
{
result = strdup(id_like);
break;
}
}
}
fclose(file);
return result;
}
void __attribute__((constructor)) hook_init()
{
// Get offsets of the Game's ELF and calculate CRC32.
dl_iterate_phdr(callback, NULL);
@@ -174,13 +216,27 @@ void __attribute__((constructor)) hook_init()
act.sa_flags = SA_SIGINFO;
sigaction(SIGSEGV, &act, NULL);
initConfig();
char *envPath = getenv("LINDBERGH_CONFIG_PATH");
initConfig(envPath);
gId = getConfig()->crc32;
char *id_like = checkIDlike();
if (id_like == NULL)
{
log_warn("Unable to get system info on current OS");
}
else if (strstr(id_like, "debian") == NULL)
{
log_warn("Seems like you're not in debian-like system. There might be unexpected issues.");
}
if (getConfig()->fpsLimiter == 1)
{
fpsLimit.targetFrameTime = 1000000 / getConfig()->fpsTarget;
fpsLimit.frameEnd = Clock_now();
}
getGPUVendor();
if (initPatch() != 0)
@@ -213,14 +269,18 @@ void __attribute__((constructor)) hook_init()
exit(1);
}
if (getConfig()->emulateCardreader)
{
if (initCardReader() != 0)
exit(1);
}
if (initInput() != 0)
exit(1);
if (initControllers(&controllers) != 0)
exit(1);
securityBoardSetDipResolution(getConfig()->width, getConfig()->height);
printf("\nSEGA Lindbergh Emulator\nBy the Lindbergh Development Team 2025\n\n");
@@ -238,21 +298,26 @@ void __attribute__((constructor)) hook_init()
}
printf("\n");
if (getConfig()->GPUVendor == ATI_GPU
&& ((getConfig()->crc32 == LETS_GO_JUNGLE) || (getConfig()->crc32 == LETS_GO_JUNGLE_REVA) ||
(getConfig()->crc32 == LETS_GO_JUNGLE_SPECIAL) || (getConfig()->crc32 == AFTER_BURNER_CLIMAX) ||
(getConfig()->crc32 == AFTER_BURNER_CLIMAX_REVA) || (getConfig()->crc32 == AFTER_BURNER_CLIMAX_REVB) ||
(getConfig()->crc32 == AFTER_BURNER_CLIMAX_SDX) || (getConfig()->crc32 == AFTER_BURNER_CLIMAX_SDX_REVA) ||
(getConfig()->crc32 == AFTER_BURNER_CLIMAX_SE) || (getConfig()->crc32 == AFTER_BURNER_CLIMAX_SE_REVA) ||
(getConfig()->crc32 == INITIALD_5_JAP_REVA) || (getConfig()->crc32 == INITIALD_5_JAP_REVF) ||
(getConfig()->crc32 == INITIALD_5_EXP_30) || (getConfig()->crc32 == INITIALD_5_EXP_40))) {
printf("WARNING: Game %s is unsupported in AMD GPU with ATI driver\n",getGameName());
}
if (getConfig()->lgjRenderWithMesa &&
((getConfig()->crc32 == LETS_GO_JUNGLE) || (getConfig()->crc32 == LETS_GO_JUNGLE_REVA) ||
(getConfig()->crc32 == LETS_GO_JUNGLE_SPECIAL)))
switch (gId)
{
getConfig()->GPUVendor = AMD_GPU;
case LETS_GO_JUNGLE:
case LETS_GO_JUNGLE_REVA:
case LETS_GO_JUNGLE_SPECIAL:
case AFTER_BURNER_CLIMAX:
case AFTER_BURNER_CLIMAX_REVA:
case AFTER_BURNER_CLIMAX_REVB:
case AFTER_BURNER_CLIMAX_SDX:
case AFTER_BURNER_CLIMAX_SDX_REVA:
case AFTER_BURNER_CLIMAX_SE:
case AFTER_BURNER_CLIMAX_SE_REVA:
case INITIALD_5_JAP_REVA:
case INITIALD_5_JAP_REVF:
case INITIALD_5_EXP_20:
case INITIALD_5_EXP_20A:
if (getConfig()->GPUVendor == ATI_GPU)
{
printf("WARNING: Game %s is unsupported in AMD GPU with ATI driver\n", getGameName());
}
}
}
@@ -260,10 +325,13 @@ DIR *opendir(const char *dirname)
{
DIR *(*_opendir)(const char *dirname) = dlsym(RTLD_NEXT, "opendir");
int gId = getConfig()->crc32;
if (gId == INITIALD_5_EXP_30 || gId == INITIALD_5_EXP_40 || gId == INITIALD_5_JAP_REVA ||
gId == INITIALD_5_JAP_REVF)
switch (gId)
{
case INITIALD_5_EXP:
case INITIALD_5_EXP_20:
case INITIALD_5_EXP_20A:
case INITIALD_5_JAP_REVA:
case INITIALD_5_JAP_REVF:
if (strcmp(dirname, "/tmp/") == 0)
{
return _opendir(dirname + 1);
@@ -306,27 +374,40 @@ int open(const char *pathname, int flags, ...)
if (strcmp(pathname, "/dev/ttyS0") == 0 || strcmp(pathname, "/dev/tts/0") == 0)
{
if (getConfig()->emulateDriveboard == 0 && getConfig()->emulateRideboard == 0)
if (getConfig()->emulateDriveboard == 0 && getConfig()->emulateRideboard == 0 && getConfig()->emulateCardreader == 0 &&
getConfig()->emulateTouchscreen == 0)
return _open(getConfig()->serial1Path, flags, mode);
if (hooks[SERIAL0] != -1)
return -1;
if (hooks[SERIAL0] != -1 && getConfig()->emulateCardreader && gId != R_TUNED)
{
return hooks[SERIAL0];
}
hooks[SERIAL0] = _open(HOOK_FILE_NAME, flags, mode);
log_warn("SERIAL0 Opened %d\n", hooks[SERIAL0]);
printf("Warning: SERIAL0 Opened %d\n", hooks[SERIAL0]);
if (getConfig()->emulateCardreader == 1 && gId != R_TUNED)
cardReaderSetFd(0, hooks[SERIAL0], getConfig()->cardFile1);
return hooks[SERIAL0];
}
if (strcmp(pathname, "/dev/ttyS1") == 0 || strcmp(pathname, "/dev/tts/1") == 0)
{
if (getConfig()->emulateMotionboard == 0)
if (getConfig()->emulateDriveboard == 0 && getConfig()->emulateMotionboard == 0 && getConfig()->emulateCardreader == 0)
return _open(getConfig()->serial2Path, flags, mode);
if (hooks[SERIAL1] != -1)
return -1;
if (hooks[SERIAL1] != -1 && getConfig()->emulateCardreader && gId != R_TUNED)
{
return hooks[SERIAL1];
}
hooks[SERIAL1] = _open(HOOK_FILE_NAME, flags, mode);
log_warn("SERIAL1 opened %d\n", hooks[SERIAL1]);
if (getConfig()->emulateCardreader == 1)
cardReaderSetFd(1, hooks[SERIAL1], getConfig()->cardFile2);
return hooks[SERIAL1];
}
@@ -370,24 +451,70 @@ FILE *fopen(const char *restrict pathname, const char *restrict mode)
{
FILE *(*_fopen)(const char *restrict pathname, const char *restrict mode) = dlsym(RTLD_NEXT, "fopen");
if (strcmp(pathname, "/proc/net/route") == 0)
{
return NULL;
}
if (strcmp(pathname, "/root/lindbergrc") == 0)
{
return _fopen("lindbergrc", mode);
}
if ((strcmp(pathname, "/usr/lib/boot/logo.tga") == 0) || (strcmp(pathname, "/usr/lib/boot/logo.tga") == 0))
if ((strcmp(pathname, "/usr/lib/boot/logo.tga") == 0))
{
return _fopen("logo.tga", mode);
if (!getConfig()->disableBuiltinLogos)
{
fileRead[FILE_LOGO_TGA] = 0;
fileHooks[FILE_LOGO_TGA] = _fopen(HOOK_FILE_NAME, mode);
return fileHooks[FILE_LOGO_TGA];
}
else
{
return _fopen("logo.tga", mode);
}
}
if (strcmp(pathname, "/usr/lib/boot/logo_red.tga") == 0)
{
if (!getConfig()->disableBuiltinLogos)
{
fileRead[FILE_LOGO_TGA] = 1;
fileHooks[FILE_LOGO_TGA] = _fopen(HOOK_FILE_NAME, mode);
return fileHooks[FILE_LOGO_TGA];
}
else
{
return _fopen("logo_red.tga", mode);
}
}
if (strcmp(pathname, "/usr/lib/boot/LucidaConsole_12.tga") == 0)
{
return _fopen("LucidaConsole_12.tga", mode);
if (!getConfig()->disableBuiltinFont)
{
fileRead[FILE_FONT_TGA] = 0;
fileHooks[FILE_FONT_TGA] = _fopen(HOOK_FILE_NAME, mode);
return fileHooks[FILE_FONT_TGA];
}
else
{
return _fopen("LucidaConsole_12.tga", mode);
}
}
if (strcmp(pathname, "/usr/lib/boot/LucidaConsole_12.abc") == 0)
{
return _fopen("LucidaConsole_12.abc", mode);
if (!getConfig()->disableBuiltinFont)
{
fileRead[FILE_FONT_ABC] = 0;
fileHooks[FILE_FONT_ABC] = _fopen(HOOK_FILE_NAME, mode);
return fileHooks[FILE_FONT_ABC];
}
else
{
return _fopen("LucidaConsole_12.abc", mode);
}
}
if (strcmp(pathname, "/proc/cpuinfo") == 0)
@@ -397,18 +524,32 @@ FILE *fopen(const char *restrict pathname, const char *restrict mode)
return fileHooks[CPUINFO];
}
if (strcmp(pathname, "/usr/lib/boot/logo_red.tga") == 0)
{
return _fopen("logo_red.tga", mode);
}
if (strcmp(pathname, "/usr/lib/boot/SEGA_KakuGothic-DB-Roman_12.tga") == 0)
{
return _fopen("SEGA_KakuGothic-DB-Roman_12.tga", mode);
if (!getConfig()->disableBuiltinFont)
{
fileRead[FILE_FONT_TGA] = 0;
fileHooks[FILE_FONT_TGA] = _fopen(HOOK_FILE_NAME, mode);
return fileHooks[FILE_FONT_TGA];
}
else
{
return _fopen("SEGA_KakuGothic-DB-Roman_12.tga", mode);
}
}
if (strcmp(pathname, "/usr/lib/boot/SEGA_KakuGothic-DB-Roman_12.abc") == 0)
{
return _fopen("SEGA_KakuGothic-DB-Roman_12.abc", mode);
if (!getConfig()->disableBuiltinFont)
{
fileRead[FILE_FONT_ABC] = 0;
fileHooks[FILE_FONT_ABC] = _fopen(HOOK_FILE_NAME, mode);
return fileHooks[FILE_FONT_ABC];
}
else
{
return _fopen("SEGA_KakuGothic-DB-Roman_12.abc", mode);
}
}
if (strcmp(pathname, "/proc/bus/pci/00/1f.0") == 0)
@@ -437,13 +578,6 @@ FILE *fopen(const char *restrict pathname, const char *restrict mode)
return 0;
}
if (strcmp("./../fs/data/cse_credit.bnk", pathname) == 0)
{
void *addr = __builtin_return_address(0);
fileHooks[FILE_HARLEY] = _fopen(pathname, mode);
return fileHooks[FILE_HARLEY];
}
if (cachedShaderFilesLoaded)
{
void *addr = __builtin_return_address(0);
@@ -476,16 +610,35 @@ FILE *fopen(const char *restrict pathname, const char *restrict mode)
}
}
int gId = getConfig()->crc32;
if (gId == INITIALD_5_EXP_30 || gId == INITIALD_5_EXP_40 || gId == INITIALD_5_JAP_REVA ||
gId == INITIALD_5_JAP_REVF)
switch (gId)
{
case INITIALD_5_EXP:
case INITIALD_5_EXP_20:
case INITIALD_5_EXP_20A:
case INITIALD_5_JAP_REVA:
case INITIALD_5_JAP_REVF:
if (strncmp(pathname, "/tmp/", 5) == 0)
{
return fopen(pathname + 1, mode);
}
}
if (gId == PRIMEVAL_HUNT)
{
if (strstr(pathname, "/data/lua/texture/start_stage") != NULL)
phShowCursorInGame = true;
else if (strstr(pathname, "/data/texture/weapon_select/") != NULL)
phShowCursorInGame = false;
else if (strstr(pathname, "/data/texture/stage_select/") != NULL)
phShowCursorInGame = false;
else if (strstr(pathname, "/data/texture/name_entry/") != NULL)
phShowCursorInGame = false;
else if (strstr(pathname, "/data/texture/game_end/") != NULL)
phShowCursorInGame = false;
else if (strstr(pathname, "/data/lua/stage/bonus_0") != NULL)
phShowCursorInGame = true;
}
// printf("Path= %s\n", pathname);
return _fopen(pathname, mode);
@@ -505,46 +658,85 @@ FILE *fopen64(const char *pathname, const char *mode)
if (strcmp(pathname, "/usr/lib/boot/logo_red.tga") == 0)
{
return _fopen64("logo_red.tga", mode);
if (!getConfig()->disableBuiltinLogos)
{
fileRead[FILE_LOGO_TGA] = 1;
fileHooks[FILE_LOGO_TGA] = _fopen64(HOOK_FILE_NAME, mode);
return fileHooks[FILE_LOGO_TGA];
}
else
{
return _fopen64("logo_red.tga", mode);
}
}
if (strcmp(pathname, "/usr/lib/boot/logo.tga") == 0)
{
return _fopen64("logo.tga", mode);
if (!getConfig()->disableBuiltinLogos)
{
fileRead[FILE_LOGO_TGA] = 0;
fileHooks[FILE_LOGO_TGA] = _fopen64(HOOK_FILE_NAME, mode);
return fileHooks[FILE_LOGO_TGA];
}
else
{
return _fopen64("logo.tga", mode);
}
}
if (strcmp(pathname, "/usr/lib/boot/SEGA_KakuGothic-DB-Roman_12.tga") == 0)
{
return _fopen64("SEGA_KakuGothic-DB-Roman_12.tga", mode);
if (!getConfig()->disableBuiltinFont)
{
fileRead[FILE_FONT_TGA] = 0;
fileHooks[FILE_FONT_TGA] = _fopen64(HOOK_FILE_NAME, mode);
return fileHooks[FILE_FONT_TGA];
}
else
{
return _fopen64("SEGA_KakuGothic-DB-Roman_12.tga", mode);
}
}
if (strcmp(pathname, "/usr/lib/boot/SEGA_KakuGothic-DB-Roman_12.abc") == 0)
{
return _fopen64("SEGA_KakuGothic-DB-Roman_12.abc", mode);
if (!getConfig()->disableBuiltinFont)
{
fileRead[FILE_FONT_ABC] = 0;
fileHooks[FILE_FONT_ABC] = _fopen64(HOOK_FILE_NAME, mode);
return fileHooks[FILE_FONT_ABC];
}
else
{
return _fopen64("SEGA_KakuGothic-DB-Roman_12.abc", mode);
}
}
if ((getConfig()->crc32 == HUMMER) || (getConfig()->crc32 == HUMMER_SDLX) ||
(getConfig()->crc32 == HUMMER_EXTREME) || (getConfig()->crc32 == HUMMER_EXTREME_MDX))
int idx;
switch (gId)
{
int idx;
case HUMMER:
case HUMMER_SDLX:
case HUMMER_EXTREME:
case HUMMER_EXTREME_MDX:
if (shaderFileInList(pathname, &idx))
{
hummerExtremeShaderFileIndex = idx;
}
}
if ((getConfig()->crc32 == VIRTUA_FIGHTER_5_FINAL_SHOWDOWN_REVA || getConfig()->crc32 == VIRTUA_FIGHTER_5_FINAL_SHOWDOWN_REVB ||
getConfig()->crc32 == VIRTUA_FIGHTER_5_FINAL_SHOWDOWN_REVB_6000) &&
(getConfig()->GPUVendor != NVIDIA_GPU && getConfig()->GPUVendor != ATI_GPU))
{
char *filename = basename((char *)pathname);
if (strstr(filename, "light_") || strstr(filename, "glow_"))
break;
case VIRTUA_FIGHTER_5_FINAL_SHOWDOWN_REVA:
case VIRTUA_FIGHTER_5_FINAL_SHOWDOWN_REVB:
case VIRTUA_FIGHTER_5_FINAL_SHOWDOWN_REVB_6000:
if (getConfig()->GPUVendor != NVIDIA_GPU && getConfig()->GPUVendor != ATI_GPU)
{
printf("Stage: %s\n", filename);
char *start = strchr(filename, '_') + 1;
char *end = strstr(filename, ".txt");
strncpy(vf5StageNameAbbr, start, end - start);
vf5StageNameAbbr[end - start] = '\0';
char *filename = basename((char *)pathname);
if (strstr(filename, "light_") || strstr(filename, "glow_"))
{
char *start = strchr(filename, '_') + 1;
char *end = strstr(filename, ".txt");
strncpy(vf5StageNameAbbr, start, end - start);
vf5StageNameAbbr[end - start] = '\0';
}
}
}
@@ -555,13 +747,19 @@ FILE *fopen64(const char *pathname, const char *mode)
int fclose(FILE *stream)
{
int (*_fclose)(FILE *stream) = dlsym(RTLD_NEXT, "fclose");
for (int i = 0; i < 7; i++)
for (int i = 0; i < 9; i++)
{
if (fileHooks[i] == stream)
{
int r = _fclose(stream);
fileHooks[i] = NULL;
fileRead[i] = 0;
if (stream == fileHooks[FILE_FONT_ABC])
fontABCidx = 0;
if (stream == fileHooks[FILE_FONT_TGA])
fontTGAidx = 0;
if (stream == fileHooks[FILE_LOGO_TGA])
logoTGAidx = 0;
return r;
}
}
@@ -653,9 +851,24 @@ ssize_t read(int fd, void *buf, size_t count)
return driveboardRead(fd, buf, count);
}
if (fd == hooks[SERIAL0] && getConfig()->emulateCardreader)
{
return cardReaderRead(fd, buf, count);
}
if (fd == hooks[SERIAL1] && getConfig()->emulateCardreader)
{
return cardReaderRead(fd, buf, count);
}
// If we don't hook the serial just reply with nothing
if (fd == hooks[SERIAL0] || fd == hooks[SERIAL1])
{
if (gId == PRIMEVAL_HUNT && getConfig()->emulateTouchscreen == 1)
{
phRead(fd, buf, count);
return 1;
}
return -1;
}
@@ -688,9 +901,33 @@ size_t fread(void *buf, size_t size, size_t count, FILE *stream)
return freadReplace(buf, size, count, fileRead[FILE_RW2]);
}
if (stream == fileHooks[FILE_HARLEY])
// if (stream == fileHooks[FILE_HARLEY])
// {
// return harleyFreadReplace(buf, size, count, fileHooks[FILE_HARLEY]);
// }
if (stream == fileHooks[FILE_FONT_ABC])
{
return harleyFreadReplace(buf, size, count, fileHooks[FILE_HARLEY]);
memcpy(buf, fontABC + fontABCidx, size * count);
fontABCidx += (size * count);
return size * count;
}
if (stream == fileHooks[FILE_FONT_TGA])
{
memcpy(buf, fontTGA + fontTGAidx, size * count);
fontTGAidx += (size * count);
return size * count;
}
if (stream == fileHooks[FILE_LOGO_TGA])
{
if (fileRead[FILE_LOGO_TGA] == 0)
memcpy(buf, logoLL + logoTGAidx, size * count);
else
memcpy(buf, logoLLRed + logoTGAidx, size * count);
logoTGAidx += (size * count);
return size * count;
}
return _fread(buf, size, count, stream);
@@ -709,9 +946,50 @@ long int ftell(FILE *stream)
return ftellGetShaderSize(fileRead[FILE_RW2]);
}
if (stream == fileHooks[FILE_FONT_ABC])
{
return fontABClen;
}
return _ftell(stream);
}
int fseek(FILE *stream, long int offset, int whence)
{
int (*_fseek)(FILE *stream, long int offset, int whence) = dlsym(RTLD_NEXT, "fseek");
if (stream == fileHooks[FILE_FONT_ABC])
{
switch (whence)
{
case SEEK_CUR:
break;
case SEEK_SET:
fontABCidx = 0;
break;
case SEEK_END:
fontABCidx = fontABClen;
break;
}
return fontABCidx;
}
return _fseek(stream, offset, whence);
}
void rewind(FILE *stream)
{
void (*_rewind)(FILE *stream) = dlsym(RTLD_NEXT, "rewind");
if (stream == fileHooks[FILE_FONT_ABC])
{
fontABCidx = 0;
return;
}
_rewind(stream);
}
ssize_t write(int fd, const void *buf, size_t count)
{
int (*_write)(int fd, const void *buf, size_t count) = dlsym(RTLD_NEXT, "write");
@@ -728,9 +1006,25 @@ ssize_t write(int fd, const void *buf, size_t count)
if (fd == hooks[SERIAL0] && getConfig()->emulateDriveboard)
{
// printf("Write addr: %p\n", addr);
return driveboardWrite(fd, buf, count);
}
if (fd == hooks[SERIAL1] && getConfig()->emulateDriveboard && gId != R_TUNED)
{
return driveboardWrite(fd, buf, count);
}
if (fd == hooks[SERIAL0] && getConfig()->emulateCardreader)
{
return cardReaderWrite(fd, buf, count);
}
if (fd == hooks[SERIAL1] && getConfig()->emulateCardreader)
{
return cardReaderWrite(fd, buf, count);
}
return _write(fd, buf, count);
}
@@ -738,15 +1032,6 @@ int ioctl(int fd, unsigned int request, void *data)
{
int (*_ioctl)(int fd, int request, void *data) = dlsym(RTLD_NEXT, "ioctl");
// Attempt to stop access to the ethernet ports
if ((request == SIOCSIFADDR) || (request == SIOCSIFFLAGS) || (request == SIOCSIFHWADDR) ||
(request == SIOCSIFHWBROADCAST) || (request == SIOCDELRT) || (request == SIOCADDRT) ||
(request == SIOCSIFNETMASK))
{
errno = ENXIO;
return -1;
}
if (fd == hooks[EEPROM])
{
if (request == 0xC04064A0)
@@ -759,15 +1044,79 @@ int ioctl(int fd, unsigned int request, void *data)
return baseboardIoctl(fd, request, data);
}
// Just accept any IOCTL on serial ports and ignore it
if (fd == hooks[SERIAL0] || fd == hooks[SERIAL1])
{
if (request == 0x541b && gId == R_TUNED && fd == hooks[SERIAL1])
{
uint8_t d = 1;
memcpy(data, &d, sizeof(uint8_t));
}
return 0;
}
return _ioctl(fd, request, data);
}
int tcgetattr(int fd, struct termios *termios_p)
{
int (*_tcgetattr)(int fd, struct termios *termios_p) = dlsym(RTLD_NEXT, "tcgetattr");
if (fd == hooks[SERIAL0] && getConfig()->emulateDriveboard == 1)
return 0;
return _tcgetattr(fd, termios_p);
}
int tcsetattr(int fd, int optional_actions, const struct termios *termios_p)
{
int (*_tcsetattr)(int fd, int optional_actions, const struct termios *termios_p) = dlsym(RTLD_NEXT, "tcsetattr");
if (fd == hooks[SERIAL0] && getConfig()->emulateDriveboard == 1)
return 0;
return _tcsetattr(fd, optional_actions, termios_p);
}
speed_t cfgetispeed(const struct termios *termios_p)
{
speed_t (*_cfgetispeed)(const struct termios *termios_p) = dlsym(RTLD_NEXT, "cfgetispeed");
if (getConfig()->emulateDriveboard == 1)
return B9600;
return _cfgetispeed(termios_p);
}
speed_t cfgetospeed(const struct termios *termios_p)
{
speed_t (*_cfgetospeed)(const struct termios *termios_p) = dlsym(RTLD_NEXT, "cfgetospeed");
if (getConfig()->emulateDriveboard == 1)
return B9600;
return _cfgetospeed(termios_p);
}
int cfsetispeed(struct termios *termios_p, speed_t speed)
{
int (*_cfsetispeed)(struct termios *termios_p, speed_t speed) = dlsym(RTLD_NEXT, "cfsetispeed");
if (getConfig()->emulateDriveboard == 1)
return 0;
return _cfsetispeed(termios_p, speed);
}
int cfsetospeed(struct termios *termios_p, speed_t speed)
{
int (*_cfsetospeed)(struct termios *termios_p, speed_t speed) = dlsym(RTLD_NEXT, "cfsetospeed");
if (getConfig()->emulateDriveboard == 1)
return 0;
return _cfsetospeed(termios_p, speed);
}
int select(int nfds, fd_set *restrict readfds, fd_set *restrict writefds, fd_set *restrict exceptfds,
struct timeval *restrict timeout)
{
@@ -784,6 +1133,11 @@ int select(int nfds, fd_set *restrict readfds, fd_set *restrict writefds, fd_set
return baseboardSelect(nfds, readfds, writefds, exceptfds, timeout);
}
if (getConfig()->emulateCardreader == 1 || getConfig()->emulateDriveboard == 1)
{
return 1;
}
return _select(nfds, readfds, writefds, exceptfds, timeout);
}
@@ -818,6 +1172,9 @@ int system(const char *command)
if (strstr(command, "losetup") != NULL)
return 0;
if (strstr(command, "check_ip.sh") != NULL)
return 0;
return _system(command);
}
@@ -925,28 +1282,6 @@ int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
return _connect(sockfd, addr, addrlen);
}
/**
* Function to calculate CRC32 checksum in memory.
*/
uint32_t get_crc32(const char *s, size_t n)
{
uint32_t crc = 0xFFFFFFFF;
for (size_t i = 0; i < n; i++)
{
char ch = s[i];
for (size_t j = 0; j < 8; j++)
{
uint32_t b = (ch ^ crc) & 1;
crc >>= 1;
if (b)
crc = crc ^ 0xEDB88320;
ch >>= 1;
}
}
return ~crc;
}
/**
* Callback function to get the offset and size of the execution program in memory of the ELF we hook to.
*/
@@ -980,26 +1315,40 @@ int setenv(const char *name, const char *value, int overwrite)
char *getenv(const char *name)
{
char *(*_getenv)(const char *name) = dlsym(RTLD_NEXT, "getenv");
int gId = getConfig()->crc32;
if ((strcmp(name, "TEA_DIR") == 0) &&
((gId == VIRTUA_TENNIS_3) || (gId == VIRTUA_TENNIS_3_TEST) || (gId == VIRTUA_TENNIS_3_REVA) ||
(gId == VIRTUA_TENNIS_3_REVA_TEST) || (gId == VIRTUA_TENNIS_3_REVB) || (gId == VIRTUA_TENNIS_3_REVB_TEST) ||
(gId == VIRTUA_TENNIS_3_REVC) || (gId == VIRTUA_TENNIS_3_REVC_TEST) || ((gId == RAMBO)) || (gId == TOO_SPICY)))
if (strcmp(name, "TEA_DIR") == 0)
{
if (getcwd(envpath, 100) == NULL)
return "";
char *ptr = strrchr(envpath, '/');
if (ptr == NULL)
return "";
*ptr = '\0';
return envpath;
}
else if (strcmp(name, "TEA_DIR") == 0)
{
if (getcwd(envpath, 100) == NULL)
return "";
return envpath;
switch (gId)
{
case VIRTUA_TENNIS_3:
case VIRTUA_TENNIS_3_TEST:
case VIRTUA_TENNIS_3_REVA:
case VIRTUA_TENNIS_3_REVA_TEST:
case VIRTUA_TENNIS_3_REVB:
case VIRTUA_TENNIS_3_REVB_TEST:
case VIRTUA_TENNIS_3_REVC:
case VIRTUA_TENNIS_3_REVC_TEST:
case RAMBO:
case TOO_SPICY:
{
if (getcwd(envpath, 100) == NULL)
return "";
char *ptr = strrchr(envpath, '/');
if (ptr == NULL)
return "";
*ptr = '\0';
return envpath;
}
break;
default:
{
if (getcwd(envpath, 100) == NULL)
return "";
return envpath;
}
}
}
if (strcmp(name, "__GL_SYNC_TO_VBLANK") == 0)
{
return "";
@@ -1040,7 +1389,7 @@ struct tm *localtime_r(const time_t *timep, struct tm *result)
struct tm *(*_localtime_r)(const time_t *, struct tm *) =
(struct tm * (*)(const time_t *, struct tm *)) dlsym(RTLD_NEXT, "localtime_r");
if ((getConfig()->crc32 == MJ4_REVG || getConfig()->crc32 == MJ4_EVO) && getConfig()->mj4EnabledAtT == 1)
if ((gId == MJ4_REVG || gId == MJ4_EVO) && getConfig()->mj4EnabledAtT == 1)
{
time_t target_time = 1735286445;
struct tm *res = _localtime_r(&target_time, result);
-4
View File
@@ -1,4 +0,0 @@
#include <stdint.h>
#include <stddef.h>
uint32_t get_crc32(const char *s, size_t n);
+227 -26
View File
@@ -1,11 +1,15 @@
#ifndef __i386__
#define __i386__
#include "customcursor.h"
#endif
#undef __x86_64__
#include <SDL2/SDL.h>
#include "jvs.h"
#include "config.h"
#include "customcursor.h"
#include "patch.h"
#include "touchscreen.h"
#include <GL/freeglut.h>
#include <GL/glx.h>
@@ -20,6 +24,12 @@
GameType gameType = SHOOTING;
int jvsAnalogueInBits = 10;
extern int phX, phY, phW, phH;
extern int phX2, phY2, phW2, phH2;
int phIsDragging = 0;
extern void *customCursor;
extern void *phTouchCursor;
extern bool phShowCursorInGame;
int initInput()
{
@@ -35,6 +45,105 @@ int initInput()
return 0;
}
void phTouchScreenCursor(int mX, int mY, int *motX, int *motY)
{
if (getConfig()->emulateTouchscreen)
{
switch (getConfig()->phMode)
{
case 0:
case 2:
case 3:
if ((mX >= phX2 && mX <= (phX2 + phW2) && mY >= phY2 && mY <= (phY2 + phH2)) && getConfig()->hideCursor == 0)
{
setCursor(phTouchCursor);
showPhCursor();
}
else if (getConfig()->hideCursor == 1 || phShowCursorInGame == false)
{
hideCursor();
}
else if (phShowCursorInGame && getConfig()->hideCursor == 0)
{
setCursor(customCursor);
showCursor();
}
break;
case 4:
if ((mX >= phX2 && mX <= (phX2 + phW2) && mY >= (phY2 + phH) && mY <= (phY2 + (phH2 + phH))) && getConfig()->hideCursor == 0)
{
setCursor(phTouchCursor);
showPhCursor();
}
else if (getConfig()->hideCursor == 1 || phShowCursorInGame == false)
{
hideCursor();
}
else if (phShowCursorInGame && getConfig()->hideCursor == 0)
{
setCursor(customCursor);
showCursor();
}
}
}
if (mX < phX)
*motX = phX;
if (mX > (phW + phX))
*motX = (phW + phX) - 1;
if (mY > phH + phY)
*motY = (phH + phY) - 1;
if (mY < phY)
*motY = phY;
}
void phTouchClick(int mX, int mY, int type)
{
int x, y;
bool insideTouchScreen = false;
switch (getConfig()->phMode)
{
case 0:
case 2:
case 3:
if (mX >= phX2 && mX <= (phX2 + phW2) && mY >= phY2 && mY <= (phY2 + phH2))
{
x = mX - phW;
y = mY - phY2;
insideTouchScreen = true;
}
break;
case 4:
if (mX >= phX2 && mX <= (phX2 + phW2) && mY >= (phY2 + phH) && mY <= (phY2 + (phH2 + phH)))
{
x = mX - phX2;
y = mY - phH;
insideTouchScreen = true;
}
}
if (insideTouchScreen)
{
if (type == ButtonPress)
phCoordinates(x, y, phW2, phH2, ButtonPress);
else if (type == SDL_MOUSEBUTTONDOWN)
phCoordinates(x, y, phW2, phH2, SDL_MOUSEBUTTONDOWN);
else if (type == ButtonRelease)
phCoordinates(x, y, phW2, phH2, ButtonRelease);
else if (type == SDL_MOUSEBUTTONUP)
phCoordinates(x, y, phW2, phH2, SDL_MOUSEBUTTONUP);
else if (type == MotionNotify)
phCoordinates(x, y, phW2, phH2, MotionNotify);
else if (type == SDL_MOUSEMOTION)
phCoordinates(x, y, phW2, phH2, SDL_MOUSEMOTION);
}
else
{
if (getConfig()->noSDL)
setSwitch(PLAYER_1, BUTTON_1, type == ButtonPress);
else
setSwitch(PLAYER_1, BUTTON_1, type == SDL_MOUSEBUTTONDOWN);
}
}
/**
* Button mapping used for driving games
*/
@@ -281,16 +390,15 @@ int XNextEventShooting(Display *display, XEvent *event_return, int returnValue)
{
int mX = event_return->xmotion.x;
int mY = event_return->xmotion.y;
if (mX < phX)
mX = phX;
if (mX > (phW + phX))
mX = (phW + phX) - 1;
if (mY > phH + phY)
mY = (phH + phY) - 1;
if (mY < phY)
mY = phY;
setAnalogue(ANALOGUE_1, ((double)(mX - phX) / (double)phW) * pow(2, jvsAnalogueInBits));
setAnalogue(ANALOGUE_2, ((double)(mY - phY) / (double)phH) * pow(2, jvsAnalogueInBits));
if (phIsDragging)
phTouchClick(mX, mY, event_return->type);
int motX = mX, motY = mY;
phTouchScreenCursor(mX, mY, &motX, &motY);
setAnalogue(ANALOGUE_1, ((double)(motX - phX) / (double)phW) * pow(2, jvsAnalogueInBits));
setAnalogue(ANALOGUE_2, ((double)(motY - phY) / (double)phH) * pow(2, jvsAnalogueInBits));
}
else
{
@@ -335,7 +443,17 @@ int XNextEventShooting(Display *display, XEvent *event_return, int returnValue)
{
if (event_return->xbutton.button == 1) // Trigger
{
setSwitch(PLAYER_1, BUTTON_1, event_return->type == ButtonPress);
if (getConfig()->crc32 == PRIMEVAL_HUNT && getConfig()->emulateTouchscreen)
{
int mX = event_return->xmotion.x;
int mY = event_return->xmotion.y;
phTouchClick(mX, mY, event_return->type);
phIsDragging = (event_return->type == ButtonPress ? 1 : 0);
}
else
{
setSwitch(PLAYER_1, BUTTON_1, event_return->type == ButtonPress);
}
}
else if (event_return->xbutton.button == 3) // Reload
{
@@ -451,6 +569,7 @@ void sdlEventDriving(SDL_Event *event)
break;
}
}
void sdlEventShooting(SDL_Event *event)
{
KeyMapping keymap = getConfig()->keymap;
@@ -502,10 +621,13 @@ void sdlEventShooting(SDL_Event *event)
setSwitch(PLAYER_2, BUTTON_1, event->type == SDL_KEYDOWN);
else if (event->key.keysym.sym == SDLK_x)
setSwitch(PLAYER_2, BUTTON_1, event->type == SDL_KEYDOWN);
setSwitch(PLAYER_2, BUTTON_2, event->type == SDL_KEYDOWN);
else if (event->key.keysym.sym == SDLK_c)
setSwitch(PLAYER_2, BUTTON_1, event->type == SDL_KEYDOWN);
setSwitch(PLAYER_2, BUTTON_3, event->type == SDL_KEYDOWN);
else if (event->key.keysym.sym == SDLK_v)
setSwitch(PLAYER_2, BUTTON_4, event->type == SDL_KEYDOWN);
else if (event->key.keysym.sym == SDLK_u)
setSwitch(PLAYER_2, BUTTON_UP, event->type == SDL_KEYDOWN);
@@ -533,16 +655,15 @@ void sdlEventShooting(SDL_Event *event)
{
int mX = event->motion.x;
int mY = event->motion.y;
if (mX < phX)
mX = phX;
if (mX > (phW + phX))
mX = (phW + phX) - 1;
if (mY > phH + phY)
mY = (phH + phY) - 1;
if (mY < phY)
mY = phY;
setAnalogue(ANALOGUE_1, ((double)(mX - phX) / (double)phW) * pow(2, jvsAnalogueInBits));
setAnalogue(ANALOGUE_2, ((double)(mY - phY) / (double)phH) * pow(2, jvsAnalogueInBits));
if (phIsDragging)
phTouchClick(mX, mY, event->type);
int motX = mX, motY = mY;
phTouchScreenCursor(mX, mY, &motX, &motY);
setAnalogue(ANALOGUE_1, ((double)(motX - phX) / (double)phW) * pow(2, jvsAnalogueInBits));
setAnalogue(ANALOGUE_2, ((double)(motY - phY) / (double)phH) * pow(2, jvsAnalogueInBits));
}
else
{
@@ -585,13 +706,32 @@ void sdlEventShooting(SDL_Event *event)
case SDL_MOUSEBUTTONUP:
{
if (event->button.button == SDL_BUTTON_LEFT) // Trigger
setSwitch(PLAYER_1, BUTTON_1, event->type == SDL_MOUSEBUTTONDOWN);
{
if (getConfig()->crc32 == PRIMEVAL_HUNT && getConfig()->emulateTouchscreen)
{
int mX = event->motion.x;
int mY = event->motion.y;
phTouchClick(mX, mY, event->type);
phIsDragging = (event->type == SDL_MOUSEBUTTONDOWN ? 1 : 0);
}
else
{
setSwitch(PLAYER_1, BUTTON_1, event->type == SDL_MOUSEBUTTONDOWN);
}
}
else if (event->button.button == SDL_BUTTON_RIGHT) // Reload
{
if (getConfig()->crc32 == RAMBO || getConfig()->crc32 == TOO_SPICY)
{
setAnalogue(ANALOGUE_1, -1);
setAnalogue(ANALOGUE_2, -1);
}
setSwitch(PLAYER_1, BUTTON_2, event->type == SDL_MOUSEBUTTONDOWN);
}
else if (event->button.button == SDL_BUTTON_MIDDLE) // Extra Gun Button
{
setSwitch(PLAYER_1, BUTTON_3, event->type == SDL_MOUSEBUTTONDOWN);
}
}
break;
default:
@@ -654,6 +794,64 @@ void sdlEventABC(SDL_Event *event)
}
}
void sdlEventHarley(SDL_Event *event)
{
switch (event->type)
{
case SDL_KEYDOWN:
case SDL_KEYUP:
{
if (event->key.keysym.sym == SDLK_t)
setSwitch(SYSTEM, BUTTON_TEST, event->type == SDL_KEYDOWN);
else if (event->key.keysym.sym == SDLK_s)
setSwitch(PLAYER_1, BUTTON_SERVICE, event->type == SDL_KEYDOWN);
else if (event->key.keysym.sym == SDLK_5)
incrementCoin(PLAYER_1, event->type == SDL_KEYDOWN);
else if (event->key.keysym.sym == SDLK_1)
setSwitch(PLAYER_1, BUTTON_START, event->type == SDL_KEYDOWN);
else if (event->key.keysym.sym == SDLK_UP)
setAnalogue(ANALOGUE_1, event->type == SDL_KEYDOWN ? pow(2, jvsAnalogueInBits) - 1 : 0);
else if (event->key.keysym.sym == SDLK_DOWN)
setAnalogue(ANALOGUE_4, event->type == SDL_KEYDOWN ? pow(2, jvsAnalogueInBits) - 1 : 0);
else if (event->key.keysym.sym == SDLK_LEFT)
setAnalogue(ANALOGUE_2, event->type == SDL_KEYDOWN ? pow(2, jvsAnalogueInBits) * 0.2 : pow(2, jvsAnalogueInBits) * 0.5);
else if (event->key.keysym.sym == SDLK_RIGHT)
setAnalogue(ANALOGUE_2, event->type == SDL_KEYDOWN ? pow(2, jvsAnalogueInBits) * 0.8 : pow(2, jvsAnalogueInBits) * 0.5);
else if (event->key.keysym.sym == SDLK_q)
setSwitch(PLAYER_1, BUTTON_1, event->type == SDL_KEYDOWN);
else if (event->key.keysym.sym == SDLK_w)
setSwitch(PLAYER_1, BUTTON_2, event->type == SDL_KEYDOWN);
else if (event->key.keysym.sym == SDLK_e)
setSwitch(PLAYER_1, BUTTON_3, event->type == SDL_KEYDOWN);
else if (event->key.keysym.sym == SDLK_r)
setSwitch(PLAYER_1, BUTTON_4, event->type == SDL_KEYDOWN);
else if (event->key.keysym.sym == SDLK_z)
setSwitch(PLAYER_1, BUTTON_DOWN, event->type == SDL_KEYDOWN); // Hummer - SegaTV view change
else if (event->key.keysym.sym == SDLK_x)
setSwitch(PLAYER_1, BUTTON_UP, event->type == SDL_KEYDOWN);
else if (event->key.keysym.sym == SDLK_c)
setSwitch(PLAYER_1, BUTTON_LEFT, event->type == SDL_KEYDOWN);
else if (event->key.keysym.sym == SDLK_v)
setSwitch(PLAYER_1, BUTTON_RIGHT, event->type == SDL_KEYDOWN);
else if (event->key.keysym.sym == SDLK_a)
setSwitch(PLAYER_2, BUTTON_1, event->type == SDL_KEYDOWN); // SegaTV boost
else if (event->key.keysym.sym == SDLK_LCTRL)
setSwitch(PLAYER_2, BUTTON_DOWN, event->type == SDL_KEYDOWN); // Hummer boost
else if (event->key.keysym.sym == SDLK_SPACE)
setSwitch(PLAYER_2, BUTTON_UP, event->type == SDL_KEYDOWN);
}
break;
default:
break;
}
}
void sdlEventMahjong(SDL_Event *event)
{
switch (event->type)
@@ -766,6 +964,9 @@ void handleSdlEvents(SDL_Event *event)
case ABC:
sdlEventABC(event);
break;
case HARLEY:
sdlEventHarley(event);
break;
case MAHJONG:
sdlEventMahjong(event);
break;
+215 -9
View File
@@ -11,7 +11,9 @@
#define LD_LIBRARY_PATH "LD_LIBRARY_PATH"
#define LD_PRELOAD "LD_PRELOAD"
#define PRELOAD_FILE_NAME "lindbergh.so"
#define PRELOAD_FILE_FLATPAK "/app/lib32/lindbergh.so"
#define TEAM "bobbydilley, retrofan, dkeruza-neo, doozer, francesco, rolel, caviar-x"
#define LINDBERGH_CONFIG_PATH "LINDBERGH_CONFIG_PATH"
uint32_t elf_crc = 0;
@@ -39,6 +41,153 @@ char *games[] = {"main.exe",
"a.elf",
"END"};
/**
* An array containin clean games elf's CRC32
*/
uint32_t cleanElfCRC32[] = {
0x51C4D2F6, // DVP-0003A | hod4M.elf
0x1348BCA8, // DVP-0003A | hod4testM.elf
0x0AAE384E, // DVP-0003B | hod4M.elf
0x352AA797, // DVP-0003B | hod4testM.elf
0x42EED61A, // DVP-0003C | hod4M.elf
0x6DA6E511, // DVP-0003C | hod4testM.elf
0x0E4BF4B1, // DVP-0005 | vt3_Lindbergh
0x9E48AB5B, // DVP-0005 | vt3_testmode
0xE4C64D01, // DVP-0005A | vt3_Lindbergh
0x9C0E77E5, // DVP-0005A | vt3_testmode
0xA4BDB9E2, // DVP-0005B | vt3_Lindbergh
0x74E25472, // DVP-0005B | vt3_testmode
0x987AE3FF, // DVP-0005C | vt3_Lindbergh
0x1E4271A4, // DVP-0005C | vt3_testmode
0xD409B70C, // DVP-0008 | vf5
0x08EBC0DB, // DVP-0008A | vf5
0xA47FBA2D, // DVP-0008B | vf5
0x8CA46167, // DVP-0008C | vf5
0x75946796, // DVP-0008E | vf5
0x2C8F5D57, // DVP-0009 | abc
0x13D90755, // DVP-0009A | abc
0x633AD6FB, // DVP-0009B | abc
0xD39825A8, // DVP-0010 | hod4M.elf
0x0745CF0A, // DVP-0010 | hod4testM.elf
0x13E59583, // DVP-0010B | hod4M.elf
0x302FEB00, // DVP-0010B | hod4testM.elf
0x04E08C99, // DVP-0011 | lgj_final
0x0C3D3CC3, // DVP-0011A | lgj_final
0xD9660B2E, // DVP-0015 | JenTest
0x821C3404, // DVP-0015 | Jennifer
0x13AF8581, // DVP-0015A | JenTest
0xB2CE9B23, // DVP-0015A | Jennifer
0xCC32DEAE, // DVP-0018 | abc
0x17114BC1, // DVP-0018A | abc
0x22905D60, // DVP-0019A | id4.elf
0x43582D48, // DVP-0019B | id4.elf
0x2D2A18C1, // DVP-0019C | id4.elf
0x9BFD0D98, // DVP-0019D | id4.elf
0x9CF9BBCC, // DVP-0019G | id4.elf
0xFA0F6AB0, // DVP-0027A | apacheM.elf
0x5A7F315E, // DVP-0027A | apachetestM.elf
0x9D414D18, // DVP-0029A | vsg
0xC345E213, // DVP-0030B | id4.elf
0x98E6A516, // DVP-0030C | id4.elf
0xF67365C9, // DVP-0030D | id4.elf
0x8BDD31BA, // DVP-0031 | abc
0x3DF37873, // DVP-0031A | abc
0xDD8BB792, // DVP-0036A | lgjsp_app
0xB0A96E34, // DVP-0043 | vf5
0xF99E5635, // DVP-0044 | drive.elf
0x4143F6B4, // DVP-0048A | main.exe
0x653BC83B, // DVP-0057 | a.elf
0x04D88552, // DVP-0057B | a.elf
0x089D6051, // DVP-0060 | dsr
0x317F3B90, // DVP-0063 | hodexRI.elf
0x3A5EEC69, // DVP-0063 | hodextestR.elf
0x81E02850, // DVP-0069 | ramboM.elf
0xE4F202BB, // DVP-0070A | id5.elf
0x2E6732A3, // DVP-0070F | id5.elf
0xF99A3CDB, // DVP-0075 | id5.elf
0x05647A8E, // DVP-0079 | hummer_Master.elf
0x4442EA15, // DVP-0083 | hummer_Master.elf
0x8DF6BBF9, // DVP-0084 | id5.elf
0x2AF8004E, // DVP-0084A | id5.elf
0xB95528F4, // DVP-5004 | vf5
0x012E4898, // DVP-5004D | vf5
0x74465F9F, // DVP-5004G | vf5
0x75B48E22, // DVP-5007 | chopperM.elf
0xFCB9D941, // DVP-5019A | vf5
0xAB70901C, // DVP-5020 | vf5
0x6BAA510D, // DVP-5020 | vf5 | Ver 6.000
};
int cleanElfCRC32Count = sizeof(cleanElfCRC32) / sizeof(uint32_t);
uint32_t calcCrc32(uint32_t crc, uint8_t data)
{
crc ^= data; // No shift needed; working in LSB-first order
for (int i = 0; i < 8; i++)
{
if (crc & 1)
{
crc = (crc >> 1) ^ 0xEDB88320;
}
else
{
crc = (crc >> 1);
}
}
return crc;
}
int lookupCrcTable(uint32_t crc)
{
for (int x = 0; x < cleanElfCRC32Count; x++)
{
if (cleanElfCRC32[x] == crc)
return 1;
}
return 0;
}
void isCleanElf(char *command)
{
const char *space_pos = strchr(command, ' ');
size_t length = space_pos ? (size_t)(space_pos - command) : strlen(command);
char elfName[256];
strncpy(elfName, command, length);
elfName[length] = '\0';
FILE *file = fopen(elfName, "rb");
if (!file)
{
log_error("Could not calculate the Elf CRC32.");
return;
}
uint32_t crc = 0xFFFFFFFF;
uint8_t buffer[4096];
size_t bytesRead;
while ((bytesRead = fread(buffer, 1, sizeof(buffer), file)) > 0)
{
for (size_t i = 0; i < bytesRead; i++)
{
crc = calcCrc32(crc, buffer[i]);
}
}
fclose(file);
crc = crc ^ 0xFFFFFFFF;
if (!lookupCrcTable(crc))
{
printf("\033[1;31m");
printf("Warning: The ELF you are running is not Clean and might cause unwanted behavior.\n");
printf(" Make sure you ELF and game dump are clean before reporting issues.\n");
printf(" If you are sure the ELF is clean, please report it to us.\n");
printf("\033[0m");
}
}
/**
* Tests if the game uses a seperate elf for test mode
* and updates the command line to this elf.
@@ -68,7 +217,7 @@ void testModePath(char *name)
if (strcmp(name, "./apacheM.elf") == 0)
{
strcpy(name, "./apacheTestM.elf");
strcpy(name, "./apachetestM.elf");
return;
}
@@ -86,7 +235,7 @@ void testModePath(char *name)
* Makes sure the environment variables are set correctly
* to run the game.
*/
void setEnvironmentVariables()
void setEnvironmentVariables(int isFlatpak, int zink, int nvidia)
{
// Ensure the library path is set correctly
char libraryPath[128] = {0};
@@ -103,7 +252,19 @@ void setEnvironmentVariables()
setenv(LD_LIBRARY_PATH, libraryPath, 1);
// Ensure the preload path is set correctly
setenv(LD_PRELOAD, PRELOAD_FILE_NAME, 1);
if (!isFlatpak)
setenv(LD_PRELOAD, PRELOAD_FILE_NAME, 1);
else
setenv(LD_PRELOAD, PRELOAD_FILE_FLATPAK, 1);
if (zink)
setenv("MESA_LOADER_DRIVER_OVERRIDE", "zink", 1);
if (nvidia)
{
setenv("__GLX_VENDOR_LIBRARY_NAME", "nvidia", 1);
setenv("__NV_PRIME_RENDER_OFFLOAD", "1", 1);
}
}
/**
@@ -115,10 +276,13 @@ void printUsage(char *argv[])
printf("Options:\n");
printf(" --test | -t Runs the test mode\n");
printf(" --segaboot | -s Runs segaboot\n");
printf(" --zink | -z Runs with Zink\n");
printf(" --nvidia | -n Runs with nVidia GPU when is as a secondary GPU in a laptop\n");
printf(" --gdb Runs with GDB\n");
printf(" --list-controllers Lists available controllers and inputs\n");
printf(" --version Displays the version of the loader and team's names\n");
printf(" --help Displays this usage text\n");
printf(" --config | -c Specifies configuration path\n");
}
/**
@@ -169,9 +333,6 @@ void printVersion() {
*/
int main(int argc, char *argv[])
{
// Ensure environment variables are set correctly
setEnvironmentVariables();
// Check for --version before directory operations
if (argc > 1 && strcmp(argv[1], "--version") == 0) {
printVersion();
@@ -191,6 +352,7 @@ int main(int argc, char *argv[])
char *game = NULL;
int lindberghSharedObjectFound = 0;
int isFlatpak = 0;
while ((ent = readdir(dir)) != NULL)
{
@@ -238,18 +400,30 @@ int main(int argc, char *argv[])
if (!lindberghSharedObjectFound)
{
log_error("The preload object lindbergh.so was not found in this directory.");
return EXIT_FAILURE;
FILE *file = fopen(PRELOAD_FILE_FLATPAK, "r");
if (file)
{
fclose(file);
isFlatpak = 1;
}
else
{
log_error("The preload object lindbergh.so was not found in this directory.");
return EXIT_FAILURE;
}
}
// Build up the command to start the game
int testMode = 0;
int gdb = 0;
int zink = 0;
int nvidia = 0;
int forceGame = 0;
int segaboot = 0;
char extConfigPath[PATH_MAX] = {0};
char forceGamePath[128] = {0};
for (int i = 1; i < argc; i++)
{
if (strcmp(argv[i], "-t") == 0 || strcmp(argv[i], "--test") == 0)
@@ -270,11 +444,36 @@ int main(int argc, char *argv[])
continue;
}
if (strcmp(argv[i], "-z") == 0 || strcmp(argv[i], "--ziink") == 0)
{
zink = 1;
continue;
}
if (strcmp(argv[i], "-n") == 0 || strcmp(argv[i], "--nvidia") == 0)
{
nvidia = 1;
continue;
}
if (strcmp(argv[i], "-c") == 0 || strcmp(argv[i], "--config") == 0)
{
if (i + 1 >= argc)
{
break;
}
strncpy(extConfigPath, argv[i + 1], PATH_MAX);
i += 1;
continue;
}
// Treat the argument as the game name
strcpy(forceGamePath, argv[i]);
forceGame = 1;
}
// Ensure environment variables are set correctly
setEnvironmentVariables(isFlatpak, zink, nvidia);
char command[128] = {0};
strcpy(command, "./");
if (forceGame)
@@ -298,6 +497,8 @@ int main(int argc, char *argv[])
if (testMode)
testModePath(command);
isCleanElf(command);
if (gdb)
{
char temp[128];
@@ -306,6 +507,11 @@ int main(int argc, char *argv[])
strcpy(command, temp);
}
if (extConfigPath[0] != '\0')
{
setenv(LINDBERGH_CONFIG_PATH, extConfigPath, 1);
}
log_info("Starting $ %s", command);
return system(command);
-1
View File
@@ -4,7 +4,6 @@
#include <stdarg.h>
#include <stdio.h>
#include <time.h>
// Structure to hold the formatted message and its size
+5 -2
View File
@@ -160,6 +160,10 @@ void *readJVSFrameThread(void * arg)
waitForEnd = 0;
do {
while (jvsFrameBuffer.ready == 1)
{
usleep(1);
}
// printf("SERIAL thread debug: trying to read byte.\n");
// Try to read a byte from serial, this call will be blocking if VMIN > 0 and VTIME = 0
bytesRead = read(fd, &localBuffer[byteCount], 1);
@@ -237,14 +241,13 @@ int startJVSFrameThread(int * fd) {
* @return
*/
JVSFrame readJVSFrameFromThread() {
JVSFrame frame;
// Lock while reading/writing to shared frame
pthread_mutex_lock(&jvsBuffer_lock);
// Check if we have a valid frame
if (jvsFrameBuffer.ready == 1) {
frame = jvsFrameBuffer;
memcpy(&frame, &jvsFrameBuffer, sizeof(JVSFrame));
// It has been red, we disable this frame
jvsFrameBuffer.ready = 0;
} else {
+2464 -2264
View File
File diff suppressed because it is too large Load Diff
+1732 -1179
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -11,6 +11,7 @@ size_t harleyFreadReplace(void *buf, size_t size, size_t count, FILE *stream);
void glTexCoord2fvABC1(const float *v);
void glVertex3fABC1(float x, float y, float z);
void glVertex3fABC2(float x, float y, float z);
int isTestMode();
typedef struct
{
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+90 -33
View File
@@ -1,6 +1,5 @@
#ifndef __i386__
#define __i386__
#include <SDL2/SDL_video.h>
#endif
#undef __x86_64__
#define GL_GLEXT_PROTOTYPES
@@ -8,18 +7,30 @@
#include <stdbool.h>
#include <dlfcn.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_syswm.h>
#include <X11/Xlib.h>
#include "config.h"
#include "input.h"
#include "sdlcalls.h"
#include "fps_limiter.h"
#include "customcursor.h"
bool SDLGame = false;
extern uint32_t gId;
bool SDLWindowCreated = false;
extern bool GLUTGame;
SDL_Window *SDLwindow;
SDL_GLContext SDLcontext;
Display *x11Display;
Window x11Window;
char SDLgameTitle[256] = {0};
extern fps_limit fpsLimit;
extern void *customCursor;
extern void *phTouchCursor;
int glutInitialized = 0;
void GLAPIENTRY openglDebugCallback2(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length,
const GLchar *message, const void *userParam)
{
@@ -40,31 +51,36 @@ void GLAPIENTRY openglDebugCallback2(GLenum source, GLenum type, GLuint id, GLen
}
}
void glutInitSDL(int *argcp, char **argv)
void initSDL(int *argcp, char **argv)
{
int gId = getConfig()->crc32;
void FGAPIENTRY (*_glutInit)(int *argcp, char **argv) = dlsym(RTLD_NEXT, "glutInit");
if (getConfig()->noSDL)
switch (gId)
{
_glutInit(argcp, argv);
return;
}
// || gId == R_TUNED || gId == VIRTUA_FIGHTER_5_R || gId == VIRTUA_FIGHTER_5_R_REVD
if (gId == OUTRUN_2_SP_SDX_TEST || gId == OUTRUN_2_SP_SDX_REVA_TEST || gId == OUTRUN_2_SP_SDX_REVA_TEST2)
{
_glutInit(argcp, argv);
case OUTRUN_2_SP_SDX_TEST:
case OUTRUN_2_SP_SDX_REVA_TEST:
case OUTRUN_2_SP_SDX_REVA_TEST2:
if (!glutInitialized)
{
glutInitialized = 1;
_glutInit(argcp, argv);
return;
}
}
if ((gId == AFTER_BURNER_CLIMAX) || (gId == AFTER_BURNER_CLIMAX_REVA) || (gId == AFTER_BURNER_CLIMAX_REVB) ||
(gId == AFTER_BURNER_CLIMAX_SDX) || (gId == AFTER_BURNER_CLIMAX_SDX_REVA) || (gId == AFTER_BURNER_CLIMAX_SE) ||
(gId == AFTER_BURNER_CLIMAX_SE_REVA))
switch (gId)
{
case AFTER_BURNER_CLIMAX:
case AFTER_BURNER_CLIMAX_REVA:
case AFTER_BURNER_CLIMAX_REVB:
case AFTER_BURNER_CLIMAX_SDX:
case AFTER_BURNER_CLIMAX_SDX_REVA:
case AFTER_BURNER_CLIMAX_SE:
case AFTER_BURNER_CLIMAX_SE_REVA:
setenv("SDL_VIDEODRIVER", "x11", 1);
}
SDLGame = true;
SDLWindowCreated = true;
if (SDL_Init(SDL_INIT_VIDEO) < 0)
{
@@ -75,14 +91,31 @@ void glutInitSDL(int *argcp, char **argv)
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); // Double buffering
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 1); // 24-bit depth buffer
SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8); // Set the alpha size to 8 bits
if (gId == AFTER_BURNER_CLIMAX || gId == AFTER_BURNER_CLIMAX_REVA || gId == AFTER_BURNER_CLIMAX_REVB ||
gId == AFTER_BURNER_CLIMAX_SDX || gId == AFTER_BURNER_CLIMAX_SDX_REVA || gId == AFTER_BURNER_CLIMAX_SE ||
gId == AFTER_BURNER_CLIMAX_SE_REVA || gId == R_TUNED || gId == VIRTUA_FIGHTER_5 || gId == VIRTUA_FIGHTER_5_REVA ||
gId == VIRTUA_FIGHTER_5_REVB || gId == VIRTUA_FIGHTER_5_REVE || gId == VIRTUA_FIGHTER_5_EXPORT || gId == VIRTUA_FIGHTER_5_R ||
gId == VIRTUA_FIGHTER_5_R_REVD || gId == VIRTUA_FIGHTER_5_R_REVG || gId == VIRTUA_FIGHTER_5_FINAL_SHOWDOWN_REVA ||
gId == VIRTUA_FIGHTER_5_FINAL_SHOWDOWN_REVB || gId == VIRTUA_FIGHTER_5_FINAL_SHOWDOWN_REVB_6000 || gId == GHOST_SQUAD_EVOLUTION ||
gId == SEGA_RACE_TV || gId == MJ4_REVG || gId == MJ4_EVO)
switch (gId)
{
case AFTER_BURNER_CLIMAX:
case AFTER_BURNER_CLIMAX_REVA:
case AFTER_BURNER_CLIMAX_REVB:
case AFTER_BURNER_CLIMAX_SDX:
case AFTER_BURNER_CLIMAX_SDX_REVA:
case AFTER_BURNER_CLIMAX_SE:
case AFTER_BURNER_CLIMAX_SE_REVA:
case R_TUNED:
case VIRTUA_FIGHTER_5:
case VIRTUA_FIGHTER_5_REVA:
case VIRTUA_FIGHTER_5_REVB:
case VIRTUA_FIGHTER_5_REVE:
case VIRTUA_FIGHTER_5_EXPORT:
case VIRTUA_FIGHTER_5_R:
case VIRTUA_FIGHTER_5_R_REVD:
case VIRTUA_FIGHTER_5_R_REVG:
case VIRTUA_FIGHTER_5_FINAL_SHOWDOWN_REVA:
case VIRTUA_FIGHTER_5_FINAL_SHOWDOWN_REVB:
case VIRTUA_FIGHTER_5_FINAL_SHOWDOWN_REVB_6000:
case GHOST_SQUAD_EVOLUTION:
case SEGA_RACE_TV:
case MJ4_REVG:
case MJ4_EVO:
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 1);
}
@@ -98,19 +131,43 @@ void glutInitSDL(int *argcp, char **argv)
exit(1);
}
SDLcontext = SDL_GL_CreateContext(SDLwindow);
if (!SDLcontext)
SDL_SysWMinfo info;
SDL_VERSION(&info.version);
if (SDL_GetWindowWMInfo(SDLwindow, &info))
{
if (info.subsystem == SDL_SYSWM_X11)
{
fprintf(stderr, "OpenGL context could not be created! SDL_Error: %s\n", SDL_GetError());
exit(1);
x11Display = info.info.x11.display;
x11Window = info.info.x11.window;
}
printf(" SDL RESOLUTION: %dx%d\n\n", getConfig()->width, getConfig()->height);
if (getConfig()->fullscreen)
else
{
SDL_SetWindowFullscreen(SDLwindow, SDL_WINDOW_FULLSCREEN);
fprintf(stderr, "This program is not running on X11.\n");
}
}
else
{
fprintf(stderr, "SDL_GetWindowWMInfo Error: %s\n", SDL_GetError());
}
SDLcontext = SDL_GL_CreateContext(SDLwindow);
if (!SDLcontext)
{
fprintf(stderr, "OpenGL context could not be created! SDL_Error: %s\n", SDL_GetError());
exit(1);
}
printf(" SDL RESOLUTION: %dx%d\n\n", getConfig()->width, getConfig()->height);
if (getConfig()->fullscreen)
{
SDL_SetWindowFullscreen(SDLwindow, SDL_WINDOW_FULLSCREEN);
}
loadCursors();
setCursor(customCursor);
if (getConfig()->hideCursor || gId == PRIMEVAL_HUNT)
SDL_ShowCursor(SDL_DISABLE);
}
void sdlQuit()
+1 -1
View File
@@ -1,2 +1,2 @@
void glutInitSDL(int *argcp, char **argv);
void initSDL(int *argcp, char **argv);
void pollEvents();
+5 -3
View File
@@ -1,7 +1,7 @@
#include <stdio.h>
#include "securityboard.h"
#include "config.h"
#include "securityboard.h"
#include "log.h"
#define SECURITY_BOARD_FRONT_PANEL 0x38
@@ -52,8 +52,10 @@ int securityBoardSetDipResolution(int width, int height)
setResolutionDips(1, 1, 0);
else if (width == 1360 && height == 768)
setResolutionDips(1, 1, 1);
else
log_warn("Resolution not compatible, using 640 x 480\n");
else {
if(getConfig()->showDebugMessages)
log_warn("Resolution not original, setting dips to 640 x 480.\n");
}
return 0;
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+85
View File
@@ -0,0 +1,85 @@
#include <SDL2/SDL_events.h>
#include <X11/X.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <sys/types.h>
char phSendBuf[10];
bool phBufferFilled = false;
int phCommand = 1;
int phCommandByte = 0;
uint16_t coordX;
uint16_t coordY;
#define TOUCH_START 0x81
#define TOUCH_TOUCHING 0x82
#define TOUCH_END 0x84
void phCoordinates(int x, int y, int w, int h, int button)
{
coordX = (float)x / ((float)w * 0.0002441406);
coordY = (float)y / ((float)h * 0.0002441406);
memset(phSendBuf, 0, sizeof(phSendBuf));
if (button == SDL_MOUSEBUTTONDOWN || button == ButtonPress)
{
phSendBuf[2] = TOUCH_START;
phCommand = 1;
}
else if (button == SDL_MOUSEBUTTONUP || button == ButtonRelease)
{
phSendBuf[2] = TOUCH_END;
phCommand = 3;
}
else if (button == SDL_MOUSEMOTION || button == MotionNotify)
{
phSendBuf[2] = TOUCH_TOUCHING;
phCommand = 2;
}
phSendBuf[0] = 0x55;
phSendBuf[1] = 0x54;
phSendBuf[3] = (char)(coordX & 0xFF);
phSendBuf[4] = (char)((coordX >> 8) & 0xff);
phSendBuf[5] = (char)(coordY & 0xFF);
phSendBuf[6] = (char)((coordY >> 8) & 0xff);
phBufferFilled = true;
}
uint8_t phCalcChecksum()
{
int8_t checksum = -0x56;
for (int x = 0; x < 9;x++)
{
checksum += phSendBuf[x];
}
return (uint8_t)(checksum & 0xff);
}
ssize_t phRead(int fd, void *buf, size_t count)
{
if(!phBufferFilled)
return 0;
if(phCommandByte == 9)
{
switch (phCommand)
{
case 1:
phCommand = 2;
break;
case 2:
phSendBuf[2] = TOUCH_TOUCHING;
break;
case 3:
phBufferFilled = false;
}
phSendBuf[9] = phCalcChecksum();
}
memcpy(buf, &phSendBuf[phCommandByte], sizeof(char));
phCommandByte++;
if (phCommandByte == 10)
phCommandByte = 0;
return 1;
}
+9
View File
@@ -0,0 +1,9 @@
#ifndef TOUCHSCREEN_H
#define TOUCHSCREEN_H
#include <sys/types.h>
void phCoordinates(int x, int y, int w, int h, int button);
ssize_t phRead(int fd, void *buf, size_t count);
#endif
+106 -89
View File
@@ -4,7 +4,6 @@
#endif
#undef __x86_64__
#include <GL/glx.h>
#include <GL/freeglut.h>
#include <X11/Xatom.h>
#include <X11/extensions/xf86vmode.h>
#include <dlfcn.h>
@@ -19,11 +18,22 @@
#include "config.h"
#include "securityboard.h"
#include "fps_limiter.h"
#include "sdlcalls.h"
#include "customcursor.h"
extern bool SDLGame;
extern bool SDLWindowCreated;
extern bool gettingGPUVendor;
extern bool GLUTGame;
Window win;
bool creatingWindow = false;
Window window;
extern Display *x11Display;
extern Window x11Window;
extern void *customCursor;
extern void *phTouchCursor;
/**
* Stop the house of the dead games turning keyboard repeating off.
@@ -33,42 +43,61 @@ int XAutoRepeatOff(Display *display)
return 0;
}
Window XCreateWindow(Display *display, Window parent, int x, int y, unsigned int width, unsigned int height,
unsigned int border_width, int depth, unsigned int class, Visual *visual, unsigned long valueMask,
XSetWindowAttributes *attributes)
Display *XOpenDisplay(const char *display_name)
{
Display *(*_XOpenDisplay)(const char *display_name) = dlsym(RTLD_NEXT, "XOpenDisplay");
if (SDLWindowCreated || gettingGPUVendor || getConfig()->noSDL)
{
x11Display = _XOpenDisplay(display_name);
}
else
{
creatingWindow = true;
initSDL(0, 0);
creatingWindow = false;
}
return x11Display;
}
Window XCreateWindow(Display *display, Window parent, int x, int y, unsigned int width, unsigned int height, unsigned int border_width,
int depth, unsigned int class, Visual *visual, unsigned long valueMask, XSetWindowAttributes *attributes)
{
Window (*_XCreateWindow)(Display *display, Window parent, int x, int y, unsigned int width, unsigned int height,
unsigned int border_width, int depth, unsigned int class, Visual *visual,
unsigned long valueMask, XSetWindowAttributes *attributes) =
dlsym(RTLD_NEXT, "XCreateWindow");
if (SDLGame || gettingGPUVendor)
if ((gettingGPUVendor || creatingWindow) || (GLUTGame && getConfig()->noSDL == 0))
{
Window window = _XCreateWindow(display, parent, x, y, width, height, border_width, depth, class, visual,
valueMask, attributes);
return window;
window = _XCreateWindow(display, parent, x, y, width, height, border_width, depth, class, visual, valueMask, attributes);
}
width = getConfig()->width;
height = getConfig()->height;
// Ensure that the windows will respond with keyboard and mouse events
attributes->event_mask = attributes->event_mask | KeyPressMask | KeyReleaseMask | PointerMotionMask;
// attributes->override_redirect = False;
Window window =
_XCreateWindow(display, parent, x, y, width, height, border_width, depth, class, visual, valueMask, attributes);
printf(" X11 RESOLUTION: %dx%d\n\n", width, height);
if (getConfig()->fullscreen)
else if (getConfig()->noSDL)
{
Atom wm_state = XInternAtom(display, "_NET_WM_STATE", true);
Atom wm_fullscreen = XInternAtom(display, "_NET_WM_STATE_FULLSCREEN", true);
XChangeProperty(display, window, wm_state, XA_ATOM, 32, PropModeReplace, (unsigned char *)&wm_fullscreen, 1);
width = getConfig()->width;
height = getConfig()->height;
attributes->event_mask = attributes->event_mask | KeyPressMask | KeyReleaseMask | PointerMotionMask;
window = _XCreateWindow(display, parent, x, y, width, height, border_width, depth, class, visual, valueMask, attributes);
printf(" X11 RESOLUTION: %dx%d\n\n", width, height);
if (getConfig()->fullscreen)
{
Atom wm_state = XInternAtom(display, "_NET_WM_STATE", true);
Atom wm_fullscreen = XInternAtom(display, "_NET_WM_STATE_FULLSCREEN", true);
XChangeProperty(display, window, wm_state, XA_ATOM, 32, PropModeReplace, (unsigned char *)&wm_fullscreen, 1);
}
x11Window = window;
loadCursors();
setCursor(customCursor);
if (getConfig()->hideCursor)
hideCursor();
}
else
{
window = x11Window;
}
win = window;
return window;
}
@@ -78,10 +107,15 @@ int XGrabPointer(Display *display, Window grab_window, Bool owner_events, unsign
int (*_XGrabPointer)(Display *display, Window grab_window, Bool owner_events, unsigned int event_mask,
int pointer_mode, int keyboard_mode, Window confine_to, Cursor cursor, Time time) =
dlsym(RTLD_NEXT, "XGrabPointer");
int returnValue = _XGrabPointer(display, grab_window, owner_events, event_mask, pointer_mode, keyboard_mode,
confine_to, cursor, time);
XUngrabPointer(display, time);
return returnValue;
if (getConfig()->noSDL)
{
int returnValue =
_XGrabPointer(display, grab_window, owner_events, event_mask, pointer_mode, keyboard_mode, confine_to, cursor, time);
XUngrabPointer(display, time);
return returnValue;
}
return _XGrabPointer(display, grab_window, owner_events, event_mask, pointer_mode, keyboard_mode, confine_to, cursor, time);
}
int XGrabKeyboard(Display *display, Window grab_window, Bool owner_events, int pointer_mode, int keyboard_mode,
@@ -89,22 +123,27 @@ int XGrabKeyboard(Display *display, Window grab_window, Bool owner_events, int p
{
int (*_XGrabKeyboard)(Display *display, Window grab_window, Bool owner_events, int pointer_mode, int keyboard_mode,
Time time) = dlsym(RTLD_NEXT, "XGrabKeyboard");
int returnValue = _XGrabKeyboard(display, grab_window, owner_events, pointer_mode, keyboard_mode, time);
XUngrabKeyboard(display, time);
return returnValue;
}
int XDefineCursor(Display *display, Window w, Cursor cursor)
{
return 0;
if (getConfig()->noSDL)
{
int returnValue = _XGrabKeyboard(display, grab_window, owner_events, pointer_mode, keyboard_mode, time);
XUngrabKeyboard(display, time);
return returnValue;
}
return _XGrabKeyboard(display, grab_window, owner_events, pointer_mode, keyboard_mode, time);
}
int XStoreName(Display *display, Window w, const char *window_name)
{
int (*_XStoreName)(Display *display, Window w, const char *window_name) = dlsym(RTLD_NEXT, "XStoreName");
char windowTitle[512];
sprintf(windowTitle, "%s - FPS: %.2f", getGameName(), calculateFps());
return _XStoreName(display, w, windowTitle);
if (getConfig()->noSDL)
{
char windowTitle[512];
sprintf(windowTitle, "%s - FPS: %.2f", getGameName(), calculateFps());
return _XStoreName(display, w, windowTitle);
}
return _XStoreName(display, w, window_name);
}
int XSetStandardProperties(Display *display, Window window, const char *window_name, const char *icon_name,
@@ -113,9 +152,30 @@ int XSetStandardProperties(Display *display, Window window, const char *window_n
int (*_XSetStandardProperties)(Display *display, Window window, const char *window_name, const char *icon_name,
Pixmap icon_pixmap, char **argv, int argc, XSizeHints *hints) =
dlsym(RTLD_NEXT, "XSetStandardProperties");
char gameTitle[256] = {0};
strcat(gameTitle, getGameName());
return _XSetStandardProperties(display, window, gameTitle, icon_name, icon_pixmap, argv, argc, hints);
if (getConfig()->noSDL)
{
char gameTitle[256] = {0};
strcat(gameTitle, getGameName());
return _XSetStandardProperties(display, window, gameTitle, icon_name, icon_pixmap, argv, argc, hints);
}
return _XSetStandardProperties(display, window, window_name, icon_name, icon_pixmap, argv, argc, hints);
}
int XPending(Display *display)
{
int (*_XPending)(Display *display) = dlsym(RTLD_NEXT, "XPending");
if (SDLWindowCreated)
return 0;
return _XPending(display);
}
int XFlush(Display *display)
{
int (*_XFlush)(Display *display) = dlsym(RTLD_NEXT, "XFlush");
if (SDLWindowCreated)
return 0;
return _XFlush(display);
}
Bool XF86VidModeSwitchToMode(Display *display, int screen, XF86VidModeModeInfo *modesinfo)
@@ -153,49 +213,6 @@ int XF86VidModeGetAllModeLines(Display *display, int screen, int *modecount_retu
return true;
}
int XPending(Display *display)
{
int (*_XPending)(Display *display) = dlsym(RTLD_NEXT, "XPending");
if (SDLGame)
return 0;
return _XPending(display);
}
Cursor XCreatePixmapCursor(Display *display, Pixmap source, Pixmap mask, XColor *fg, XColor *bg, unsigned int x,
unsigned int y)
{
int (*_XCreatePixmapCursor)(Display *display, Pixmap source, Pixmap mask, XColor *fg, XColor *bg, unsigned int x,
unsigned int y) = dlsym(RTLD_NEXT, "XCreatePixmapCursor");
if (SDLGame)
return 0;
return _XCreatePixmapCursor(display, source, mask, fg, bg, x, y);
}
int XFreePixmap(Display *display, Pixmap pixmap)
{
int (*_XFreePixmap)(Display *display, Pixmap pixmap) = dlsym(RTLD_NEXT, "XFreePixmap");
if (SDLGame)
return 0;
return _XFreePixmap(display, pixmap);
}
Pixmap XCreateBitmapFromData(Display *display, Drawable drawable, const char *data, unsigned int x, unsigned int y)
{
Pixmap (*_XCreateBitmapFromData)(Display *display, Drawable drawable, const char *data, unsigned int x,
unsigned int y) = dlsym(RTLD_NEXT, "XCreateBitmapFromData");
if (SDLGame)
return 0;
return _XCreateBitmapFromData(display, drawable, data, x, y);
}
int XFlush(Display *display)
{
int (*_XFlush)(Display *display) = dlsym(RTLD_NEXT, "XFlush");
if (SDLGame)
return 0;
return _XFlush(display);
}
typedef unsigned int uint;
void glGenFencesNV(int n, uint *fences)