mirror of
https://github.com/flyinghead/flycast.git
synced 2026-11-08 08:06:48 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3d5fd61285 | ||
|
|
069b501ca3 | ||
|
|
d035af7ff0 | ||
|
|
20302cd378 | ||
|
|
959685e260 | ||
|
|
e46d819c46 | ||
|
|
274f2fe10d | ||
|
|
2c96d49cf2 | ||
|
|
a9cabdc342 | ||
|
|
90a95b4688 | ||
|
|
0c46ea13c7 | ||
|
|
1e01dbb151 | ||
|
|
be270259ee | ||
|
|
03f9955f8b | ||
|
|
514eedbc63 | ||
|
|
1f61f80c92 | ||
|
|
830ffd0559 | ||
|
|
ed066df469 | ||
|
|
e6676c7d09 | ||
|
|
33115a39a3 | ||
|
|
6538360fe1 | ||
|
|
ed0e5b8c5a | ||
|
|
c75d94bd90 | ||
|
|
a8d6374d76 | ||
|
|
4b10402c5b | ||
|
|
20571c5aa1 | ||
|
|
3872a6b475 | ||
|
|
083a1c85a8 | ||
|
|
943e0285ac | ||
|
|
d7abfc688c | ||
|
|
8f01ef90cf | ||
|
|
3929fe64a3 | ||
|
|
4fe8e40569 | ||
|
|
b91b3d5da6 | ||
|
|
92f81fa054 | ||
|
|
4e21391f8c | ||
|
|
9ab4bb963f | ||
|
|
58f05f74cf | ||
|
|
a4b0a69c45 | ||
|
|
2a364910c0 | ||
|
|
45ba648622 | ||
|
|
dcd48f4264 | ||
|
|
8ee9f1b1d9 | ||
|
|
f2c39e4004 | ||
|
|
62ec3546d6 | ||
|
|
8bb0bd05f9 | ||
|
|
e538242962 | ||
|
|
d70d2ad405 | ||
|
|
4f638f6d77 | ||
|
|
80d78705b0 | ||
|
|
140cec7c59 | ||
|
|
746b3c5a54 | ||
|
|
a4788b5b24 | ||
|
|
8dcf0f58b5 | ||
|
|
a8080c5db3 | ||
|
|
a52977d1cf | ||
|
|
0bb6fed822 | ||
|
|
d86305a7c3 | ||
|
|
5aeef17d09 | ||
|
|
2d41d993e3 | ||
|
|
503cc7ea97 | ||
|
|
7f41847c5c | ||
|
|
fde683a82e | ||
|
|
4feff7d917 | ||
|
|
e61951a319 | ||
|
|
da81274eb9 | ||
|
|
8740141a93 | ||
|
|
9223a2b530 | ||
|
|
300c74e3fc | ||
|
|
3f82c7fb6f | ||
|
|
2cb7a1d96c | ||
|
|
00562455e0 | ||
|
|
bb88dcfe66 | ||
|
|
970e594009 | ||
|
|
cd5a784277 | ||
|
|
771f653174 | ||
|
|
109cb81ab7 | ||
|
|
bf87f7ba84 | ||
|
|
92b8eae2dc | ||
|
|
776f86c7f2 | ||
|
|
c10c3a1cfe | ||
|
|
94fccc5112 | ||
|
|
73fa0e3efc | ||
|
|
2b827e43d7 | ||
|
|
e706368225 | ||
|
|
2f5271ab83 | ||
|
|
4e448b23a8 | ||
|
|
38002d4907 | ||
|
|
fd81f9b1b4 | ||
|
|
77900f5745 | ||
|
|
8684aac4f2 | ||
|
|
b1e0bc90ba | ||
|
|
8e305bfd0f | ||
|
|
32716e1480 | ||
|
|
833eccb6c4 | ||
|
|
f64b3618f2 | ||
|
|
325cd9a066 | ||
|
|
544c711fd7 | ||
|
|
e02afb34d1 | ||
|
|
dc5acd24b2 | ||
|
|
7555263e38 | ||
|
|
71d016722e | ||
|
|
96560e4914 | ||
|
|
04be40767b | ||
|
|
5a6197cfc6 | ||
|
|
5fca12af49 | ||
|
|
853830a446 | ||
|
|
2f47f72957 | ||
|
|
de35cf9840 | ||
|
|
18d8107992 | ||
|
|
2478b72a3e | ||
|
|
4d60150345 | ||
|
|
6a3a8d5578 | ||
|
|
08828991e7 | ||
|
|
4c14a96888 | ||
|
|
0478ec9696 | ||
|
|
46044c068b | ||
|
|
c6fe6b83ac | ||
|
|
cc39d4dd7d | ||
|
|
b79c049bd4 | ||
|
|
4cbf19c97e | ||
|
|
27041cbf59 | ||
|
|
8e2c72ed1b | ||
|
|
7820c9bc44 | ||
|
|
92fff9acf5 | ||
|
|
91da49dc52 | ||
|
|
b5a45417d9 | ||
|
|
3db4993077 | ||
|
|
bc1a5fdd8d | ||
|
|
191f1c38df | ||
|
|
adb61259c1 | ||
|
|
ddc2e84e45 | ||
|
|
a050a61f2e | ||
|
|
99195c3f4c | ||
|
|
280c159078 | ||
|
|
6a8f1b941e | ||
|
|
8a6ce19e1e | ||
|
|
d071adea9a | ||
|
|
3d7455316f | ||
|
|
3f50baa318 | ||
|
|
8164c96379 | ||
|
|
4ab3f01867 | ||
|
|
dbb277f749 | ||
|
|
0579f2ede6 | ||
|
|
ef3af9aad3 | ||
|
|
d5694036fa | ||
|
|
f91847dad0 | ||
|
|
c4eaa973f0 | ||
|
|
42fa77c81f | ||
|
|
e4bfeb9e44 | ||
|
|
67f2162fb3 | ||
|
|
465499f6c3 | ||
|
|
ea75311a34 | ||
|
|
33fd8a9ec7 | ||
|
|
417ffc09f8 | ||
|
|
1057f50f86 | ||
|
|
5b933cde61 | ||
|
|
47442d1bc9 | ||
|
|
f25c83e006 | ||
|
|
bc34024e32 | ||
|
|
628bef9094 | ||
|
|
63598019e1 | ||
|
|
501244ed25 | ||
|
|
e12912450c | ||
|
|
8262c9ece7 | ||
|
|
cc208ce451 | ||
|
|
c6374a899c | ||
|
|
8f80bcb159 | ||
|
|
e56ecfec40 | ||
|
|
80cf422a5e | ||
|
|
d788c310ee | ||
|
|
7583db3bef | ||
|
|
ac5abd96bb | ||
|
|
aa944ac5e8 | ||
|
|
35e1fb9ae5 | ||
|
|
a15863ae35 | ||
|
|
a04fd06e38 | ||
|
|
f6cc2c7b91 | ||
|
|
99ee526ac5 | ||
|
|
d100067e02 | ||
|
|
f777c62a66 | ||
|
|
06ef0e5fdc | ||
|
|
5209623064 | ||
|
|
7c53413bc5 | ||
|
|
42f92b8dc1 | ||
|
|
986baccf83 | ||
|
|
32d31e7644 | ||
|
|
03161446b9 | ||
|
|
17bbb7f145 | ||
|
|
71c4ec34d5 | ||
|
|
da3ed74c4e | ||
|
|
46ae8f92cc | ||
|
|
9b3dec5f70 | ||
|
|
146bfb28d1 | ||
|
|
46fb331275 | ||
|
|
ff39b8b252 | ||
|
|
004250ed23 | ||
|
|
037339f3be | ||
|
|
e0437ab447 | ||
|
|
808a161d39 | ||
|
|
6d8e1794a0 | ||
|
|
89338c0b4b | ||
|
|
7f7cbd5666 | ||
|
|
846ed76808 | ||
|
|
ab45b5ec8a | ||
|
|
db93a4c4a7 | ||
|
|
59566eb363 | ||
|
|
7fb85e5b25 | ||
|
|
c061912574 | ||
|
|
3eeb7e7cae | ||
|
|
cf653640b3 | ||
|
|
5cfd897298 | ||
|
|
7ecb6a6d96 | ||
|
|
c08f177d3b | ||
|
|
1c6e722961 | ||
|
|
0d49817f00 | ||
|
|
85c21df5e7 | ||
|
|
f9d5b8eb74 | ||
|
|
bcc3337c58 | ||
|
|
163888f329 | ||
|
|
8b986dfab3 | ||
|
|
19bd6d0bca | ||
|
|
c2caef4ad5 | ||
|
|
1d9ac4918c | ||
|
|
bc3be1029c | ||
|
|
bc238de5ce | ||
|
|
1072235b1a | ||
|
|
3c2c7b379d | ||
|
|
4af194035c | ||
|
|
3171cfd381 | ||
|
|
8183bf7f95 | ||
|
|
82bec1e324 | ||
|
|
897cc01f93 | ||
|
|
5bcfa35737 | ||
|
|
c1bcf91dd6 | ||
|
|
621e4d196e | ||
|
|
45ebc2239f | ||
|
|
a6248905a0 | ||
|
|
699dcdaf5b | ||
|
|
23d1f6b507 | ||
|
|
f72f4c49fb | ||
|
|
2803ee8274 | ||
|
|
0d2e6f5e98 | ||
|
|
99bf7f77c4 | ||
|
|
7fe2ab720f | ||
|
|
18cecc8d38 | ||
|
|
5d068fc2d4 | ||
|
|
84d98763f1 | ||
|
|
86356c737c | ||
|
|
1fa233aae7 | ||
|
|
1dc01314a1 | ||
|
|
fb40bb22df | ||
|
|
1dc22ec76c | ||
|
|
41ac140076 | ||
|
|
4e019cc233 | ||
|
|
36007ceb68 | ||
|
|
25fdeac697 | ||
|
|
07d27edb76 | ||
|
|
39fabf39ae | ||
|
|
945a483e9b | ||
|
|
1725dbfa98 | ||
|
|
67790abf0e | ||
|
|
3ec08f6ae1 | ||
|
|
c419654a11 | ||
|
|
51ad6094e8 | ||
|
|
5b7d189058 | ||
|
|
7d57d55414 | ||
|
|
65956dbc8d | ||
|
|
d75072362a | ||
|
|
22947af854 | ||
|
|
50a67dbd3e | ||
|
|
7fd954e10d | ||
|
|
4c53fcecfa | ||
|
|
17348dae8a | ||
|
|
05d495b282 | ||
|
|
3b7a940e9b | ||
|
|
501c6f260a | ||
|
|
e1fa2b9831 | ||
|
|
043175ae4d | ||
|
|
8b266b1327 | ||
|
|
f7abe3bb34 | ||
|
|
480e85f615 | ||
|
|
0182d1ca09 | ||
|
|
99a0dce8cd | ||
|
|
badcace987 | ||
|
|
e8b73e22b7 | ||
|
|
45f68d59ff | ||
|
|
1762987aae | ||
|
|
ad2e142b01 | ||
|
|
88fa5d5c41 | ||
|
|
e45ec4324f | ||
|
|
d9a8e29a94 | ||
|
|
3ced57a263 | ||
|
|
458868a634 | ||
|
|
7ecc0543f4 | ||
|
|
6d6f3d38d4 | ||
|
|
a4e715fa71 | ||
|
|
8594d11693 | ||
|
|
a4c14ebef7 | ||
|
|
599874c9c1 | ||
|
|
5121b0df93 | ||
|
|
e3a2f1cfbe | ||
|
|
414fb9dba2 | ||
|
|
a402c69c55 | ||
|
|
c007165a0f | ||
|
|
a3d50fc197 | ||
|
|
baa0ac44ca | ||
|
|
6768901446 | ||
|
|
35e77976a6 | ||
|
|
dba805e8c4 | ||
|
|
e3aca85efd | ||
|
|
f35a18bb63 | ||
|
|
a6ad0208db | ||
|
|
e02ccbf32a | ||
|
|
b362a55c04 | ||
|
|
69d0801121 | ||
|
|
f85bca06d7 | ||
|
|
3589e94121 | ||
|
|
2baf2cfed6 | ||
|
|
4d5c93adfa | ||
|
|
93eff7fac6 | ||
|
|
ce68a9c708 | ||
|
|
280dad1c07 | ||
|
|
c3d954263b | ||
|
|
e058ba5d3b | ||
|
|
05d51cc35c | ||
|
|
088287227e | ||
|
|
ad1f9527c1 | ||
|
|
ca17717af7 | ||
|
|
2a849ccba5 | ||
|
|
4bf20846bc | ||
|
|
ad80184e7f | ||
|
|
e5ca63db20 | ||
|
|
2f03922b43 | ||
|
|
5db2856270 | ||
|
|
e3e3229612 | ||
|
|
8b2ed736a6 | ||
|
|
27da5f84c4 | ||
|
|
98d04702ae | ||
|
|
a0664a49d2 | ||
|
|
55fb0a6efb | ||
|
|
7fb83f4f77 | ||
|
|
970f8c6dcd | ||
|
|
c99de2370f | ||
|
|
8c9ff4a66f | ||
|
|
42eeddcbfb | ||
|
|
8b0f17fb25 | ||
|
|
a3900495d5 | ||
|
|
d7bc1f0f77 | ||
|
|
281a04837f | ||
|
|
3ea688be69 | ||
|
|
1bea7853ef | ||
|
|
104521517c | ||
|
|
bb217e5c49 | ||
|
|
12f302d356 | ||
|
|
77e7c25e9c | ||
|
|
b027a6b9a1 | ||
|
|
6bb4575c95 | ||
|
|
37eace9db4 | ||
|
|
0414406471 | ||
|
|
8c000f327e | ||
|
|
951e70328f | ||
|
|
2dd7717128 | ||
|
|
9d6c548730 | ||
|
|
8a46853dfd | ||
|
|
789fd21bb7 | ||
|
|
3fa97b5ce7 | ||
|
|
c8ebbc657a | ||
|
|
b59585437c | ||
|
|
6f4e1365b1 | ||
|
|
aabb492d01 | ||
|
|
cfa21934bb | ||
|
|
7561ce753a | ||
|
|
5fd00e3063 | ||
|
|
a46a012c3c | ||
|
|
3072105efe | ||
|
|
8f09ac2611 | ||
|
|
e12be7cf29 | ||
|
|
588d79641a | ||
|
|
daac6de533 | ||
|
|
c6d7307efe | ||
|
|
710f379bd3 | ||
|
|
c453d14352 | ||
|
|
de060d66ab | ||
|
|
c458a8f5e7 | ||
|
|
4a77f847b4 | ||
|
|
edc6474f27 | ||
|
|
117f47e3a2 | ||
|
|
4f11ff76a5 | ||
|
|
10e97b63be | ||
|
|
af76a09e03 | ||
|
|
9e5769912b | ||
|
|
ab50bc9936 | ||
|
|
a604a3904f | ||
|
|
e112f2d8af | ||
|
|
376d2e1433 | ||
|
|
ed0caa119a | ||
|
|
f768146d8e | ||
|
|
412083d9ea | ||
|
|
07cdb42ff7 | ||
|
|
1e37e8f333 | ||
|
|
4fa89c4a45 | ||
|
|
0d7a2128b6 | ||
|
|
ae33c8de18 | ||
|
|
b12e82c344 | ||
|
|
8dee648d01 | ||
|
|
8e6dc54b16 | ||
|
|
db9c48b085 | ||
|
|
c0171f5fd1 | ||
|
|
9a5a55d074 | ||
|
|
855836d9aa | ||
|
|
8a0a0bcdfc | ||
|
|
43c00568c6 | ||
|
|
113ef66e26 | ||
|
|
4d38e69f63 | ||
|
|
8c02345dfd | ||
|
|
a2efde1103 | ||
|
|
eb81583d9f | ||
|
|
44213bf830 | ||
|
|
f187f77e3d | ||
|
|
63a3f02368 | ||
|
|
994e6826b4 | ||
|
|
97991fd8fc | ||
|
|
1fdda98d8d | ||
|
|
a73ca94124 | ||
|
|
4be4ad07f3 | ||
|
|
57874a9bcb | ||
|
|
ec7968b2f4 | ||
|
|
81546fe727 | ||
|
|
7948bac6ba | ||
|
|
345dab9633 | ||
|
|
5c952021b7 | ||
|
|
80a5b44fe9 | ||
|
|
b66e6560ca | ||
|
|
673c2988d6 | ||
|
|
b300bb9f7a | ||
|
|
205f2690d6 | ||
|
|
8e6bbed74f | ||
|
|
ef506d49aa | ||
|
|
c205a888a9 | ||
|
|
a3b66aec1f | ||
|
|
68f4c50bd3 | ||
|
|
7dbd79750c |
No files matched your search
@@ -0,0 +1 @@
|
||||
custom: ['https://utip.io/flyinghead', 'https://www.paypal.com/paypalme/FlycastEmu']
|
||||
@@ -1,3 +1,12 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Please Note: This form is the minimum required information for submitting bugs.**
|
||||
**Removing this form may lead to your issue being closed until it is completed.**
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: enhancement
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
@@ -8,52 +8,69 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Set up build environment
|
||||
run: sudo apt-get update && sudo apt-get -y install ninja-build
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install ccache libcurl4-openssl-dev ninja-build
|
||||
|
||||
# Workaround for https://github.com/actions/virtual-environments/issues/3078
|
||||
- name: Downgrade CMake
|
||||
uses: jwlawson/[email protected]
|
||||
with:
|
||||
cmake-version: '3.19.x'
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
submodules: recursive
|
||||
submodules: true
|
||||
|
||||
- uses: actions/cache@v2
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.ccache
|
||||
key: android-ccache-${{ github.sha }}
|
||||
restore-keys: android-ccache-
|
||||
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.gradle/caches
|
||||
~/.gradle/wrapper
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-gradle-
|
||||
key: android-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
|
||||
restore-keys: android-gradle-
|
||||
|
||||
- name: Gradle
|
||||
working-directory: shell/android-studio
|
||||
run: ./gradlew assembleRelease --parallel
|
||||
|
||||
- uses: actions/upload-artifact@v2
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: flycast-release.apk
|
||||
path: shell/android-studio/flycast/build/outputs/apk/release/flycast-release.apk
|
||||
|
||||
- name: Set up git vars
|
||||
- name: Build dump_syms
|
||||
working-directory: core/deps/breakpad
|
||||
run: |
|
||||
echo GIT_BUILD=`git describe --all --always | sed 's/remotes\/origin/heads/'`-$GITHUB_SHA >> $GITHUB_ENV
|
||||
./configure --prefix=$PWD
|
||||
make -j2
|
||||
make install
|
||||
|
||||
- name: Clean up
|
||||
run: rm -f shell/android-studio/flycast/build/outputs/apk/release/*.json
|
||||
- name: Extract symbols
|
||||
run: |
|
||||
DUMP_SYMS=./core/deps/breakpad/bin/dump_syms
|
||||
SO_DIR=shell/android-studio/flycast/build/intermediates/cmake/release/obj
|
||||
for arch in arm64-v8a armeabi-v7a x86 x86_64 ; do
|
||||
$DUMP_SYMS $SO_DIR/$arch/libflycast.so > libflycast.so.sym
|
||||
BUILD_ID=`head -1 libflycast.so.sym | awk '{ print $4 }'`
|
||||
mkdir -p symbols/libflycast.so/$BUILD_ID
|
||||
mv libflycast.so.sym symbols/libflycast.so/$BUILD_ID
|
||||
done
|
||||
|
||||
- uses: jakejarvis/s3-sync-action@master
|
||||
- name: Configure AWS Credentials
|
||||
id: aws-credentials
|
||||
uses: aws-actions/configure-aws-credentials@v1
|
||||
with:
|
||||
args: --acl public-read --follow-symlinks
|
||||
env:
|
||||
AWS_S3_BUCKET: flycast-builds
|
||||
AWS_ACCESS_KEY_ID: AKIAJOZQS4H2PHQWYFCA
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.S3_SECRET_KEY }}
|
||||
AWS_REGION: 'us-east-2'
|
||||
SOURCE_DIR: 'shell/android-studio/flycast/build/outputs/apk/release/'
|
||||
DEST_DIR: android/${{ env.GIT_BUILD }}
|
||||
if: ${{ github.repository == 'flyinghead/flycast' && github.event_name == 'push' }}
|
||||
aws-access-key-id: AKIAJOZQS4H2PHQWYFCA
|
||||
aws-secret-access-key: ${{ secrets.S3_SECRET_KEY }}
|
||||
aws-region: us-east-2
|
||||
if: github.repository == 'flyinghead/flycast' && github.event_name == 'push'
|
||||
|
||||
- name: Upload to S3
|
||||
run: aws s3 sync shell/android-studio/flycast/build/outputs/apk/release s3://flycast-builds/android/${GITHUB_REF#refs/}-$GITHUB_SHA --acl public-read --exclude='*.json' --follow-symlinks
|
||||
if: ${{ steps.aws-credentials.outputs.aws-account-id != '' }}
|
||||
|
||||
- name: Upload to S3 (symbols)
|
||||
run: aws s3 sync symbols s3://flycast-symbols/android --follow-symlinks
|
||||
if: ${{ steps.aws-credentials.outputs.aws-account-id != '' }}
|
||||
+77
-72
@@ -7,112 +7,111 @@ jobs:
|
||||
name: ${{ matrix.config.name }}
|
||||
runs-on: ${{ matrix.config.os }}
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: ${{ matrix.config.shell }}
|
||||
|
||||
env:
|
||||
CCACHE_DIR: ${{ github.workspace }}/.ccache
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
config:
|
||||
- {name: i686-pc-windows-msvc, os: windows-latest, cmakeArgs: -DCMAKE_SYSTEM_VERSION="10.0.18362.0" -G "Visual Studio 16 2019" -A Win32}
|
||||
- {name: x86_64-apple-darwin, os: macos-latest, cmakeArgs: -G "Xcode", destDir: osx}
|
||||
- {name: x86_64-pc-linux-gnu, os: ubuntu-latest}
|
||||
- {name: x86_64-pc-windows-msvc, os: windows-latest, cmakeArgs: -DCMAKE_SYSTEM_VERSION="10.0.18362.0" -G "Visual Studio 16 2019" -A x64}
|
||||
- {name: x86_64-w64-mingw32, os: windows-latest, cmakeArgs: -G "MinGW Makefiles", destDir: win}
|
||||
- {name: i686-pc-windows-msvc, os: windows-latest, shell: cmd, arch: x86, cmakeArgs: -G Ninja, buildType: Release}
|
||||
- {name: apple-darwin, os: macos-latest, shell: sh, cmakeArgs: -G Xcode, destDir: osx, buildType: Release}
|
||||
- {name: apple-ios, os: macos-latest, shell: sh, cmakeArgs: -DCMAKE_SYSTEM_NAME=iOS -G Xcode, destDir: ios, buildType: Release}
|
||||
- {name: x86_64-pc-linux-gnu, os: ubuntu-latest, shell: sh, cmakeArgs: -G Ninja, buildType: Release}
|
||||
- {name: x86_64-pc-windows-msvc, os: windows-latest, shell: cmd, arch: x64, cmakeArgs: -G Ninja, buildType: Release}
|
||||
- {name: x86_64-w64-mingw32, os: windows-latest, shell: 'msys2 {0}', cmakeArgs: -G Ninja, destDir: win, buildType: RelWithDebInfo}
|
||||
- {name: libretro-x86_64-pc-linux-gnu, os: ubuntu-latest, shell: sh, cmakeArgs: -DLIBRETRO=ON -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE -G Ninja, buildType: Release}
|
||||
- {name: libretro-x86_64-w64-mingw32, os: windows-latest, shell: 'msys2 {0}', cmakeArgs: -DLIBRETRO=ON -G Ninja, buildType: Release}
|
||||
|
||||
steps:
|
||||
- name: Set up build environment (macos-latest)
|
||||
- name: Set up build environment (macOS)
|
||||
run: |
|
||||
brew install ccache libao libomp pulseaudio zlib
|
||||
echo "/usr/local/opt/ccache/libexec" >> $GITHUB_PATH
|
||||
echo "CCACHE_DIR=/tmp/ccache" >> $GITHUB_ENV
|
||||
if: matrix.config.os == 'macos-latest'
|
||||
brew update
|
||||
brew install libao ldid libomp ninja pulseaudio
|
||||
wget https://sdk.lunarg.com/sdk/download/1.3.204.1/mac/vulkansdk-macos-1.3.204.1.dmg
|
||||
hdiutil attach ./vulkansdk-macos-*.dmg
|
||||
sudo /Volumes/vulkansdk-macos-*/InstallVulkan.app/Contents/MacOS/InstallVulkan --root $HOME/VulkanSDK --accept-licenses --default-answer --confirm-command install
|
||||
hdiutil detach /Volumes/vulkansdk-macos-*
|
||||
echo "VULKAN_SDK=$HOME/VulkanSDK/macOS" >> $GITHUB_ENV
|
||||
if: runner.os == 'macOS'
|
||||
|
||||
- name: Set up build environment (ubuntu-latest)
|
||||
- name: Set up build environment (Linux)
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install ccache libao-dev libasound2-dev libevdev-dev libgl1-mesa-dev libpulse-dev libsdl2-dev libudev-dev libzip-dev libminiupnpc-dev
|
||||
echo "CCACHE_DIR=/tmp/ccache" >> $GITHUB_ENV
|
||||
if: matrix.config.os == 'ubuntu-latest'
|
||||
sudo apt-get -y install ccache libao-dev libasound2-dev libevdev-dev libgl1-mesa-dev liblua5.3-dev libminiupnpc-dev libpulse-dev libsdl2-dev libudev-dev libzip-dev ninja-build
|
||||
if: runner.os == 'Linux'
|
||||
|
||||
- name: Set up build environment (windows-latest)
|
||||
run: echo "DXSDK_DIR=${Env:HOMEDRIVE}${Env:HOMEPATH}\ccache\" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append
|
||||
if: matrix.config.os == 'windows-latest' && matrix.config.name != 'x86_64-w64-mingw32'
|
||||
|
||||
- uses: actions/cache@v2
|
||||
- name: Set up build environment (Windows, MinGW)
|
||||
uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
path: /tmp/ccache
|
||||
key: ccache-${{ matrix.config.os }}-${{ github.sha }}
|
||||
restore-keys: ccache-${{ matrix.config.os }}-
|
||||
if: matrix.config.os != 'windows-latest'
|
||||
msystem: MINGW64
|
||||
install: git make mingw-w64-x86_64-ccache mingw-w64-x86_64-cmake mingw-w64-x86_64-lua mingw-w64-x86_64-ninja mingw-w64-x86_64-SDL2 mingw-w64-x86_64-toolchain
|
||||
if: matrix.config.shell == 'msys2 {0}'
|
||||
|
||||
- uses: actions/cache@v2
|
||||
id: cache
|
||||
- name: Set up build environment (Windows, Visual Studio)
|
||||
run: |
|
||||
choco install ccache directx-sdk ninja
|
||||
echo DXSDK_DIR=C:\Program Files (x86)\Microsoft DirectX SDK (June 2010)>> %GITHUB_ENV%
|
||||
if: matrix.config.shell == 'cmd'
|
||||
|
||||
- uses: ilammy/msvc-dev-cmd@v1
|
||||
with:
|
||||
path: $HOME/ccache
|
||||
key: ccache-${{ matrix.config.os }}-${{ github.sha }}
|
||||
restore-keys: ccache-${{ matrix.config.os }}-
|
||||
if: matrix.config.os == 'windows-latest'
|
||||
arch: ${{ matrix.config.arch }}
|
||||
if: matrix.config.shell == 'cmd'
|
||||
|
||||
- name: Download DX2010
|
||||
if: steps.cache.outputs.cache-hit != 'true' && matrix.config.os == 'windows-latest' && matrix.config.name != 'x86_64-w64-mingw32'
|
||||
run: |
|
||||
curl -L https://download.microsoft.com/download/a/e/7/ae743f1f-632b-4809-87a9-aa1bb3458e31/DXSDK_Jun10.exe -o _DX2010_.exe
|
||||
7z x _DX2010_.exe DXSDK/Include -o_DX2010_
|
||||
7z x _DX2010_.exe DXSDK/Lib/x86 -o_DX2010_
|
||||
7z x _DX2010_.exe DXSDK/Lib/x64 -o_DX2010_
|
||||
mv _DX2010_/DXSDK $HOME/ccache
|
||||
rm -fR _DX*_ _DX*_.exe
|
||||
shell: bash
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
submodules: recursive
|
||||
submodules: true
|
||||
|
||||
- name: Create artifact directory
|
||||
run: mkdir -p build/artifact
|
||||
|
||||
- name: Build SDL (macos-latest)
|
||||
run: |
|
||||
cd shell/apple
|
||||
mkdir artifacts
|
||||
brew install --build-from-source ./sdl2.rb
|
||||
if: matrix.config.os == 'macos-latest'
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{ env.CCACHE_DIR }}
|
||||
key: ccache-${{ matrix.config.name }}-${{ github.sha }}
|
||||
restore-keys: ccache-${{ matrix.config.name }}-
|
||||
if: runner.os != 'macOS'
|
||||
|
||||
- name: CMake
|
||||
run: |
|
||||
cmake -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE=artifact ${{ matrix.config.cmakeArgs }}
|
||||
cmake --build build --config Release --parallel 2
|
||||
cmake -B build -DCMAKE_BUILD_TYPE=${{ matrix.config.buildType }} -DCMAKE_INSTALL_PREFIX=artifact ${{ matrix.config.cmakeArgs }}
|
||||
cmake --build build --config ${{ matrix.config.buildType }} --target install
|
||||
|
||||
- name: Unit Tests
|
||||
run: |
|
||||
mkdir -p build/tests
|
||||
cmake -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE=tests -DENABLE_CTEST=ON ${{ matrix.config.cmakeArgs }}
|
||||
cmake --build build --config Release --parallel 2
|
||||
./build/tests/flycast
|
||||
cmake -B build -DCMAKE_BUILD_TYPE=${{ matrix.config.buildType }} -DCMAKE_INSTALL_PREFIX=artifact -DENABLE_CTEST=ON ${{ matrix.config.cmakeArgs }}
|
||||
cmake --build build --config ${{ matrix.config.buildType }}
|
||||
./build/flycast
|
||||
if: matrix.config.name == 'x86_64-pc-linux-gnu'
|
||||
|
||||
- uses: actions/upload-artifact@v2
|
||||
- name: Dump symbols
|
||||
run: |
|
||||
core/deps/breakpad/bin/dump_syms artifact/bin/flycast.exe > flycast.exe.sym 2>/dev/null
|
||||
BUILD_ID=`head -1 flycast.exe.sym | awk '{ print $4 }'`
|
||||
mkdir -p symbols/flycast.exe/$BUILD_ID
|
||||
mv flycast.exe.sym symbols/flycast.exe/$BUILD_ID
|
||||
strip artifact/bin/flycast.exe
|
||||
if: matrix.config.name == 'x86_64-w64-mingw32'
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: flycast-${{ matrix.config.name }}
|
||||
path: build/artifact
|
||||
path: artifact/bin
|
||||
|
||||
- name: Package app (macos)
|
||||
run: |
|
||||
cd build/artifact
|
||||
rm -rf Flycast.swiftmodule
|
||||
zip -r flycast.app.zip Flycast.app
|
||||
rm -rf Flycast.app
|
||||
if: matrix.config.os == 'macos-latest'
|
||||
cd artifact/bin
|
||||
zip -rm flycast.app.zip Flycast.app
|
||||
if: matrix.config.name == 'apple-darwin'
|
||||
|
||||
- name: Package app (windows)
|
||||
run: |
|
||||
powershell Compress-Archive build/artifact/flycast.exe build/artifact/flycast.zip
|
||||
rm build/artifact/flycast.exe
|
||||
powershell Compress-Archive artifact/bin/flycast.exe artifact/bin/flycast.zip
|
||||
rm artifact/bin/flycast.exe
|
||||
if: matrix.config.name == 'x86_64-w64-mingw32'
|
||||
|
||||
- name: Set up git vars
|
||||
run: |
|
||||
echo GIT_BUILD=`git describe --all --always | sed 's/remotes\/origin/heads/'`-$GITHUB_SHA >> $GITHUB_ENV
|
||||
shell: bash
|
||||
|
||||
- name: Configure AWS Credentials
|
||||
id: aws-credentials
|
||||
uses: aws-actions/configure-aws-credentials@v1
|
||||
@@ -123,5 +122,11 @@ jobs:
|
||||
if: github.repository == 'flyinghead/flycast' && github.event_name == 'push' && matrix.config.destDir != ''
|
||||
|
||||
- name: Upload to S3
|
||||
run: aws s3 sync build/artifact s3://flycast-builds/${{ matrix.config.destDir }}/${{ env.GIT_BUILD }} --acl public-read --follow-symlinks
|
||||
run: aws s3 sync artifact/bin s3://flycast-builds/${{ matrix.config.destDir }}/${GITHUB_REF#refs/}-$GITHUB_SHA --acl public-read --follow-symlinks
|
||||
shell: bash
|
||||
if: ${{ steps.aws-credentials.outputs.aws-account-id != '' }}
|
||||
|
||||
- name: Upload symbols to S3
|
||||
run: aws s3 sync symbols s3://flycast-symbols/${{ matrix.config.destDir }} --follow-symlinks
|
||||
shell: bash
|
||||
if: ${{ steps.aws-credentials.outputs.aws-account-id != '' && matrix.config.name == 'x86_64-w64-mingw32' }}
|
||||
@@ -0,0 +1,33 @@
|
||||
# Prepare source texts & upload them to Crowdin
|
||||
|
||||
name: Crowdin Source Texts Upload
|
||||
|
||||
# on change to the English texts
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
paths:
|
||||
- 'shell/libretro/libretro_core_options.h'
|
||||
|
||||
jobs:
|
||||
upload_source_file:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Setup Java JDK
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: 1.8
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v3
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Upload Source
|
||||
shell: bash
|
||||
env:
|
||||
CROWDIN_API_KEY: ${{ secrets.CROWDIN_API_KEY }}
|
||||
run: |
|
||||
python3 intl/upload_workflow.py $CROWDIN_API_KEY "flyinghead-flycast" "shell/libretro/libretro_core_options.h"
|
||||
@@ -0,0 +1,46 @@
|
||||
# Download translations form Crowdin & Recreate libretro_core_options_intl.h
|
||||
|
||||
name: Crowdin Translation Integration
|
||||
|
||||
on:
|
||||
schedule:
|
||||
# please choose a random time & weekday to avoid all repos synching at the same time
|
||||
- cron: '15 22 * * 5' # Fridays at 10:15 PM, UTC
|
||||
|
||||
jobs:
|
||||
create_intl_file:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Setup Java JDK
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: 1.8
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v3
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal access token.
|
||||
fetch-depth: 0 # otherwise, there would be errors pushing refs to the destination repository.
|
||||
|
||||
- name: Create intl file
|
||||
shell: bash
|
||||
env:
|
||||
CROWDIN_API_KEY: ${{ secrets.CROWDIN_API_KEY }}
|
||||
run: |
|
||||
python3 intl/download_workflow.py $CROWDIN_API_KEY "flyinghead-flycast" "shell/libretro/libretro_core_options_intl.h"
|
||||
|
||||
- name: Commit files
|
||||
run: |
|
||||
git config --local user.email "[email protected]"
|
||||
git config --local user.name "github-actions[bot]"
|
||||
git add intl/*_workflow.py "shell/libretro/libretro_core_options_intl.h"
|
||||
git commit -m "Fetch translations & Recreate libretro_core_options_intl.h"
|
||||
|
||||
- name: GitHub Push
|
||||
uses: ad-m/[email protected]
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
branch: ${{ github.ref }}
|
||||
@@ -0,0 +1,59 @@
|
||||
name: Nintendo Switch CI
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: ${{ matrix.config.name }}
|
||||
runs-on: ubuntu-latest
|
||||
container: devkitpro/devkita64:20220128
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
config:
|
||||
- {name: standalone, destDir: switch}
|
||||
- {name: libretro, cmakeArgs: -DLIBRETRO=ON}
|
||||
|
||||
steps:
|
||||
- name: Set up build environment
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install awscli ccache ninja-build
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
submodules: true
|
||||
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.ccache
|
||||
key: ccache-switch-${{ matrix.config.name }}-${{ github.sha }}
|
||||
restore-keys: ccache-switch-${{ matrix.config.name }}-
|
||||
|
||||
- name: CMake
|
||||
run: |
|
||||
$DEVKITPRO/portlibs/switch/bin/aarch64-none-elf-cmake -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=artifact -G Ninja ${{ matrix.config.cmakeArgs }}
|
||||
cmake --build build --config Release --target install
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: flycast-switch-${{ matrix.config.name }}
|
||||
path: artifact/bin
|
||||
|
||||
- name: Package app
|
||||
run: zip -m artifact/bin/flycast.nro.zip artifact/bin/flycast.nro
|
||||
if: hashFiles('artifact/bin/flycast.nro') != ''
|
||||
|
||||
- name: Configure AWS Credentials
|
||||
id: aws-credentials
|
||||
uses: aws-actions/configure-aws-credentials@v1
|
||||
with:
|
||||
aws-access-key-id: AKIAJOZQS4H2PHQWYFCA
|
||||
aws-secret-access-key: ${{ secrets.S3_SECRET_KEY }}
|
||||
aws-region: us-east-2
|
||||
if: github.repository == 'flyinghead/flycast' && github.event_name == 'push' && matrix.config.destDir != ''
|
||||
|
||||
- name: Upload to S3
|
||||
run: aws s3 sync artifact/bin s3://flycast-builds/${{ matrix.config.destDir }}/${GITHUB_REF#refs/}-$GITHUB_SHA --acl public-read --follow-symlinks
|
||||
if: ${{ steps.aws-credentials.outputs.aws-account-id != '' }}
|
||||
@@ -0,0 +1,69 @@
|
||||
name: Windows UWP CI
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: windows-latest
|
||||
|
||||
env:
|
||||
VCPKG_ROOT: ${{ github.workspace }}/vcpkg
|
||||
VCPKG_DEFAULT_BINARY_CACHE: ${{ github.workspace }}/vcpkg/bincache
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
submodules: true
|
||||
|
||||
- name: bootstrap vcpkg
|
||||
run: |
|
||||
git clone https://github.com/microsoft/vcpkg
|
||||
mkdir vcpkg\bincache
|
||||
vcpkg\bootstrap-vcpkg.bat
|
||||
|
||||
- uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{ env.VCPKG_DEFAULT_BINARY_CACHE }}
|
||||
key: vcpkg-${{ hashFiles( 'vcpkg.json' ) }}
|
||||
|
||||
- name: CMake
|
||||
run: |
|
||||
cmake -B build -DCMAKE_BUILD_TYPE=Release -G "Visual Studio 17 2022" -A x64 -DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION=10.0 -DCMAKE_SYSTEM_PROCESSOR=AMD64 -DCMAKE_CROSSCOMPILING=OFF -DUSE_VULKAN=OFF -DCMAKE_TOOLCHAIN_FILE=%VCPKG_ROOT%\scripts\buildsystems\vcpkg.cmake
|
||||
cmake --build build --config Release --parallel 2
|
||||
shell: cmd
|
||||
|
||||
- uses: ilammy/msvc-dev-cmd@v1
|
||||
|
||||
- name: Package app
|
||||
run: |
|
||||
mkdir build\artifact
|
||||
cd build\AppPackages\flycast\flycast_*_x64_Test
|
||||
mkdir tmp
|
||||
ren *.msix flycast.msix
|
||||
makeappx.exe unpack /p .\flycast.msix /d tmp
|
||||
copy ..\..\..\Release\*.dll tmp
|
||||
makeappx pack /d tmp /p ..\..\..\artifact\flycast.appx
|
||||
|
||||
- name: Sign app
|
||||
run: signtool sign /f shell\uwp\sign_cert.pfx /p '${{ secrets.SIGN_CERT_PWD }}' /v /fd SHA256 build\artifact\flycast.appx
|
||||
if: github.repository == 'flyinghead/flycast' && github.event_name == 'push'
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: flycast-uwp
|
||||
path: build/artifact
|
||||
|
||||
- name: Configure AWS Credentials
|
||||
id: aws-credentials
|
||||
uses: aws-actions/configure-aws-credentials@v1
|
||||
with:
|
||||
aws-access-key-id: AKIAJOZQS4H2PHQWYFCA
|
||||
aws-secret-access-key: ${{ secrets.S3_SECRET_KEY }}
|
||||
aws-region: us-east-2
|
||||
if: github.repository == 'flyinghead/flycast' && github.event_name == 'push'
|
||||
|
||||
- name: Upload to S3
|
||||
run: aws s3 sync build/artifact s3://flycast-builds/xbox/${GITHUB_REF#refs/}-$GITHUB_SHA --acl public-read --follow-symlinks
|
||||
shell: bash
|
||||
if: ${{ steps.aws-credentials.outputs.aws-account-id != '' }}
|
||||
+5
-44
@@ -1,50 +1,11 @@
|
||||
build/
|
||||
|
||||
# macOS
|
||||
.DS_Store
|
||||
*.class
|
||||
*.orig
|
||||
*build_obj
|
||||
Workdir/data
|
||||
Workdir/reicast*
|
||||
Workdir/vmu*
|
||||
Workdir/webui*
|
||||
Workdir/emu.cfg
|
||||
Workdir/lib*ant.properties
|
||||
|
||||
# iOS General
|
||||
*/build/*
|
||||
**/build/*
|
||||
*.pbxuser
|
||||
!default.pbxuser
|
||||
*.mode1v3
|
||||
!default.mode1v3
|
||||
*.mode2v3
|
||||
!default.mode2v3
|
||||
*.perspectivev3
|
||||
!default.perspectivev3
|
||||
xcuserdata
|
||||
profile
|
||||
*.moved-aside
|
||||
DerivedData
|
||||
*.hmap
|
||||
emulator.xccheckout
|
||||
reicast.xccheckout
|
||||
build/*
|
||||
*.so
|
||||
*Karen_angelXwind*
|
||||
local.properties
|
||||
ant.properties
|
||||
*.d
|
||||
reicast-ios.xccheckout
|
||||
|
||||
# Linux General
|
||||
shell/linux/.map
|
||||
shell/linux/flycast.elf.map
|
||||
shell/linux/nosym-flycast.elf
|
||||
shell/linux/flycast.elf
|
||||
shell/linux/dispframe.elf
|
||||
|
||||
# Visual Studio
|
||||
generated
|
||||
.vs
|
||||
.vs/
|
||||
out/
|
||||
|
||||
# JetBrains IDES
|
||||
.idea/
|
||||
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
# DESCRIPTION: GitLab CI/CD for libRetro (NOT FOR GitLab-proper)
|
||||
|
||||
##############################################################################
|
||||
################################# BOILERPLATE ################################
|
||||
##############################################################################
|
||||
|
||||
# Core definitions
|
||||
.core-defs:
|
||||
variables:
|
||||
GIT_SUBMODULE_STRATEGY: recursive
|
||||
CORENAME: flycast
|
||||
CORE_ARGS: -DLIBRETRO=ON -DCMAKE_BUILD_TYPE=Release
|
||||
|
||||
.core-defs-linux:
|
||||
extends: .core-defs
|
||||
variables:
|
||||
CORE_ARGS: -DLIBRETRO=ON -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE -DCMAKE_BUILD_TYPE=Release
|
||||
|
||||
.core-defs-osx-x64:
|
||||
extends: .core-defs
|
||||
variables:
|
||||
CORE_ARGS: -DLIBRETRO=ON -G Xcode -DCMAKE_BUILD_TYPE=Release
|
||||
EXTRA_PATH: Release
|
||||
|
||||
.core-defs-android:
|
||||
extends: .core-defs
|
||||
script:
|
||||
- cmake $CORE_ARGS -DANDROID_PLATFORM=android-$API_LEVEL -DCMAKE_TOOLCHAIN_FILE=$NDK_ROOT/build/cmake/android.toolchain.cmake -DANDROID_STL=c++_static -DANDROID_ABI=$ANDROID_ABI -DANDROID_ARM_MODE=arm "$CMAKE_SOURCE_ROOT" -B$BUILD_DIR
|
||||
- cmake --build $BUILD_DIR --target ${CORENAME}_libretro --config Release -- -j $NUMPROC
|
||||
- mv $BUILD_DIR/${CORENAME}_libretro.so $LIBNAME
|
||||
- if [ $STRIP_CORE_LIB -eq 1 ]; then $NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip $LIBNAME; fi
|
||||
variables:
|
||||
API_LEVEL: 18
|
||||
|
||||
# Inclusion templates, required for the build to work
|
||||
include:
|
||||
################################## DESKTOPS ################################
|
||||
# Windows
|
||||
- project: 'libretro-infrastructure/ci-templates'
|
||||
file: '/windows-cmake-mingw.yml'
|
||||
|
||||
# MacOS
|
||||
- project: 'libretro-infrastructure/ci-templates'
|
||||
file: 'osx-cmake-x86.yml'
|
||||
|
||||
# Linux
|
||||
- project: 'libretro-infrastructure/ci-templates'
|
||||
file: '/linux-cmake.yml'
|
||||
|
||||
################################## CELLULAR ################################
|
||||
# Android
|
||||
- project: 'libretro-infrastructure/ci-templates'
|
||||
file: '/android-cmake.yml'
|
||||
|
||||
# Stages for building
|
||||
stages:
|
||||
- build-prepare
|
||||
- build-shared
|
||||
|
||||
##############################################################################
|
||||
#################################### STAGES ##################################
|
||||
##############################################################################
|
||||
#
|
||||
################################### DESKTOPS #################################
|
||||
# Windows 64-bit
|
||||
libretro-build-windows-x64:
|
||||
extends:
|
||||
- .libretro-windows-cmake-x86_64
|
||||
- .core-defs
|
||||
|
||||
# Windows 32-bit
|
||||
libretro-build-windows-i686:
|
||||
extends:
|
||||
- .libretro-windows-cmake-x86
|
||||
- .core-defs
|
||||
|
||||
# Linux 64-bit
|
||||
libretro-build-linux-x64:
|
||||
extends:
|
||||
- .libretro-linux-cmake-x86_64
|
||||
- .core-defs-linux
|
||||
|
||||
# Linux 32-bit
|
||||
libretro-build-linux-i686:
|
||||
extends:
|
||||
- .libretro-linux-cmake-x86
|
||||
- .core-defs-linux
|
||||
|
||||
# MacOS 64-bit
|
||||
libretro-build-osx-x64:
|
||||
extends:
|
||||
- .libretro-osx-cmake-x86
|
||||
- .core-defs-osx-x64
|
||||
|
||||
################################### CELLULAR #################################
|
||||
# Android ARMv7a
|
||||
android-armeabi-v7a:
|
||||
extends:
|
||||
- .libretro-android-cmake-armeabi-v7a
|
||||
- .core-defs-android
|
||||
|
||||
# Android ARMv8a
|
||||
android-arm64-v8a:
|
||||
extends:
|
||||
- .libretro-android-cmake-arm64-v8a
|
||||
- .core-defs-android
|
||||
|
||||
# Android 64-bit x86
|
||||
android-x86_64:
|
||||
extends:
|
||||
- .libretro-android-cmake-x86_64
|
||||
- .core-defs-android
|
||||
|
||||
# Android 32-bit x86
|
||||
android-x86:
|
||||
extends:
|
||||
- .libretro-android-cmake-x86
|
||||
- .core-defs-android
|
||||
@@ -4,3 +4,9 @@
|
||||
[submodule "core/deps/libchdr"]
|
||||
path = core/deps/libchdr
|
||||
url = https://github.com/rtissera/libchdr.git
|
||||
[submodule "core/deps/luabridge"]
|
||||
path = core/deps/luabridge
|
||||
url = https://github.com/vinniefalco/LuaBridge.git
|
||||
[submodule "core/deps/breakpad"]
|
||||
path = core/deps/breakpad
|
||||
url = https://github.com/flyinghead/mingw-breakpad
|
||||
+819
-346
File diff suppressed because it is too large.
Load diff
@@ -1,7 +1,9 @@
|
||||
# Flycast
|
||||
|
||||
[](https://github.com/flyinghead/flycast/actions/workflows/c-cpp.yml)
|
||||
[](https://github.com/flyinghead/flycast/actions/workflows/android.yml)
|
||||
[](https://github.com/flyinghead/flycast/actions/workflows/c-cpp.yml)
|
||||
[](https://github.com/flyinghead/flycast/actions/workflows/switch.yml)
|
||||
[](https://github.com/flyinghead/flycast/actions/workflows/uwp.yml)
|
||||
|
||||

|
||||
|
||||
@@ -13,7 +15,7 @@ Join us on our [**Discord server**](https://discord.gg/X8YWP8w) for a chat.
|
||||
|
||||
## Install
|
||||
|
||||
### Flatpak
|
||||
### Flatpak (Linux)
|
||||
|
||||
1. [Set up Flatpak](https://www.flatpak.org/setup/)
|
||||
|
||||
@@ -25,12 +27,20 @@ Join us on our [**Discord server**](https://discord.gg/X8YWP8w) for a chat.
|
||||
|
||||
`flatpak run org.flycast.Flycast`
|
||||
|
||||
### Homebrew (MacOS)
|
||||
|
||||
1. [Set up Homebrew](https://brew.sh)
|
||||
|
||||
2. Install Flycast via Homebrew
|
||||
|
||||
`brew install --cask flycast`
|
||||
|
||||
### Xbox One
|
||||
|
||||
Open [**gamr13's github page**](https://gamr13.github.io/) from your console.
|
||||
|
||||
### Binaries
|
||||
|
||||
Get fresh builds for your system [on the builds page](https://flyinghead.github.io/flycast-builds/).
|
||||
Get fresh builds for your system [**on the builds page**](https://flyinghead.github.io/flycast-builds/).
|
||||
|
||||
**New:** Now automated test results are available as well.
|
||||
|
||||
## Disclaimer
|
||||
|
||||
All code contributed to this fork is *not* bound by the Individual Contributor License Agreement of the upstream repository (https://github.com/reicast/reicast-emulator) and shall *not* be considered as a contribution to the upstream repository.
|
||||
@@ -33,20 +33,10 @@ bool SzArchive::Open(const char* path)
|
||||
|
||||
File_Close(&archiveStream.file);
|
||||
File_Construct(&archiveStream.file);
|
||||
#ifdef USE_WINDOWS_FILE
|
||||
nowide::wstackstring wpath;
|
||||
if (!wpath.convert(path))
|
||||
return false;
|
||||
archiveStream.file.handle = CreateFileW(wpath.c_str(),
|
||||
GENERIC_READ, FILE_SHARE_READ, NULL,
|
||||
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (archiveStream.file.handle == INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
#else
|
||||
archiveStream.file.file = nowide::fopen(path, "rb");
|
||||
if (archiveStream.file.file == nullptr)
|
||||
return false;
|
||||
#endif
|
||||
|
||||
FileInStream_CreateVTable(&archiveStream);
|
||||
LookToRead2_CreateVTable(&lookStream, 0);
|
||||
lookStream.buf = (Byte *)ISzAlloc_Alloc(&g_Alloc, kInputBufSize);
|
||||
|
||||
@@ -32,6 +32,7 @@ public:
|
||||
size_t Size() const { return size; }
|
||||
size_t Read(void *data, size_t length);
|
||||
size_t Write(const void *data, size_t length);
|
||||
FILE *rawFile() const { return file; }
|
||||
|
||||
private:
|
||||
FILE *file = nullptr;
|
||||
|
||||
+21
-6
@@ -181,13 +181,17 @@
|
||||
#define FEAT_DSPREC DYNAREC_NONE
|
||||
#endif
|
||||
|
||||
#ifdef __SWITCH__
|
||||
#define FEAT_NO_RWX_PAGES
|
||||
#endif
|
||||
|
||||
//defaults
|
||||
|
||||
#ifndef FEAT_SHREC
|
||||
#if HOST_CPU == CPU_MIPS
|
||||
#define FEAT_SHREC DYNAREC_NONE
|
||||
#else
|
||||
#if HOST_CPU == CPU_ARM || HOST_CPU == CPU_ARM64 || HOST_CPU == CPU_X86 || HOST_CPU == CPU_X64
|
||||
#define FEAT_SHREC DYNAREC_JIT
|
||||
#else
|
||||
#define FEAT_SHREC DYNAREC_NONE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -200,15 +204,13 @@
|
||||
#endif
|
||||
|
||||
#ifndef FEAT_DSPREC
|
||||
#if HOST_CPU == CPU_X86 || HOST_CPU == CPU_ARM64 || HOST_CPU == CPU_X64
|
||||
#if HOST_CPU == CPU_ARM || HOST_CPU == CPU_ARM64 || HOST_CPU == CPU_X86 || HOST_CPU == CPU_X64
|
||||
#define FEAT_DSPREC DYNAREC_JIT
|
||||
#else
|
||||
#define FEAT_DSPREC DYNAREC_NONE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define USE_MINIUPNPC
|
||||
|
||||
// Some restrictions on FEAT_NO_RWX_PAGES
|
||||
#if defined(FEAT_NO_RWX_PAGES) && FEAT_SHREC == DYNAREC_JIT
|
||||
#if HOST_CPU != CPU_X64 && HOST_CPU != CPU_ARM64
|
||||
@@ -216,6 +218,19 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP)
|
||||
#define TARGET_UWP
|
||||
#endif
|
||||
#if !defined(LIBRETRO) && !defined(TARGET_UWP)
|
||||
#define USE_DX9
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#if !defined(LIBRETRO) && !defined(TARGET_NO_EXCEPTIONS)
|
||||
#define USE_GGPO
|
||||
#endif
|
||||
|
||||
// TARGET PLATFORM
|
||||
|
||||
|
||||
+28
-62
@@ -1,8 +1,5 @@
|
||||
/*
|
||||
Command line parsing
|
||||
~yay~
|
||||
|
||||
Nothing too interesting here, really
|
||||
*/
|
||||
|
||||
#include <cstdio>
|
||||
@@ -10,39 +7,9 @@
|
||||
#include <cstring>
|
||||
|
||||
#include "cfg/cfg.h"
|
||||
#include "stdclass.h"
|
||||
|
||||
char* trim_ws(char* str)
|
||||
{
|
||||
if (str==0 || strlen(str)==0)
|
||||
return 0;
|
||||
|
||||
while(*str)
|
||||
{
|
||||
if (!isspace(*str))
|
||||
break;
|
||||
str++;
|
||||
}
|
||||
|
||||
size_t l=strlen(str);
|
||||
|
||||
if (l==0)
|
||||
return 0;
|
||||
|
||||
while(l>0)
|
||||
{
|
||||
if (!isspace(str[l-1]))
|
||||
break;
|
||||
str[l-1]=0;
|
||||
l--;
|
||||
}
|
||||
|
||||
if (l==0)
|
||||
return 0;
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
int setconfig(char** arg,int cl)
|
||||
static int setconfig(char *arg[], int cl)
|
||||
{
|
||||
int rv=0;
|
||||
for(;;)
|
||||
@@ -50,43 +17,38 @@ int setconfig(char** arg,int cl)
|
||||
if (cl<1)
|
||||
{
|
||||
WARN_LOG(COMMON, "-config : invalid number of parameters, format is section:key=value");
|
||||
return rv;
|
||||
break;
|
||||
}
|
||||
char* sep=strstr(arg[1],":");
|
||||
if (sep==0)
|
||||
std::string value(arg[1]);
|
||||
auto seppos = value.find(':');
|
||||
if (seppos == std::string::npos)
|
||||
{
|
||||
WARN_LOG(COMMON, "-config : invalid parameter %s, format is section:key=value", arg[1]);
|
||||
return rv;
|
||||
WARN_LOG(COMMON, "-config : invalid parameter %s, format is section:key=value", value.c_str());
|
||||
break;
|
||||
}
|
||||
char* value=strstr(sep+1,"=");
|
||||
if (value==0)
|
||||
auto eqpos = value.find('=', seppos);
|
||||
if (eqpos == std::string::npos)
|
||||
{
|
||||
WARN_LOG(COMMON, "-config : invalid parameter %s, format is section:key=value", arg[1]);
|
||||
return rv;
|
||||
WARN_LOG(COMMON, "-config : invalid parameter %s, format is section:key=value", value.c_str());
|
||||
break;
|
||||
}
|
||||
|
||||
*sep++=0;
|
||||
*value++=0;
|
||||
std::string sect = trim_ws(value.substr(0, seppos));
|
||||
std::string key = trim_ws(value.substr(seppos + 1, eqpos - seppos - 1));
|
||||
value = trim_ws(value.substr(eqpos + 1));
|
||||
|
||||
char* sect=trim_ws(arg[1]);
|
||||
char* key=trim_ws(sep);
|
||||
value=trim_ws(value);
|
||||
|
||||
if (sect==0 || key==0)
|
||||
if (sect.empty() || key.empty())
|
||||
{
|
||||
WARN_LOG(COMMON, "-config : invalid parameter, format is section:key=value");
|
||||
return rv;
|
||||
break;
|
||||
}
|
||||
|
||||
const char* constval = value;
|
||||
if (constval==0)
|
||||
constval="";
|
||||
INFO_LOG(COMMON, "Virtual cfg %s:%s=%s", sect, key, value);
|
||||
INFO_LOG(COMMON, "Virtual cfg %s:%s=%s", sect.c_str(), key.c_str(), value.c_str());
|
||||
|
||||
cfgSetVirtual(sect,key,value);
|
||||
cfgSetVirtual(sect, key, value);
|
||||
rv++;
|
||||
|
||||
if (cl>=3 && stricmp(arg[2],",")==0)
|
||||
if (cl>=3 && strcmp(arg[2],",")==0)
|
||||
{
|
||||
cl-=2;
|
||||
arg+=2;
|
||||
@@ -114,7 +76,7 @@ static int showhelp()
|
||||
|
||||
bool ParseCommandLine(int argc,char* argv[])
|
||||
{
|
||||
settings.imgread.ImagePath[0] = '\0';
|
||||
settings.content.path.clear();
|
||||
int cl=argc-2;
|
||||
char** arg=argv+1;
|
||||
while(cl>=0)
|
||||
@@ -136,6 +98,10 @@ bool ParseCommandLine(int argc,char* argv[])
|
||||
cl--;
|
||||
}
|
||||
#endif
|
||||
else if ((*arg)[0] == '-')
|
||||
{
|
||||
WARN_LOG(COMMON, "Ignoring unknown command line option '%s'", *arg);
|
||||
}
|
||||
else
|
||||
{
|
||||
char* extension = strrchr(*arg, '.');
|
||||
@@ -145,18 +111,18 @@ bool ParseCommandLine(int argc,char* argv[])
|
||||
|| stricmp(extension, ".gdi") == 0 || stricmp(extension, ".cue") == 0))
|
||||
{
|
||||
INFO_LOG(COMMON, "Using '%s' as cd image", *arg);
|
||||
strcpy(settings.imgread.ImagePath, *arg);
|
||||
settings.content.path = *arg;
|
||||
}
|
||||
else if (extension && stricmp(extension, ".elf") == 0)
|
||||
{
|
||||
INFO_LOG(COMMON, "Using '%s' as reios elf file", *arg);
|
||||
cfgSetVirtual("config", "bios.UseReios", "yes");
|
||||
strcpy(settings.imgread.ImagePath, *arg);
|
||||
settings.content.path = *arg;
|
||||
}
|
||||
else
|
||||
{
|
||||
INFO_LOG(COMMON, "Using '%s' as rom", *arg);
|
||||
strcpy(settings.imgread.ImagePath, *arg);
|
||||
settings.content.path = *arg;
|
||||
}
|
||||
}
|
||||
arg++;
|
||||
|
||||
+25
-62
@@ -1,8 +1,7 @@
|
||||
#include "ini.h"
|
||||
#include "types.h"
|
||||
#include <sstream>
|
||||
|
||||
char* trim_ws(char* str);
|
||||
#include "stdclass.h"
|
||||
|
||||
namespace emucfg {
|
||||
|
||||
@@ -197,74 +196,37 @@ void ConfigFile::set_bool(const std::string& section_name, const std::string& en
|
||||
|
||||
void ConfigFile::parse(FILE* file)
|
||||
{
|
||||
if(file == NULL)
|
||||
{
|
||||
if (file == nullptr)
|
||||
return;
|
||||
}
|
||||
|
||||
char line[512];
|
||||
char current_section[512] = { '\0' };
|
||||
std::string section;
|
||||
int cline = 0;
|
||||
while(file && !feof(file))
|
||||
while (true)
|
||||
{
|
||||
if (std::fgets(line, 512, file) == NULL || std::feof(file))
|
||||
{
|
||||
if (std::fgets(line, sizeof(line), file) == nullptr)
|
||||
break;
|
||||
}
|
||||
|
||||
cline++;
|
||||
|
||||
if (strlen(line) < 3)
|
||||
std::string s(line);
|
||||
s = trim_ws(s, " \r\n");
|
||||
if (s.empty())
|
||||
continue;
|
||||
if (s.length() >= 3 && s[0] == '[' && s[s.length() - 1] == ']')
|
||||
{
|
||||
section = s.substr(1, s.length() - 2);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (line[strlen(line)-1] == '\r' ||
|
||||
line[strlen(line)-1] == '\n')
|
||||
auto eqpos = s.find('=');
|
||||
if (eqpos == std::string::npos)
|
||||
{
|
||||
line[strlen(line)-1] = '\0';
|
||||
}
|
||||
|
||||
char* tl = trim_ws(line);
|
||||
|
||||
if (tl[0] == '[' && tl[strlen(tl)-1] == ']')
|
||||
{
|
||||
tl[strlen(tl)-1] = '\0';
|
||||
|
||||
// FIXME: Data loss if buffer is too small
|
||||
strncpy(current_section, tl+1, sizeof(current_section));
|
||||
current_section[sizeof(current_section) - 1] = '\0';
|
||||
|
||||
trim_ws(current_section);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (strlen(current_section) == 0)
|
||||
{
|
||||
continue; //no open section
|
||||
}
|
||||
|
||||
char* separator = strstr(tl, "=");
|
||||
|
||||
if (!separator)
|
||||
{
|
||||
WARN_LOG(COMMON, "Malformed entry on config - ignoring @ %d(%s)", cline, tl);
|
||||
continue;
|
||||
}
|
||||
|
||||
*separator = '\0';
|
||||
|
||||
char* name = trim_ws(tl);
|
||||
char* value = trim_ws(separator + 1);
|
||||
if (name == NULL || value == NULL)
|
||||
{
|
||||
//printf("Malformed entry on config - ignoring @ %d(%s)\n",cline, tl);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->set(std::string(current_section), std::string(name), std::string(value));
|
||||
}
|
||||
WARN_LOG(COMMON, "Malformed entry on config - ignoring line %d: %s", cline, s.c_str());
|
||||
continue;
|
||||
}
|
||||
std::string property = trim_ws(s.substr(0, eqpos));
|
||||
std::string value = trim_ws(s.substr(eqpos + 1));
|
||||
if (value.length() >= 2 && value[0] == '"' && value[value.length() - 1] == '"')
|
||||
value = value.substr(1, value.length() - 2);
|
||||
set(section, property, value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -275,7 +237,8 @@ void ConfigFile::save(FILE* file)
|
||||
const std::string& section_name = section_it.first;
|
||||
const ConfigSection& section = section_it.second;
|
||||
|
||||
std::fprintf(file, "[%s]\n", section_name.c_str());
|
||||
if (!section_name.empty())
|
||||
std::fprintf(file, "[%s]\n", section_name.c_str());
|
||||
|
||||
for (const auto& entry_it : section.entries)
|
||||
{
|
||||
@@ -283,8 +246,8 @@ void ConfigFile::save(FILE* file)
|
||||
const ConfigEntry& entry = entry_it.second;
|
||||
std::fprintf(file, "%s = %s\n", entry_name.c_str(), entry.get_string().c_str());
|
||||
}
|
||||
|
||||
std::fputs("\n", file);
|
||||
if (!section_name.empty())
|
||||
std::fputc('\n', file);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+19
-2
@@ -24,7 +24,6 @@ namespace config {
|
||||
|
||||
Option<bool> DynarecEnabled("Dynarec.Enabled", true);
|
||||
Option<bool> DynarecIdleSkip("Dynarec.idleskip", true);
|
||||
Option<bool> DynarecSafeMode("Dynarec.safe-mode");
|
||||
|
||||
// General
|
||||
|
||||
@@ -41,7 +40,6 @@ Option<int> SavestateSlot("Dreamcast.SavestateSlot");
|
||||
// Sound
|
||||
|
||||
Option<bool> DSPEnabled("aica.DSPEnabled", false);
|
||||
Option<bool> DisableSound("aica.NoSound");
|
||||
#if HOST_CPU == CPU_ARM
|
||||
Option<int> AudioBufferSize("aica.BufferSize", 5644); // 128 ms
|
||||
#else
|
||||
@@ -78,7 +76,11 @@ Option<bool> Fog("rend.Fog", true);
|
||||
Option<bool> FloatVMUs("rend.FloatVMUs");
|
||||
Option<bool> Rotate90("rend.Rotate90");
|
||||
Option<bool> PerStripSorting("rend.PerStripSorting");
|
||||
#ifdef __APPLE__
|
||||
Option<bool> DelayFrameSwapping("rend.DelayFrameSwapping", false);
|
||||
#else
|
||||
Option<bool> DelayFrameSwapping("rend.DelayFrameSwapping", true);
|
||||
#endif
|
||||
Option<bool> WidescreenGameHacks("rend.WidescreenGameHacks");
|
||||
std::array<Option<int>, 4> CrosshairColor {
|
||||
Option<int>("rend.CrossHairColor1"),
|
||||
@@ -91,12 +93,18 @@ Option<int> MaxThreads("pvr.MaxThreads", 3);
|
||||
Option<int> AutoSkipFrame("pvr.AutoSkipFrame", 0);
|
||||
Option<int> RenderResolution("rend.Resolution", 480);
|
||||
Option<bool> VSync("rend.vsync", true);
|
||||
Option<u64> PixelBufferSize("rend.PixelBufferSize", 512 * 1024 * 1024);
|
||||
Option<int> AnisotropicFiltering("rend.AnisotropicFiltering", 1);
|
||||
Option<int> TextureFiltering("rend.TextureFiltering", 0); // Default
|
||||
Option<bool> ThreadedRendering("rend.ThreadedRendering", true);
|
||||
Option<bool> DupeFrames("rend.DupeFrames", false);
|
||||
|
||||
// Misc
|
||||
|
||||
Option<bool> SerialConsole("Debug.SerialConsoleEnabled");
|
||||
Option<bool> SerialPTY("Debug.SerialPTY");
|
||||
Option<bool> UseReios("UseReios");
|
||||
Option<bool> FastGDRomLoad("FastGDRomLoad", false);
|
||||
|
||||
Option<bool> OpenGlChecks("OpenGlChecks", false, "validate");
|
||||
|
||||
@@ -110,6 +118,11 @@ Option<bool> ActAsServer("ActAsServer", false, "network");
|
||||
OptionString DNS("DNS", "46.101.91.123", "network");
|
||||
OptionString NetworkServer("server", "", "network");
|
||||
Option<bool> EmulateBBA("EmulateBBA", false, "network");
|
||||
Option<bool> GGPOEnable("GGPO", false, "network");
|
||||
Option<int> GGPODelay("GGPODelay", 0, "network");
|
||||
Option<bool> NetworkStats("Stats", true, "network");
|
||||
Option<int> GGPOAnalogAxes("GGPOAnalogAxes", 0, "network");
|
||||
Option<bool> GGPOChat("GGPOChat", true, "network");
|
||||
|
||||
#ifdef SUPPORT_DISPMANX
|
||||
Option<bool> DispmanxMaintainAspect("maintain_aspect", true, "dispmanx");
|
||||
@@ -148,4 +161,8 @@ std::array<std::array<Option<MapleDeviceType>, 2>, 4> MapleExpansionDevices {
|
||||
Option<bool> UseRawInput("RawInput", false, "input");
|
||||
#endif
|
||||
|
||||
#ifdef USE_LUA
|
||||
OptionString LuaFileName("LuaFileName", "flycast.lua");
|
||||
#endif
|
||||
|
||||
} // namespace config
|
||||
+103
-57
@@ -23,6 +23,9 @@
|
||||
#include <cmath>
|
||||
#include "cfg.h"
|
||||
#include "hw/maple/maple_cfg.h"
|
||||
#ifdef LIBRETRO
|
||||
#include <libretro.h>
|
||||
#endif
|
||||
|
||||
namespace config {
|
||||
|
||||
@@ -34,6 +37,10 @@ public:
|
||||
virtual void reset() = 0;
|
||||
};
|
||||
|
||||
#ifdef LIBRETRO
|
||||
#include "option_lr.h"
|
||||
#else
|
||||
|
||||
class Settings {
|
||||
public:
|
||||
void reset() {
|
||||
@@ -63,10 +70,6 @@ public:
|
||||
cfgSetAutoSave(true);
|
||||
}
|
||||
|
||||
const std::string& getGameId() const {
|
||||
return gameId;
|
||||
}
|
||||
|
||||
void setGameId(const std::string& gameId) {
|
||||
this->gameId = gameId;
|
||||
}
|
||||
@@ -118,7 +121,7 @@ public:
|
||||
|
||||
void load() override {
|
||||
if (PerGameOption && settings.hasPerGameConfig())
|
||||
set(doLoad(settings.getGameId(), section + "." + name));
|
||||
set(doLoad(settings.gameId, section + "." + name));
|
||||
else
|
||||
{
|
||||
set(doLoad(section, name));
|
||||
@@ -142,7 +145,7 @@ public:
|
||||
return;
|
||||
}
|
||||
if (PerGameOption && settings.hasPerGameConfig())
|
||||
doSave(settings.getGameId(), section + "." + name);
|
||||
doSave(settings.gameId, section + "." + name);
|
||||
else
|
||||
doSave(section, name);
|
||||
}
|
||||
@@ -195,7 +198,7 @@ protected:
|
||||
if (strValue.empty())
|
||||
return value;
|
||||
else
|
||||
return atof(strValue.c_str());
|
||||
return (float)atof(strValue.c_str());
|
||||
}
|
||||
|
||||
template <typename U = T>
|
||||
@@ -209,14 +212,50 @@ protected:
|
||||
std::vector<std::string> newValue;
|
||||
while (true)
|
||||
{
|
||||
std::string::size_type end = paths.find(';', start);
|
||||
if (end == std::string::npos)
|
||||
end = paths.size();
|
||||
if (start != end)
|
||||
newValue.push_back(paths.substr(start, end - start));
|
||||
if (end == paths.size())
|
||||
break;
|
||||
start = end + 1;
|
||||
if (paths[start] == '"')
|
||||
{
|
||||
std::string v;
|
||||
start++;
|
||||
while (true)
|
||||
{
|
||||
if (paths[start] == '"')
|
||||
{
|
||||
if (start + 1 >= paths.size())
|
||||
{
|
||||
newValue.push_back(v);
|
||||
return newValue;
|
||||
}
|
||||
if (paths[start + 1] == '"')
|
||||
{
|
||||
v += paths[start++];
|
||||
start++;
|
||||
}
|
||||
else if (paths[start + 1] == ';')
|
||||
{
|
||||
newValue.push_back(v);
|
||||
start += 2;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
v += paths[start++];
|
||||
}
|
||||
}
|
||||
else
|
||||
v += paths[start++];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string::size_type end = paths.find(';', start);
|
||||
if (end == std::string::npos)
|
||||
end = paths.size();
|
||||
if (start != end)
|
||||
newValue.push_back(paths.substr(start, end - start));
|
||||
if (end == paths.size())
|
||||
break;
|
||||
start = end + 1;
|
||||
}
|
||||
}
|
||||
return newValue;
|
||||
}
|
||||
@@ -257,12 +296,32 @@ protected:
|
||||
doSave(const std::string& section, const std::string& name) const
|
||||
{
|
||||
std::string s;
|
||||
for (auto& v : value)
|
||||
for (const auto& v : value)
|
||||
{
|
||||
if (s.empty())
|
||||
s = v;
|
||||
if (!s.empty())
|
||||
s += ';';
|
||||
if (v.find(';') != std::string::npos || (!v.empty() && v[0] == '"'))
|
||||
{
|
||||
s += '"';
|
||||
std::string v2 = v;
|
||||
while (true)
|
||||
{
|
||||
auto pos = v2.find('"');
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
s += v2.substr(0, pos + 1) + '"';
|
||||
v2 = v2.substr(pos + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
s += v2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
s += '"';
|
||||
}
|
||||
else
|
||||
s += ";" + v;
|
||||
s += v;
|
||||
}
|
||||
cfgSaveStr(section, name, s);
|
||||
}
|
||||
@@ -275,6 +334,7 @@ protected:
|
||||
bool overridden = false;
|
||||
Settings& settings;
|
||||
};
|
||||
#endif
|
||||
|
||||
using OptionString = Option<std::string>;
|
||||
|
||||
@@ -282,7 +342,7 @@ using OptionString = Option<std::string>;
|
||||
|
||||
extern Option<bool> DynarecEnabled;
|
||||
extern Option<bool> DynarecIdleSkip;
|
||||
extern Option<bool> DynarecSafeMode;
|
||||
constexpr bool DynarecSafeMode = false;
|
||||
|
||||
// General
|
||||
|
||||
@@ -300,7 +360,6 @@ extern Option<int> SavestateSlot;
|
||||
|
||||
constexpr bool LimitFPS = true;
|
||||
extern Option<bool> DSPEnabled;
|
||||
extern Option<bool> DisableSound;
|
||||
extern Option<int> AudioBufferSize; //In samples ,*4 for bytes
|
||||
extern Option<bool> AutoLatency;
|
||||
|
||||
@@ -323,9 +382,9 @@ public:
|
||||
void calcDbPower()
|
||||
{
|
||||
// dB scaling calculation: https://www.dr-lex.be/info-stuff/volumecontrols.html
|
||||
logarithmic_volume_scale = fmin(exp(4.605 * float(value) / 100.0) / 100.0, 1.0);
|
||||
logarithmic_volume_scale = std::min(std::exp(4.605f * float(value) / 100.f) / 100.f, 1.f);
|
||||
if (value < 10)
|
||||
logarithmic_volume_scale *= value / 10.0;
|
||||
logarithmic_volume_scale *= value / 10.f;
|
||||
}
|
||||
};
|
||||
extern AudioVolumeOption AudioVolume;
|
||||
@@ -335,49 +394,20 @@ extern AudioVolumeOption AudioVolume;
|
||||
class RendererOption : public Option<RenderType> {
|
||||
public:
|
||||
RendererOption()
|
||||
#ifdef _WIN32
|
||||
#ifdef USE_DX9
|
||||
: Option<RenderType>("pvr.rend", RenderType::DirectX9) {}
|
||||
#elif defined(TARGET_UWP)
|
||||
: Option<RenderType>("pvr.rend", RenderType::DirectX11) {}
|
||||
#else
|
||||
: Option<RenderType>("pvr.rend", RenderType::OpenGL) {}
|
||||
#endif
|
||||
|
||||
bool isOpenGL() const {
|
||||
return value == RenderType::OpenGL || value == RenderType::OpenGL_OIT;
|
||||
}
|
||||
bool isVulkan() const {
|
||||
return value == RenderType::Vulkan || value == RenderType::Vulkan_OIT;
|
||||
}
|
||||
bool isDirectX() const {
|
||||
return value == RenderType::DirectX9;
|
||||
}
|
||||
|
||||
void set(RenderType v)
|
||||
{
|
||||
newValue = v;
|
||||
}
|
||||
RenderType& operator=(const RenderType& v) { set(v); return value; }
|
||||
|
||||
void load() override {
|
||||
RenderType current = value;
|
||||
Option<RenderType>::load();
|
||||
newValue = value;
|
||||
value = current;
|
||||
}
|
||||
|
||||
void reset() override {
|
||||
// don't reset the value to avoid vk -> gl -> vk quick switching
|
||||
// don't reset the value to avoid quick switching when starting a game
|
||||
overridden = false;
|
||||
}
|
||||
|
||||
bool pendingChange() {
|
||||
return newValue != value;
|
||||
}
|
||||
void commit() {
|
||||
value = newValue;
|
||||
}
|
||||
|
||||
private:
|
||||
RenderType newValue = RenderType();
|
||||
};
|
||||
extern RendererOption RendererType;
|
||||
extern Option<bool> UseMipmaps;
|
||||
@@ -388,8 +418,10 @@ extern Option<bool> RenderToTextureBuffer;
|
||||
extern Option<bool> TranslucentPolygonDepthMask;
|
||||
extern Option<bool> ModifierVolumes;
|
||||
constexpr bool Clipping = true;
|
||||
#ifndef LIBRETRO
|
||||
extern Option<int> TextureUpscale;
|
||||
extern Option<int> MaxFilteredTextureSize;
|
||||
#endif
|
||||
extern Option<float> ExtraDepthScale;
|
||||
extern Option<bool> CustomTextures;
|
||||
extern Option<bool> DumpTextures;
|
||||
@@ -406,12 +438,18 @@ extern Option<int> MaxThreads;
|
||||
extern Option<int> AutoSkipFrame; // 0: none, 1: some, 2: more
|
||||
extern Option<int> RenderResolution;
|
||||
extern Option<bool> VSync;
|
||||
extern Option<u64> PixelBufferSize;
|
||||
extern Option<int> AnisotropicFiltering;
|
||||
extern Option<int> TextureFiltering; // 0: default, 1: force nearest, 2: force linear
|
||||
extern Option<bool> ThreadedRendering;
|
||||
extern Option<bool> DupeFrames;
|
||||
|
||||
// Misc
|
||||
|
||||
extern Option<bool> SerialConsole;
|
||||
extern Option<bool> SerialPTY;
|
||||
extern Option<bool> UseReios;
|
||||
extern Option<bool> FastGDRomLoad;
|
||||
|
||||
extern Option<bool> OpenGlChecks;
|
||||
|
||||
@@ -425,6 +463,11 @@ extern Option<bool> ActAsServer;
|
||||
extern OptionString DNS;
|
||||
extern OptionString NetworkServer;
|
||||
extern Option<bool> EmulateBBA;
|
||||
extern Option<bool> GGPOEnable;
|
||||
extern Option<int> GGPODelay;
|
||||
extern Option<bool> NetworkStats;
|
||||
extern Option<int> GGPOAnalogAxes;
|
||||
extern Option<bool> GGPOChat;
|
||||
|
||||
#ifdef SUPPORT_DISPMANX
|
||||
extern Option<bool> DispmanxMaintainAspect;
|
||||
@@ -447,5 +490,8 @@ extern Option<bool> UseRawInput;
|
||||
constexpr bool UseRawInput = false;
|
||||
#endif
|
||||
|
||||
} // namespace config
|
||||
#ifdef USE_LUA
|
||||
extern OptionString LuaFileName;
|
||||
#endif
|
||||
|
||||
} // namespace config
|
||||
+341
-58
@@ -23,8 +23,8 @@
|
||||
#include "cheats.h"
|
||||
#include "hw/sh4/sh4_mem.h"
|
||||
#include "reios/reios.h"
|
||||
#include "network/picoppp.h"
|
||||
#include "cfg/cfg.h"
|
||||
#include "cfg/ini.h"
|
||||
|
||||
const WidescreenCheat CheatManager::widescreen_cheats[] =
|
||||
{
|
||||
@@ -306,69 +306,53 @@ CheatManager cheatManager;
|
||||
|
||||
void CheatManager::loadCheatFile(const std::string& filename)
|
||||
{
|
||||
#ifndef LIBRETRO
|
||||
FILE* cheatfile = nowide::fopen(filename.c_str(), "r");
|
||||
if (cheatfile == nullptr)
|
||||
{
|
||||
WARN_LOG(COMMON, "Cannot open cheat file '%s'", filename.c_str());
|
||||
return;
|
||||
}
|
||||
cheats.clear();
|
||||
Cheat cheat;
|
||||
int cheatNumber = 0;
|
||||
char buffer[512];
|
||||
while (fgets(buffer, sizeof(buffer), cheatfile) != nullptr)
|
||||
{
|
||||
std::string l = buffer;
|
||||
auto equalPos = l.find('=');
|
||||
if (equalPos == std::string::npos)
|
||||
continue;
|
||||
auto quotePos = l.find('"', equalPos);
|
||||
if (quotePos == std::string::npos)
|
||||
continue;
|
||||
auto quote2Pos = l.find('"', quotePos + 1);
|
||||
if (quote2Pos == std::string::npos)
|
||||
continue;
|
||||
if (l.substr(0, 5) != "cheat" || l[5] < '0' || l[5] > '9')
|
||||
continue;
|
||||
char *p;
|
||||
int number = strtol(&l[5], &p, 10);
|
||||
if (number != cheatNumber && cheat.type != Cheat::Type::disabled)
|
||||
{
|
||||
cheatNumber = number;
|
||||
cheats.push_back(cheat);
|
||||
cheat = Cheat();
|
||||
}
|
||||
std::string param = trim_trailing_ws(l.substr(p - &l[0], equalPos - (p - &l[0])));
|
||||
std::string value = l.substr(quotePos + 1, quote2Pos - quotePos - 1);
|
||||
emucfg::ConfigFile cfg;
|
||||
cfg.parse(cheatfile);
|
||||
fclose(cheatfile);
|
||||
|
||||
if (param == "_address")
|
||||
int count = cfg.get_int("", "cheats", 0);
|
||||
cheats.clear();
|
||||
for (int i = 0; count == 0 || i < count; i++)
|
||||
{
|
||||
std::string prefix = "cheat" + std::to_string(i) + "_";
|
||||
Cheat cheat{};
|
||||
cheat.description = cfg.get("", prefix + "desc", "Cheat " + std::to_string(i + 1));
|
||||
cheat.address = cfg.get_int("", prefix + "address", -1);
|
||||
if (count == 0 && cheat.address == (u32)-1)
|
||||
break;
|
||||
if (cheat.address >= RAM_SIZE)
|
||||
{
|
||||
cheat.address = strtol(value.c_str(), nullptr, 10);
|
||||
verify(cheat.address < RAM_SIZE);
|
||||
WARN_LOG(COMMON, "Invalid address %x", cheat.address);
|
||||
continue;
|
||||
}
|
||||
else if (param == "_cheat_type")
|
||||
cheat.type = (Cheat::Type)strtol(value.c_str(), nullptr, 10);
|
||||
else if (param == "_desc")
|
||||
cheat.description = value;
|
||||
else if (param == "_memory_search_size")
|
||||
cheat.size = 1 << strtol(value.c_str(), nullptr, 10);
|
||||
else if (param == "_value")
|
||||
cheat.value = strtol(value.c_str(), nullptr, 10);
|
||||
else if (param == "_repeat_count")
|
||||
cheat.repeatCount = strtol(value.c_str(), nullptr, 10);
|
||||
else if (param == "_repeat_add_to_value")
|
||||
cheat.repeatValueIncrement = strtol(value.c_str(), nullptr, 10);
|
||||
else if (param == "_repeat_add_to_address")
|
||||
cheat.repeatAddressIncrement = strtol(value.c_str(), nullptr, 10);
|
||||
else if (param == "_enable")
|
||||
cheat.enabled = value == "true";
|
||||
cheat.type = (Cheat::Type)cfg.get_int("", prefix + "cheat_type", (int)Cheat::Type::disabled);
|
||||
cheat.size = 1 << cfg.get_int("", prefix + "memory_search_size", 0);
|
||||
cheat.value = cfg.get_int("", prefix + "value", cheat.value);
|
||||
cheat.repeatCount = cfg.get_int("", prefix + "repeat_count", cheat.repeatCount);
|
||||
cheat.repeatValueIncrement = cfg.get_int("", prefix + "repeat_add_to_value", cheat.repeatValueIncrement);
|
||||
cheat.repeatAddressIncrement = cfg.get_int("", prefix + "repeat_add_to_address", cheat.repeatAddressIncrement);
|
||||
cheat.enabled = cfg.get_bool("", prefix + "enable", false);
|
||||
cheat.destAddress = cfg.get_int("", prefix + "dest_address", 0);
|
||||
if (cheat.destAddress >= RAM_SIZE)
|
||||
{
|
||||
WARN_LOG(COMMON, "Invalid address %x", cheat.destAddress);
|
||||
continue;
|
||||
}
|
||||
cheat.valueMask = cfg.get_int("", prefix + "address_bit_position", 0);
|
||||
if (cheat.type != Cheat::Type::disabled)
|
||||
cheats.push_back(cheat);
|
||||
}
|
||||
std::fclose(cheatfile);
|
||||
if (cheat.type != Cheat::Type::disabled)
|
||||
cheats.push_back(cheat);
|
||||
active = !cheats.empty();
|
||||
INFO_LOG(COMMON, "%d cheats loaded", (int)cheats.size());
|
||||
cfgSaveStr("cheats", gameId, filename);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CheatManager::reset(const std::string& gameId)
|
||||
@@ -378,9 +362,11 @@ void CheatManager::reset(const std::string& gameId)
|
||||
cheats.clear();
|
||||
active = false;
|
||||
this->gameId = gameId;
|
||||
#ifndef LIBRETRO
|
||||
std::string cheatFile = cfgLoadStr("cheats", gameId, "");
|
||||
if (!cheatFile.empty())
|
||||
loadCheatFile(cheatFile);
|
||||
#endif
|
||||
}
|
||||
widescreen_cheat = nullptr;
|
||||
if (!config::WidescreenGameHacks)
|
||||
@@ -423,14 +409,12 @@ u32 CheatManager::readRam(u32 addr, u32 bits)
|
||||
switch (bits)
|
||||
{
|
||||
case 8:
|
||||
default:
|
||||
return ReadMem8_nommu(0x8C000000 + addr);
|
||||
case 16:
|
||||
return ReadMem16_nommu(0x8C000000 + addr);
|
||||
case 32:
|
||||
return ReadMem32_nommu(0x8C000000 + addr);
|
||||
default:
|
||||
die("invalid size");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -439,6 +423,7 @@ void CheatManager::writeRam(u32 addr, u32 value, u32 bits)
|
||||
switch (bits)
|
||||
{
|
||||
case 8:
|
||||
default:
|
||||
WriteMem8_nommu(0x8C000000 + addr, (u8)value);
|
||||
break;
|
||||
case 16:
|
||||
@@ -447,9 +432,6 @@ void CheatManager::writeRam(u32 addr, u32 value, u32 bits)
|
||||
case 32:
|
||||
WriteMem32_nommu(0x8C000000 + addr, value);
|
||||
break;
|
||||
default:
|
||||
die("invalid size");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -460,7 +442,7 @@ void CheatManager::apply()
|
||||
for (size_t i = 0; i < ARRAY_SIZE(widescreen_cheat->addresses) && widescreen_cheat->addresses[i] != 0; i++)
|
||||
writeRam(widescreen_cheat->addresses[i], widescreen_cheat->values[i], 32);
|
||||
}
|
||||
if (active && !networkStarted())
|
||||
if (active && !settings.network.online)
|
||||
{
|
||||
bool skipCheat = false;
|
||||
for (const Cheat& cheat : cheats)
|
||||
@@ -503,12 +485,27 @@ void CheatManager::apply()
|
||||
case Cheat::Type::runNextIfLt:
|
||||
skipCheat = readRam(cheat.address, cheat.size) >= cheat.value;
|
||||
break;
|
||||
case Cheat::Type::copy:
|
||||
for (u32 i = 0; i < cheat.repeatCount; i++)
|
||||
writeRam(cheat.destAddress + i, readRam(cheat.address + i, cheat.size), cheat.size);
|
||||
break;
|
||||
}
|
||||
if (setValue)
|
||||
{
|
||||
u32 address = cheat.address;
|
||||
for (u32 repeat = 0; repeat < cheat.repeatCount; repeat++)
|
||||
{
|
||||
if (cheat.size < 8)
|
||||
{
|
||||
u8 curVal = readRam(address, 8);
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
int bitmask = 1 << i;
|
||||
if ((cheat.valueMask & bitmask) == 0)
|
||||
// keep current bit value
|
||||
valueToSet = (valueToSet & ~bitmask) | (curVal & bitmask);
|
||||
}
|
||||
}
|
||||
writeRam(address, valueToSet, cheat.size);
|
||||
address += cheat.repeatAddressIncrement * cheat.size / 8;
|
||||
valueToSet += cheat.repeatValueIncrement;
|
||||
@@ -517,3 +514,289 @@ void CheatManager::apply()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static std::vector<u32> parseCodes(const std::string& s)
|
||||
{
|
||||
std::vector<u32> codes;
|
||||
std::string curCode;
|
||||
for (u8 c : s)
|
||||
{
|
||||
if (std::isxdigit(c))
|
||||
{
|
||||
curCode += c;
|
||||
if (curCode.length() == 8)
|
||||
{
|
||||
codes.push_back(strtol(curCode.c_str(), nullptr, 16));
|
||||
curCode.clear();
|
||||
}
|
||||
}
|
||||
else if (!curCode.empty())
|
||||
throw FlycastException("Invalid cheat code");
|
||||
}
|
||||
if (!curCode.empty())
|
||||
{
|
||||
if (curCode.length() != 8)
|
||||
throw FlycastException("Invalid cheat code");
|
||||
codes.push_back(strtol(curCode.c_str(), nullptr, 16));
|
||||
}
|
||||
|
||||
return codes;
|
||||
}
|
||||
|
||||
void CheatManager::addGameSharkCheat(const std::string& name, const std::string& s)
|
||||
{
|
||||
std::vector<u32> codes = parseCodes(s);
|
||||
Cheat conditionCheat;
|
||||
unsigned conditionLimit = 0;
|
||||
|
||||
for (unsigned i = 0; i < codes.size(); i++)
|
||||
{
|
||||
if (i < conditionLimit)
|
||||
cheats.push_back(conditionCheat);
|
||||
Cheat cheat{};
|
||||
cheat.description = name;
|
||||
u32 code = (codes[i] & 0xff000000) >> 24;
|
||||
switch (code)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
{
|
||||
// 8/16/32-bit write
|
||||
if (i + 1 >= codes.size())
|
||||
throw FlycastException("Missing value");
|
||||
cheat.type = Cheat::Type::setValue;
|
||||
cheat.size = code == 0 ? 8 : code == 1 ? 16 : 32;
|
||||
cheat.address = codes[i] & 0x00ffffff;
|
||||
cheat.value = codes[++i];
|
||||
cheats.push_back(cheat);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
{
|
||||
u32 subcode = (codes[i] & 0x00ff0000) >> 16;
|
||||
switch (subcode)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
// Group write
|
||||
int count = codes[i] & 0xffff;
|
||||
if (i + count + 1 >= codes.size())
|
||||
throw FlycastException("Missing values");
|
||||
cheat.type = Cheat::Type::setValue;
|
||||
cheat.size = 32;
|
||||
cheat.address = codes[++i] & 0x00ffffff;
|
||||
for (int j = 0; j < count; j++)
|
||||
{
|
||||
if (j == 1)
|
||||
cheat.description += " (cont'd)";
|
||||
cheat.value = codes[++i];
|
||||
cheats.push_back(cheat);
|
||||
cheat.address += 4;
|
||||
if (j < count - 1 && i < conditionLimit)
|
||||
cheats.push_back(conditionCheat);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
{
|
||||
// 8-bit inc/decrement
|
||||
if (i + 1 >= codes.size())
|
||||
throw FlycastException("Missing value");
|
||||
cheat.type = subcode == 1 ? Cheat::Type::increase : Cheat::Type::decrease;
|
||||
cheat.size = 8;
|
||||
cheat.value = codes[i] & 0xff;
|
||||
cheat.address = codes[++i] & 0x00ffffff;
|
||||
cheats.push_back(cheat);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
{
|
||||
// 16-bit inc/decrement
|
||||
if (i + 1 >= codes.size())
|
||||
throw FlycastException("Missing value");
|
||||
cheat.type = subcode == 3 ? Cheat::Type::increase : Cheat::Type::decrease;
|
||||
cheat.size = 16;
|
||||
cheat.value = codes[i] & 0xffff;
|
||||
cheat.address = codes[++i] & 0x00ffffff;
|
||||
cheats.push_back(cheat);
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
case 6:
|
||||
{
|
||||
// 32-bit inc/decrement
|
||||
if (i + 2 >= codes.size())
|
||||
throw FlycastException("Missing address or value");
|
||||
cheat.type = subcode == 5 ? Cheat::Type::increase : Cheat::Type::decrease;
|
||||
cheat.size = 32;
|
||||
cheat.address = codes[++i] & 0x00ffffff;
|
||||
cheat.value = codes[++i];
|
||||
cheats.push_back(cheat);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw FlycastException("Unsupported cheat type");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
{
|
||||
// 32-bit repeat write
|
||||
if (i + 2 >= codes.size())
|
||||
throw FlycastException("Missing count or value");
|
||||
cheat.type = Cheat::Type::setValue;
|
||||
cheat.size = 32;
|
||||
cheat.address = codes[i] & 0x00ffffff;
|
||||
cheat.repeatCount = codes[++i] >> 16;
|
||||
cheat.repeatAddressIncrement = codes[i] & 0xffff;
|
||||
cheat.value = codes[++i];
|
||||
cheats.push_back(cheat);
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
{
|
||||
// copy bytes
|
||||
if (i + 2 >= codes.size())
|
||||
throw FlycastException("Missing count or destination address");
|
||||
cheat.type = Cheat::Type::copy;
|
||||
cheat.size = 8;
|
||||
cheat.address = codes[i] & 0x00ffffff;
|
||||
cheat.destAddress = codes[++i] & 0x00ffffff;
|
||||
cheat.repeatCount = codes[++i];
|
||||
cheats.push_back(cheat);
|
||||
}
|
||||
break;
|
||||
// TODO 7 change decryption type
|
||||
// TODO 0xb delay applying codes
|
||||
// TODO 0xc global enable test
|
||||
case 0xd:
|
||||
{
|
||||
// enable next code if eq/neq/lt/gt
|
||||
if (i + 1 >= codes.size())
|
||||
throw FlycastException("Missing count or destination address");
|
||||
cheat.size = 16;
|
||||
cheat.address = codes[i] & 0x00ffffff;
|
||||
switch (codes[++i] >> 16)
|
||||
{
|
||||
case 0:
|
||||
cheat.type = Cheat::Type::runNextIfEq;
|
||||
break;
|
||||
case 1:
|
||||
cheat.type = Cheat::Type::runNextIfNeq;
|
||||
break;
|
||||
case 2:
|
||||
cheat.type = Cheat::Type::runNextIfLt;
|
||||
break;
|
||||
case 3:
|
||||
cheat.type = Cheat::Type::runNextIfGt;
|
||||
break;
|
||||
default:
|
||||
throw FlycastException("Unsupported conditional code");
|
||||
}
|
||||
cheat.value = codes[i] & 0xffff;
|
||||
cheats.push_back(cheat);
|
||||
}
|
||||
break;
|
||||
case 0xe:
|
||||
{
|
||||
// multiline enable codes if eq/neq/lt/gt
|
||||
if (i + 1 >= codes.size())
|
||||
throw FlycastException("Missing test address");
|
||||
cheat.size = 16;
|
||||
cheat.value = codes[i] & 0xffff;
|
||||
conditionLimit = i + 1 + ((codes[i] >> 16) & 0xff);
|
||||
switch (codes[++i] >> 24)
|
||||
{
|
||||
case 0:
|
||||
cheat.type = Cheat::Type::runNextIfEq;
|
||||
break;
|
||||
case 1:
|
||||
cheat.type = Cheat::Type::runNextIfNeq;
|
||||
break;
|
||||
case 2:
|
||||
cheat.type = Cheat::Type::runNextIfLt;
|
||||
break;
|
||||
case 3:
|
||||
cheat.type = Cheat::Type::runNextIfGt;
|
||||
break;
|
||||
default:
|
||||
throw FlycastException("Unsupported conditional code");
|
||||
}
|
||||
cheat.address = codes[i] & 0x00ffffff;
|
||||
conditionCheat = cheat;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw FlycastException("Unsupported cheat type");
|
||||
}
|
||||
}
|
||||
active = !cheats.empty();
|
||||
#ifndef LIBRETRO
|
||||
std::string path = cfgLoadStr("cheats", gameId, "");
|
||||
if (path == "")
|
||||
{
|
||||
path = get_game_save_prefix() + ".cht";
|
||||
cfgSaveStr("cheats", gameId, path);
|
||||
}
|
||||
saveCheatFile(path);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CheatManager::saveCheatFile(const std::string& filename)
|
||||
{
|
||||
#ifndef LIBRETRO
|
||||
emucfg::ConfigFile cfg;
|
||||
|
||||
cfg.set_int("", "cheats", cheats.size());
|
||||
int i = 0;
|
||||
for (const Cheat& cheat : cheats)
|
||||
{
|
||||
std::string prefix = "cheat" + std::to_string(i) + "_";
|
||||
cfg.set_int("", prefix + "address", cheat.address);
|
||||
cfg.set_int("", prefix + "address_bit_position", cheat.valueMask);
|
||||
cfg.set_bool("", prefix + "big_endian", false);
|
||||
cfg.set_int("", prefix + "cheat_type", (int)cheat.type);
|
||||
cfg.set("", prefix + "code", "");
|
||||
cfg.set("", prefix + "desc", cheat.description);
|
||||
cfg.set_int("", prefix + "dest_address", cheat.destAddress);
|
||||
cfg.set_bool("", prefix + "enable", false); // force all cheats disabled at start
|
||||
cfg.set_int("", prefix + "handler", 1);
|
||||
int memSize;
|
||||
switch (cheat.size) {
|
||||
case 1:
|
||||
memSize = 0;
|
||||
break;
|
||||
case 2:
|
||||
memSize = 1;
|
||||
break;
|
||||
case 4:
|
||||
memSize = 2;
|
||||
break;
|
||||
case 8:
|
||||
memSize = 3;
|
||||
break;
|
||||
case 16:
|
||||
memSize = 4;
|
||||
break;
|
||||
case 32:
|
||||
default:
|
||||
memSize = 5;
|
||||
break;
|
||||
}
|
||||
cfg.set_int("", prefix + "memory_search_size", memSize);
|
||||
cfg.set_int("", prefix + "value", cheat.value);
|
||||
cfg.set_int("", prefix + "repeat_count", cheat.repeatCount);
|
||||
cfg.set_int("", prefix + "repeat_add_to_value", cheat.repeatValueIncrement);
|
||||
cfg.set_int("", prefix + "repeat_add_to_address", cheat.repeatAddressIncrement);
|
||||
i++;
|
||||
}
|
||||
FILE *fp = nowide::fopen(filename.c_str(), "w");
|
||||
if (fp == nullptr)
|
||||
throw FlycastException("Can't save cheat file");
|
||||
cfg.save(fp);
|
||||
fclose(fp);
|
||||
#endif
|
||||
}
|
||||
+10
-1
@@ -39,7 +39,8 @@ struct Cheat
|
||||
runNextIfEq,
|
||||
runNextIfNeq,
|
||||
runNextIfGt,
|
||||
runNextIfLt
|
||||
runNextIfLt,
|
||||
copy
|
||||
};
|
||||
Type type = Type::disabled;
|
||||
std::string description;
|
||||
@@ -47,9 +48,11 @@ struct Cheat
|
||||
u32 size = 0;
|
||||
u32 address = 0;
|
||||
u32 value = 0;
|
||||
u8 valueMask = 0;
|
||||
u32 repeatCount = 1;
|
||||
u32 repeatValueIncrement = 0;
|
||||
u32 repeatAddressIncrement = 0;
|
||||
u32 destAddress = 0;
|
||||
};
|
||||
|
||||
class CheatManager
|
||||
@@ -62,8 +65,10 @@ public:
|
||||
bool cheatEnabled(size_t index) const { return cheats[index].enabled; }
|
||||
void enableCheat(size_t index, bool enabled) { cheats[index].enabled = enabled; }
|
||||
void loadCheatFile(const std::string& filename);
|
||||
void saveCheatFile(const std::string& filename);
|
||||
// Returns true if using 16:9 anamorphic screen ratio
|
||||
bool isWidescreen() const { return widescreen_cheat != nullptr; }
|
||||
void addGameSharkCheat(const std::string& name, const std::string& s);
|
||||
|
||||
private:
|
||||
u32 readRam(u32 addr, u32 bits);
|
||||
@@ -75,6 +80,10 @@ private:
|
||||
bool active = false;
|
||||
std::vector<Cheat> cheats;
|
||||
std::string gameId;
|
||||
|
||||
friend class CheatManagerTest_TestLoad_Test;
|
||||
friend class CheatManagerTest_TestGameShark_Test;
|
||||
friend class CheatManagerTest_TestSave_Test;
|
||||
};
|
||||
|
||||
extern CheatManager cheatManager;
|
||||
-261
@@ -1,261 +0,0 @@
|
||||
RZDCY_FILES :=
|
||||
|
||||
RZDCY_SRC_DIR ?= $(call my-dir)
|
||||
VERSION_HEADER := $(RZDCY_SRC_DIR)/version.h
|
||||
|
||||
RZDCY_MODULES := cfg/ hw/arm7/ hw/aica/ hw/holly/ hw/ hw/gdrom/ hw/maple/ \
|
||||
hw/mem/ hw/pvr/ hw/sh4/ hw/sh4/interpr/ hw/sh4/modules/ profiler/ oslib/ \
|
||||
hw/naomi/ imgread/ ./ deps/libchdr/src/ deps/libchdr/deps/zlib-1.2.11/ \
|
||||
deps/libelf/ deps/chdpsr/ rend/ reios/ deps/xbrz/ \
|
||||
deps/imgui/ archive/ input/ log/ wsi/ network/ hw/bba/ debug/ \
|
||||
hw/modem/ deps/picotcp/modules/ deps/picotcp/stack/
|
||||
|
||||
ifndef NO_REC
|
||||
ifndef NOT_ARM
|
||||
RZDCY_MODULES += rec-ARM/ deps/vixl/ deps/vixl/aarch32/
|
||||
endif
|
||||
|
||||
ifdef X86_REC
|
||||
RZDCY_MODULES += rec-x86/
|
||||
endif
|
||||
|
||||
ifdef X64_REC
|
||||
RZDCY_MODULES += rec-x64/
|
||||
endif
|
||||
|
||||
ifdef CPP_REC
|
||||
RZDCY_MODULES += rec-cpp/
|
||||
endif
|
||||
|
||||
ifdef ARM64_REC
|
||||
RZDCY_MODULES += rec-ARM64/ deps/vixl/ deps/vixl/aarch64/
|
||||
endif
|
||||
endif
|
||||
|
||||
ifndef NO_REND
|
||||
RZDCY_MODULES += rend/gles/
|
||||
ifndef USE_GLES
|
||||
ifndef USE_DISPMANX
|
||||
RZDCY_MODULES += rend/gl4/
|
||||
endif
|
||||
endif
|
||||
ifdef USE_VULKAN
|
||||
RZDCY_MODULES += rend/vulkan/ rend/vulkan/oit/ deps/volk/ \
|
||||
deps/glslang/glslang/MachineIndependent/ \
|
||||
deps/glslang/glslang/MachineIndependent/preprocessor/ \
|
||||
deps/glslang/glslang/GenericCodeGen/ \
|
||||
deps/glslang/OGLCompilersDLL/ \
|
||||
deps/glslang/SPIRV/
|
||||
ifdef FOR_WINDOWS
|
||||
RZDCY_FILES += $(RZDCY_SRC_DIR)/deps/glslang/glslang/OSDependent/Windows/ossource.cpp
|
||||
else
|
||||
RZDCY_FILES += $(RZDCY_SRC_DIR)/deps/glslang/glslang/OSDependent/Unix/ossource.cpp
|
||||
endif
|
||||
endif
|
||||
else
|
||||
RZDCY_MODULES += rend/norend/
|
||||
endif
|
||||
|
||||
ifdef USE_SDL
|
||||
RZDCY_MODULES += sdl/
|
||||
endif
|
||||
|
||||
ifdef FOR_LINUX
|
||||
ifndef UNIT_TESTS
|
||||
RZDCY_MODULES += linux-dist/
|
||||
endif
|
||||
RZDCY_MODULES += linux/
|
||||
endif
|
||||
|
||||
ifdef FOR_WINDOWS
|
||||
RZDCY_MODULES += rend/dx9/
|
||||
ifndef UNIT_TESTS
|
||||
RZDCY_FILES += $(RZDCY_SRC_DIR)/windows/winmain.cpp
|
||||
endif
|
||||
RZDCY_FILES += $(RZDCY_SRC_DIR)/windows/win_vmem.cpp $(RZDCY_SRC_DIR)/windows/rawinput.cpp
|
||||
RZDCY_CFLAGS += -I$(RZDCY_SRC_DIR)/deps/dirent
|
||||
endif
|
||||
|
||||
ifdef USE_VULKAN
|
||||
ifdef FOR_WINDOWS
|
||||
RZDCY_CFLAGS += -DVK_USE_PLATFORM_WIN32_KHR
|
||||
else
|
||||
RZDCY_CFLAGS += -DVK_USE_PLATFORM_XLIB_KHR
|
||||
endif
|
||||
RZDCY_CFLAGS += -D USE_VULKAN
|
||||
endif
|
||||
|
||||
RZDCY_CFLAGS += -I$(RZDCY_SRC_DIR) -I$(RZDCY_SRC_DIR)/rend/gles -I$(RZDCY_SRC_DIR)/deps \
|
||||
-I$(RZDCY_SRC_DIR)/deps/vixl -I$(RZDCY_SRC_DIR)/khronos -I$(RZDCY_SRC_DIR)/deps/glslang \
|
||||
-I$(RZDCY_SRC_DIR)/deps/glm -I$(RZDCY_SRC_DIR)/deps/xbyak -I$(RZDCY_SRC_DIR)/deps/nowide/include \
|
||||
-I$(RZDCY_SRC_DIR)/deps/picotcp/include -I$(RZDCY_SRC_DIR)/deps/picotcp/modules \
|
||||
-I$(RZDCY_SRC_DIR)/deps/libchdr/include -I$(RZDCY_SRC_DIR)/deps/libchdr/deps/zlib-1.2.11/ \
|
||||
-I$(RZDCY_SRC_DIR)/deps/libchdr/deps/lzma-19.00 -I$(RZDCY_SRC_DIR)/deps/libchdr/deps/lzma-19.00/include
|
||||
|
||||
ifdef USE_SYSTEM_MINIUPNPC
|
||||
RZDCY_CFLAGS += -I/usr/include/miniupnpc
|
||||
else
|
||||
RZDCY_CFLAGS += -I$(RZDCY_SRC_DIR)/deps/miniupnpc
|
||||
endif
|
||||
|
||||
ifdef NO_REC
|
||||
RZDCY_CFLAGS += -DTARGET_NO_REC
|
||||
else
|
||||
RZDCY_MODULES += hw/sh4/dyna/
|
||||
endif
|
||||
|
||||
ifdef USE_GLES
|
||||
RZDCY_CFLAGS += -DGLES -fPIC
|
||||
endif
|
||||
|
||||
ifdef CHD5_FLAC
|
||||
RZDCY_CFLAGS += -DCHD5_FLAC -I$(RZDCY_SRC_DIR)/deps/flac/src/libFLAC/include/ -I$(RZDCY_SRC_DIR)/deps/flac/include
|
||||
RZDCY_CFLAGS += -DHAVE_CONFIG_H
|
||||
RZDCY_MODULES += deps/flac/src/libFLAC/
|
||||
endif
|
||||
|
||||
# 7-Zip/LZMA settings (CHDv5)
|
||||
ifdef CHD5_LZMA
|
||||
RZDCY_MODULES += deps/lzma/
|
||||
RZDCY_CFLAGS += -D_7ZIP_ST -DCHD5_LZMA
|
||||
endif
|
||||
|
||||
RZDCY_CFLAGS += -DXXH_INLINE_ALL -I$(RZDCY_SRC_DIR)/deps/xxHash -I$(RZDCY_SRC_DIR)/deps/stb
|
||||
|
||||
RZDCY_FILES += $(foreach dir,$(addprefix $(RZDCY_SRC_DIR)/,$(RZDCY_MODULES)),$(wildcard $(dir)*.cpp))
|
||||
RZDCY_FILES += $(foreach dir,$(addprefix $(RZDCY_SRC_DIR)/,$(RZDCY_MODULES)),$(wildcard $(dir)*.cc))
|
||||
RZDCY_FILES += $(foreach dir,$(addprefix $(RZDCY_SRC_DIR)/,$(RZDCY_MODULES)),$(wildcard $(dir)*.c))
|
||||
RZDCY_FILES += $(foreach dir,$(addprefix $(RZDCY_SRC_DIR)/,$(RZDCY_MODULES)),$(wildcard $(dir)*.S))
|
||||
|
||||
ifdef STATIC_LIBZIP
|
||||
RZDCY_CFLAGS += -I$(RZDCY_SRC_DIR)/deps/libzip/lib
|
||||
LIBZIP_DIR = $(RZDCY_SRC_DIR)/deps/libzip/lib
|
||||
RZDCY_FILES += $(LIBZIP_DIR)/zip_add.c \
|
||||
$(LIBZIP_DIR)/zip_add_dir.c \
|
||||
$(LIBZIP_DIR)/zip_add_entry.c \
|
||||
$(LIBZIP_DIR)/zip_algorithm_deflate.c \
|
||||
$(LIBZIP_DIR)/zip_buffer.c \
|
||||
$(LIBZIP_DIR)/zip_close.c \
|
||||
$(LIBZIP_DIR)/zip_delete.c \
|
||||
$(LIBZIP_DIR)/zip_dir_add.c \
|
||||
$(LIBZIP_DIR)/zip_dirent.c \
|
||||
$(LIBZIP_DIR)/zip_discard.c \
|
||||
$(LIBZIP_DIR)/zip_entry.c \
|
||||
$(LIBZIP_DIR)/zip_error.c \
|
||||
$(LIBZIP_DIR)/zip_error_clear.c \
|
||||
$(LIBZIP_DIR)/zip_error_get.c \
|
||||
$(LIBZIP_DIR)/zip_error_get_sys_type.c \
|
||||
$(LIBZIP_DIR)/zip_error_strerror.c \
|
||||
$(LIBZIP_DIR)/zip_error_to_str.c \
|
||||
$(LIBZIP_DIR)/zip_extra_field.c \
|
||||
$(LIBZIP_DIR)/zip_extra_field_api.c \
|
||||
$(LIBZIP_DIR)/zip_fclose.c \
|
||||
$(LIBZIP_DIR)/zip_fdopen.c \
|
||||
$(LIBZIP_DIR)/zip_file_add.c \
|
||||
$(LIBZIP_DIR)/zip_file_error_clear.c \
|
||||
$(LIBZIP_DIR)/zip_file_error_get.c \
|
||||
$(LIBZIP_DIR)/zip_file_get_comment.c \
|
||||
$(LIBZIP_DIR)/zip_file_get_external_attributes.c \
|
||||
$(LIBZIP_DIR)/zip_file_get_offset.c \
|
||||
$(LIBZIP_DIR)/zip_file_rename.c \
|
||||
$(LIBZIP_DIR)/zip_file_replace.c \
|
||||
$(LIBZIP_DIR)/zip_file_set_comment.c \
|
||||
$(LIBZIP_DIR)/zip_file_set_encryption.c \
|
||||
$(LIBZIP_DIR)/zip_file_set_external_attributes.c \
|
||||
$(LIBZIP_DIR)/zip_file_set_mtime.c \
|
||||
$(LIBZIP_DIR)/zip_file_strerror.c \
|
||||
$(LIBZIP_DIR)/zip_fopen.c \
|
||||
$(LIBZIP_DIR)/zip_fopen_encrypted.c \
|
||||
$(LIBZIP_DIR)/zip_fopen_index.c \
|
||||
$(LIBZIP_DIR)/zip_fopen_index_encrypted.c \
|
||||
$(LIBZIP_DIR)/zip_fread.c \
|
||||
$(LIBZIP_DIR)/zip_fseek.c \
|
||||
$(LIBZIP_DIR)/zip_ftell.c \
|
||||
$(LIBZIP_DIR)/zip_get_archive_comment.c \
|
||||
$(LIBZIP_DIR)/zip_get_archive_flag.c \
|
||||
$(LIBZIP_DIR)/zip_get_encryption_implementation.c \
|
||||
$(LIBZIP_DIR)/zip_get_file_comment.c \
|
||||
$(LIBZIP_DIR)/zip_get_name.c \
|
||||
$(LIBZIP_DIR)/zip_get_num_entries.c \
|
||||
$(LIBZIP_DIR)/zip_get_num_files.c \
|
||||
$(LIBZIP_DIR)/zip_hash.c \
|
||||
$(LIBZIP_DIR)/zip_io_util.c \
|
||||
$(LIBZIP_DIR)/zip_libzip_version.c \
|
||||
$(LIBZIP_DIR)/zip_memdup.c \
|
||||
$(LIBZIP_DIR)/zip_name_locate.c \
|
||||
$(LIBZIP_DIR)/zip_new.c \
|
||||
$(LIBZIP_DIR)/zip_open.c \
|
||||
$(LIBZIP_DIR)/zip_pkware.c \
|
||||
$(LIBZIP_DIR)/zip_progress.c \
|
||||
$(LIBZIP_DIR)/zip_rename.c \
|
||||
$(LIBZIP_DIR)/zip_replace.c \
|
||||
$(LIBZIP_DIR)/zip_set_archive_comment.c \
|
||||
$(LIBZIP_DIR)/zip_set_archive_flag.c \
|
||||
$(LIBZIP_DIR)/zip_set_default_password.c \
|
||||
$(LIBZIP_DIR)/zip_set_file_comment.c \
|
||||
$(LIBZIP_DIR)/zip_set_file_compression.c \
|
||||
$(LIBZIP_DIR)/zip_set_name.c \
|
||||
$(LIBZIP_DIR)/zip_source_accept_empty.c \
|
||||
$(LIBZIP_DIR)/zip_source_begin_write.c \
|
||||
$(LIBZIP_DIR)/zip_source_begin_write_cloning.c \
|
||||
$(LIBZIP_DIR)/zip_source_buffer.c \
|
||||
$(LIBZIP_DIR)/zip_source_call.c \
|
||||
$(LIBZIP_DIR)/zip_source_close.c \
|
||||
$(LIBZIP_DIR)/zip_source_commit_write.c \
|
||||
$(LIBZIP_DIR)/zip_source_compress.c \
|
||||
$(LIBZIP_DIR)/zip_source_crc.c \
|
||||
$(LIBZIP_DIR)/zip_source_error.c \
|
||||
$(LIBZIP_DIR)/zip_source_file_common.c \
|
||||
$(LIBZIP_DIR)/zip_source_file_stdio.c \
|
||||
$(LIBZIP_DIR)/zip_source_free.c \
|
||||
$(LIBZIP_DIR)/zip_source_function.c \
|
||||
$(LIBZIP_DIR)/zip_source_get_file_attributes.c \
|
||||
$(LIBZIP_DIR)/zip_source_is_deleted.c \
|
||||
$(LIBZIP_DIR)/zip_source_layered.c \
|
||||
$(LIBZIP_DIR)/zip_source_open.c \
|
||||
$(LIBZIP_DIR)/zip_source_pkware_decode.c \
|
||||
$(LIBZIP_DIR)/zip_source_pkware_encode.c \
|
||||
$(LIBZIP_DIR)/zip_source_read.c \
|
||||
$(LIBZIP_DIR)/zip_source_remove.c \
|
||||
$(LIBZIP_DIR)/zip_source_rollback_write.c \
|
||||
$(LIBZIP_DIR)/zip_source_seek.c \
|
||||
$(LIBZIP_DIR)/zip_source_seek_write.c \
|
||||
$(LIBZIP_DIR)/zip_source_stat.c \
|
||||
$(LIBZIP_DIR)/zip_source_supports.c \
|
||||
$(LIBZIP_DIR)/zip_source_tell.c \
|
||||
$(LIBZIP_DIR)/zip_source_tell_write.c \
|
||||
$(LIBZIP_DIR)/zip_source_window.c \
|
||||
$(LIBZIP_DIR)/zip_source_write.c \
|
||||
$(LIBZIP_DIR)/zip_source_zip.c \
|
||||
$(LIBZIP_DIR)/zip_source_zip_new.c \
|
||||
$(LIBZIP_DIR)/zip_stat.c \
|
||||
$(LIBZIP_DIR)/zip_stat_index.c \
|
||||
$(LIBZIP_DIR)/zip_stat_init.c \
|
||||
$(LIBZIP_DIR)/zip_strerror.c \
|
||||
$(LIBZIP_DIR)/zip_string.c \
|
||||
$(LIBZIP_DIR)/zip_unchange.c \
|
||||
$(LIBZIP_DIR)/zip_unchange_all.c \
|
||||
$(LIBZIP_DIR)/zip_unchange_archive.c \
|
||||
$(LIBZIP_DIR)/zip_unchange_data.c \
|
||||
$(LIBZIP_DIR)/zip_utf-8.c \
|
||||
$(LIBZIP_DIR)/zip_err_str.c
|
||||
|
||||
ifdef FOR_WINDOWS
|
||||
RZDCY_FILES += $(LIBZIP_DIR)/zip_source_file_win32.c \
|
||||
$(LIBZIP_DIR)/zip_source_file_win32_named.c \
|
||||
$(LIBZIP_DIR)/zip_source_file_win32_utf16.c \
|
||||
$(LIBZIP_DIR)/zip_source_file_win32_utf8.c \
|
||||
$(LIBZIP_DIR)/zip_source_file_win32_ansi.c \
|
||||
$(LIBZIP_DIR)/zip_random_win32.c
|
||||
else
|
||||
RZDCY_FILES += $(LIBZIP_DIR)/zip_mkstempm.c \
|
||||
$(LIBZIP_DIR)/zip_source_file_stdio_named.c \
|
||||
$(LIBZIP_DIR)/zip_random_unix.c
|
||||
endif
|
||||
endif
|
||||
|
||||
$(VERSION_HEADER):
|
||||
echo "#define GIT_VERSION \"`git describe --tags --always`\"" > $(VERSION_HEADER)
|
||||
echo "#define GIT_HASH \"`git rev-parse --short HEAD`\"" >> $(VERSION_HEADER)
|
||||
echo "#define BUILD_DATE \"`date '+%Y-%m-%d %H:%M:%S %Z'`\"" >> $(VERSION_HEADER)
|
||||
|
||||
@@ -77,14 +77,14 @@ public:
|
||||
{
|
||||
if (pc != 1)
|
||||
Sh4cntx.pc = pc;
|
||||
dc_resume();
|
||||
emu.start();
|
||||
}
|
||||
|
||||
void step()
|
||||
{
|
||||
bool restoreBreakpoint = removeMatchpoint(0, Sh4cntx.pc, 2);
|
||||
u32 savedPc = Sh4cntx.pc;
|
||||
dc_step();
|
||||
emu.step();
|
||||
if (restoreBreakpoint)
|
||||
insertMatchpoint(0, savedPc, 2);
|
||||
}
|
||||
@@ -222,7 +222,7 @@ public:
|
||||
{
|
||||
config::DynarecEnabled = false;
|
||||
exception = SIGINT;
|
||||
dc_stop();
|
||||
emu.stop();
|
||||
return exception;
|
||||
}
|
||||
|
||||
@@ -236,7 +236,7 @@ public:
|
||||
void postDebugTrap()
|
||||
{
|
||||
// needed to join the emu thread since debugTrap() is called by it
|
||||
dc_stop();
|
||||
emu.stop();
|
||||
}
|
||||
|
||||
u32 currentException()
|
||||
@@ -246,14 +246,14 @@ public:
|
||||
|
||||
void restart()
|
||||
{
|
||||
dc_stop();
|
||||
dc_reset(true);
|
||||
dc_resume();
|
||||
emu.unloadGame();
|
||||
emu.loadGame(settings.content.path);
|
||||
emu.start();
|
||||
}
|
||||
|
||||
void detach()
|
||||
{
|
||||
dc_resume();
|
||||
emu.start();
|
||||
}
|
||||
|
||||
void kill()
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
namespace debugger {
|
||||
|
||||
static void emuEventCallback(Event event);
|
||||
static void emuEventCallback(Event event, void *);
|
||||
|
||||
class GdbServer
|
||||
{
|
||||
@@ -73,6 +73,8 @@ public:
|
||||
|
||||
void term()
|
||||
{
|
||||
EventManager::unlisten(Event::Resume, emuEventCallback);
|
||||
EventManager::unlisten(Event::Terminate, emuEventCallback);
|
||||
stop();
|
||||
if (VALID(clientSocket))
|
||||
{
|
||||
@@ -863,7 +865,7 @@ void subroutineReturn()
|
||||
gdbServer.agent.subroutineReturn();
|
||||
}
|
||||
|
||||
static void emuEventCallback(Event event)
|
||||
static void emuEventCallback(Event event, void *)
|
||||
{
|
||||
switch (event)
|
||||
{
|
||||
|
||||
+1
-1
Submodule core/deps/SDL updated: 178ae70a29...b424665e08.
Submodule
+1
Submodule core/deps/breakpad added at d2657e1267.
@@ -29,6 +29,10 @@
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
|
||||
#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PC_APP || WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
|
||||
#define FindFirstFileExW FindFirstFileExFromAppW
|
||||
#endif
|
||||
|
||||
/* Indicates that d_type field is available in dirent structure */
|
||||
#define _DIRENT_HAVE_D_TYPE
|
||||
|
||||
@@ -613,7 +617,7 @@ dirent_first(
|
||||
/* Failed to re-open directory: no directory entry in memory */
|
||||
dirp->cached = 0;
|
||||
datap = NULL;
|
||||
|
||||
dirent_set_errno(GetLastError()); /* Not a valid errno but better than nothing */
|
||||
}
|
||||
return datap;
|
||||
}
|
||||
@@ -647,6 +651,8 @@ dirent_next(
|
||||
FindClose (dirp->handle);
|
||||
dirp->handle = INVALID_HANDLE_VALUE;
|
||||
p = NULL;
|
||||
if (GetLastError() != ERROR_NO_MORE_FILES)
|
||||
dirent_set_errno(GetLastError());
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
@@ -0,0 +1,618 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
* GGPO.net (http://ggpo.net) - Copyright 2009 GroundStorm Studios, LLC.
|
||||
*
|
||||
* Use of this software is governed by the MIT license that can be found
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef _GGPONET_H_
|
||||
#define _GGPONET_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
// On windows, export at build time and import at runtime.
|
||||
// ELF systems don't need an explicit export/import.
|
||||
#ifdef _WIN32
|
||||
# if defined(GGPO_SHARED_LIB)
|
||||
# ifdef GGPO_SDK_EXPORT
|
||||
# define GGPO_API __declspec(dllexport)
|
||||
# else
|
||||
# define GGPO_API __declspec(dllimport)
|
||||
# endif
|
||||
# else
|
||||
# define GGPO_API
|
||||
# endif
|
||||
#else
|
||||
# define GGPO_API
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
#if defined(_WIN32) && !defined(_WIN64)
|
||||
#define __cdecl __attribute__((cdecl))
|
||||
#elif !defined(__cdecl)
|
||||
#define __cdecl
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define GGPO_MAX_PLAYERS 4
|
||||
#define GGPO_MAX_PREDICTION_FRAMES 8
|
||||
#define GGPO_MAX_SPECTATORS 32
|
||||
|
||||
#define GGPO_SPECTATOR_INPUT_INTERVAL 4
|
||||
|
||||
typedef struct GGPOSession GGPOSession;
|
||||
|
||||
typedef int GGPOPlayerHandle;
|
||||
|
||||
typedef enum {
|
||||
GGPO_PLAYERTYPE_LOCAL,
|
||||
GGPO_PLAYERTYPE_REMOTE,
|
||||
GGPO_PLAYERTYPE_SPECTATOR,
|
||||
} GGPOPlayerType;
|
||||
|
||||
/*
|
||||
* The GGPOPlayer structure used to describe players in ggpo_add_player
|
||||
*
|
||||
* size: Should be set to the sizeof(GGPOPlayer)
|
||||
*
|
||||
* type: One of the GGPOPlayerType values describing how inputs should be handled
|
||||
* Local players must have their inputs updated every frame via
|
||||
* ggpo_add_local_inputs. Remote players values will come over the
|
||||
* network.
|
||||
*
|
||||
* player_num: The player number. Should be between 1 and the number of players
|
||||
* In the game (e.g. in a 2 player game, either 1 or 2).
|
||||
*
|
||||
* If type == GGPO_PLAYERTYPE_REMOTE:
|
||||
*
|
||||
* u.remote.ip_address: The ip address of the ggpo session which will host this
|
||||
* player.
|
||||
*
|
||||
* u.remote.port: The port where udp packets should be sent to reach this player.
|
||||
* All the local inputs for this session will be sent to this player at
|
||||
* ip_address:port.
|
||||
*
|
||||
*/
|
||||
|
||||
typedef struct GGPOPlayer {
|
||||
int size;
|
||||
GGPOPlayerType type;
|
||||
int player_num;
|
||||
union {
|
||||
struct {
|
||||
bool _unused;
|
||||
} local;
|
||||
struct {
|
||||
char ip_address[32];
|
||||
unsigned short port;
|
||||
} remote;
|
||||
} u;
|
||||
} GGPOPlayer;
|
||||
|
||||
typedef struct GGPOLocalEndpoint {
|
||||
int player_num;
|
||||
} GGPOLocalEndpoint;
|
||||
|
||||
|
||||
#define GGPO_ERRORLIST \
|
||||
GGPO_ERRORLIST_ENTRY(GGPO_OK, 0) \
|
||||
GGPO_ERRORLIST_ENTRY(GGPO_ERRORCODE_SUCCESS, 0) \
|
||||
GGPO_ERRORLIST_ENTRY(GGPO_ERRORCODE_GENERAL_FAILURE, -1) \
|
||||
GGPO_ERRORLIST_ENTRY(GGPO_ERRORCODE_INVALID_SESSION, 1) \
|
||||
GGPO_ERRORLIST_ENTRY(GGPO_ERRORCODE_INVALID_PLAYER_HANDLE, 2) \
|
||||
GGPO_ERRORLIST_ENTRY(GGPO_ERRORCODE_PLAYER_OUT_OF_RANGE, 3) \
|
||||
GGPO_ERRORLIST_ENTRY(GGPO_ERRORCODE_PREDICTION_THRESHOLD, 4) \
|
||||
GGPO_ERRORLIST_ENTRY(GGPO_ERRORCODE_UNSUPPORTED, 5) \
|
||||
GGPO_ERRORLIST_ENTRY(GGPO_ERRORCODE_NOT_SYNCHRONIZED, 6) \
|
||||
GGPO_ERRORLIST_ENTRY(GGPO_ERRORCODE_IN_ROLLBACK, 7) \
|
||||
GGPO_ERRORLIST_ENTRY(GGPO_ERRORCODE_INPUT_DROPPED, 8) \
|
||||
GGPO_ERRORLIST_ENTRY(GGPO_ERRORCODE_PLAYER_DISCONNECTED, 9) \
|
||||
GGPO_ERRORLIST_ENTRY(GGPO_ERRORCODE_TOO_MANY_SPECTATORS, 10) \
|
||||
GGPO_ERRORLIST_ENTRY(GGPO_ERRORCODE_INVALID_REQUEST, 11) \
|
||||
GGPO_ERRORLIST_ENTRY(GGPO_ERRORCODE_INPUT_SIZE_DIFF, 12) \
|
||||
GGPO_ERRORLIST_ENTRY(GGPO_ERRORCODE_NETWORK_ERROR, 13) \
|
||||
GGPO_ERRORLIST_ENTRY(GGPO_ERRORCODE_VERIFICATION_ERROR, 14)
|
||||
|
||||
#define GGPO_ERRORLIST_ENTRY(name, value) name = value,
|
||||
typedef enum {
|
||||
GGPO_ERRORLIST
|
||||
} GGPOErrorCode;
|
||||
#undef GGPO_ERRORLIST_ENTRY
|
||||
|
||||
#define GGPO_SUCCEEDED(result) ((result) == GGPO_ERRORCODE_SUCCESS)
|
||||
|
||||
|
||||
#define GGPO_INVALID_HANDLE (-1)
|
||||
|
||||
|
||||
/*
|
||||
* The GGPOEventCode enumeration describes what type of event just happened.
|
||||
*
|
||||
* GGPO_EVENTCODE_CONNECTED_TO_PEER - Handshake with the game running on the
|
||||
* other side of the network has been completed.
|
||||
*
|
||||
* GGPO_EVENTCODE_SYNCHRONIZING_WITH_PEER - Beginning the synchronization
|
||||
* process with the client on the other end of the networking. The count
|
||||
* and total fields in the u.synchronizing struct of the GGPOEvent
|
||||
* object indicate progress.
|
||||
*
|
||||
* GGPO_EVENTCODE_SYNCHRONIZED_WITH_PEER - The synchronziation with this
|
||||
* peer has finished.
|
||||
*
|
||||
* GGPO_EVENTCODE_RUNNING - All the clients have synchronized. You may begin
|
||||
* sending inputs with ggpo_synchronize_inputs.
|
||||
*
|
||||
* GGPO_EVENTCODE_DISCONNECTED_FROM_PEER - The network connection on
|
||||
* the other end of the network has closed.
|
||||
*
|
||||
* GGPO_EVENTCODE_TIMESYNC - The time synchronziation code has determined
|
||||
* that this client is too far ahead of the other one and should slow
|
||||
* down to ensure fairness. The u.timesync.frames_ahead parameter in
|
||||
* the GGPOEvent object indicates how many frames the client is.
|
||||
*
|
||||
*/
|
||||
typedef enum {
|
||||
GGPO_EVENTCODE_CONNECTED_TO_PEER = 1000,
|
||||
GGPO_EVENTCODE_SYNCHRONIZING_WITH_PEER = 1001,
|
||||
GGPO_EVENTCODE_SYNCHRONIZED_WITH_PEER = 1002,
|
||||
GGPO_EVENTCODE_RUNNING = 1003,
|
||||
GGPO_EVENTCODE_DISCONNECTED_FROM_PEER = 1004,
|
||||
GGPO_EVENTCODE_TIMESYNC = 1005,
|
||||
GGPO_EVENTCODE_CONNECTION_INTERRUPTED = 1006,
|
||||
GGPO_EVENTCODE_CONNECTION_RESUMED = 1007,
|
||||
} GGPOEventCode;
|
||||
|
||||
/*
|
||||
* The GGPOEvent structure contains an asynchronous event notification sent
|
||||
* by the on_event callback. See GGPOEventCode, above, for a detailed
|
||||
* explanation of each event.
|
||||
*/
|
||||
typedef struct {
|
||||
GGPOEventCode code;
|
||||
union {
|
||||
struct {
|
||||
GGPOPlayerHandle player;
|
||||
} connected;
|
||||
struct {
|
||||
GGPOPlayerHandle player;
|
||||
int count;
|
||||
int total;
|
||||
} synchronizing;
|
||||
struct {
|
||||
GGPOPlayerHandle player;
|
||||
} synchronized;
|
||||
struct {
|
||||
GGPOPlayerHandle player;
|
||||
} disconnected;
|
||||
struct {
|
||||
int frames_ahead;
|
||||
} timesync;
|
||||
struct {
|
||||
GGPOPlayerHandle player;
|
||||
int disconnect_timeout;
|
||||
} connection_interrupted;
|
||||
struct {
|
||||
GGPOPlayerHandle player;
|
||||
} connection_resumed;
|
||||
} u;
|
||||
} GGPOEvent;
|
||||
|
||||
/*
|
||||
* The GGPOSessionCallbacks structure contains the callback functions that
|
||||
* your application must implement. GGPO.net will periodically call these
|
||||
* functions during the game. All callback functions must be implemented.
|
||||
*/
|
||||
typedef struct {
|
||||
/*
|
||||
* begin_game callback - This callback has been deprecated. You must
|
||||
* implement it, but should ignore the 'game' parameter.
|
||||
*/
|
||||
bool (__cdecl *begin_game)(const char *game);
|
||||
|
||||
/*
|
||||
* save_game_state - The client should allocate a buffer, copy the
|
||||
* entire contents of the current game state into it, and copy the
|
||||
* length into the *len parameter. Optionally, the client can compute
|
||||
* a checksum of the data and store it in the *checksum argument.
|
||||
*/
|
||||
bool (__cdecl *save_game_state)(unsigned char **buffer, int *len, int *checksum, int frame);
|
||||
|
||||
/*
|
||||
* load_game_state - GGPO.net will call this function at the beginning
|
||||
* of a rollback. The buffer and len parameters contain a previously
|
||||
* saved state returned from the save_game_state function. The client
|
||||
* should make the current game state match the state contained in the
|
||||
* buffer.
|
||||
*/
|
||||
bool (__cdecl *load_game_state)(unsigned char *buffer, int len);
|
||||
|
||||
/*
|
||||
* log_game_state - Used in diagnostic testing. The client should use
|
||||
* the ggpo_log function to write the contents of the specified save
|
||||
* state in a human readible form.
|
||||
*/
|
||||
bool (__cdecl *log_game_state)(char *filename, unsigned char *buffer, int len);
|
||||
|
||||
/*
|
||||
* free_buffer - Frees a game state allocated in save_game_state. You
|
||||
* should deallocate the memory contained in the buffer.
|
||||
*/
|
||||
void (__cdecl *free_buffer)(void *buffer);
|
||||
|
||||
/*
|
||||
* advance_frame - Called during a rollback. You should advance your game
|
||||
* state by exactly one frame. Before each frame, call ggpo_synchronize_input
|
||||
* to retrieve the inputs you should use for that frame. After each frame,
|
||||
* you should call ggpo_advance_frame to notify GGPO.net that you're
|
||||
* finished.
|
||||
*
|
||||
* The flags parameter is reserved. It can safely be ignored at this time.
|
||||
*/
|
||||
bool (__cdecl *advance_frame)(int flags);
|
||||
|
||||
/*
|
||||
* on_event - Notification that something has happened. See the GGPOEventCode
|
||||
* structure above for more information.
|
||||
*/
|
||||
bool (__cdecl *on_event)(GGPOEvent *info);
|
||||
|
||||
/*
|
||||
* on_message - Delivers an application message. Allows arbitrary data to be
|
||||
* exchanged with peers. This callback is optional.
|
||||
*/
|
||||
void (__cdecl *on_message)(unsigned char *msg, int len);
|
||||
} GGPOSessionCallbacks;
|
||||
|
||||
/*
|
||||
* The GGPONetworkStats function contains some statistics about the current
|
||||
* session.
|
||||
*
|
||||
* network.send_queue_len - The length of the queue containing UDP packets
|
||||
* which have not yet been acknowledged by the end client. The length of
|
||||
* the send queue is a rough indication of the quality of the connection.
|
||||
* The longer the send queue, the higher the round-trip time between the
|
||||
* clients. The send queue will also be longer than usual during high
|
||||
* packet loss situations.
|
||||
*
|
||||
* network.recv_queue_len - The number of inputs currently buffered by the
|
||||
* GGPO.net network layer which have yet to be validated. The length of
|
||||
* the prediction queue is roughly equal to the current frame number
|
||||
* minus the frame number of the last packet in the remote queue.
|
||||
*
|
||||
* network.ping - The roundtrip packet transmission time as calcuated
|
||||
* by GGPO.net. This will be roughly equal to the actual round trip
|
||||
* packet transmission time + 2 the interval at which you call ggpo_idle
|
||||
* or ggpo_advance_frame.
|
||||
*
|
||||
* network.kbps_sent - The estimated bandwidth used between the two
|
||||
* clients, in kilobits per second.
|
||||
*
|
||||
* timesync.local_frames_behind - The number of frames GGPO.net calculates
|
||||
* that the local client is behind the remote client at this instant in
|
||||
* time. For example, if at this instant the current game client is running
|
||||
* frame 1002 and the remote game client is running frame 1009, this value
|
||||
* will mostly likely roughly equal 7.
|
||||
*
|
||||
* timesync.remote_frames_behind - The same as local_frames_behind, but
|
||||
* calculated from the perspective of the remote player.
|
||||
*
|
||||
*/
|
||||
typedef struct GGPONetworkStats {
|
||||
struct {
|
||||
int send_queue_len;
|
||||
int recv_queue_len;
|
||||
int ping;
|
||||
int kbps_sent;
|
||||
} network;
|
||||
struct {
|
||||
int local_frames_behind;
|
||||
int remote_frames_behind;
|
||||
} timesync;
|
||||
struct {
|
||||
int predicted_frames;
|
||||
} sync;
|
||||
} GGPONetworkStats;
|
||||
|
||||
/*
|
||||
* ggpo_start_session --
|
||||
*
|
||||
* Used to being a new GGPO.net session. The ggpo object returned by ggpo_start_session
|
||||
* uniquely identifies the state for this session and should be passed to all other
|
||||
* functions.
|
||||
*
|
||||
* session - An out parameter to the new ggpo session object.
|
||||
*
|
||||
* cb - A GGPOSessionCallbacks structure which contains the callbacks you implement
|
||||
* to help GGPO.net synchronize the two games. You must implement all functions in
|
||||
* cb, even if they do nothing but 'return true';
|
||||
*
|
||||
* game - The name of the game. This is used internally for GGPO for logging purposes only.
|
||||
*
|
||||
* num_players - The number of players which will be in this game. The number of players
|
||||
* per session is fixed. If you need to change the number of players or any player
|
||||
* disconnects, you must start a new session.
|
||||
*
|
||||
* input_size - The size of the game inputs which will be passsed to ggpo_add_local_input.
|
||||
*
|
||||
* local_port - The port GGPO should bind to for UDP traffic.
|
||||
*
|
||||
* verification - Some optional data that will be matched with the peers during initial sync.
|
||||
* Can be set to null if verification_size is zero. This can be used to check that all peers are
|
||||
* running the same version of the application and of the game, are using the same settings, etc.
|
||||
*
|
||||
* verification_size - Size of the verification data. Can be set to zero to not exchange verification data.
|
||||
* Maximum size is 256 bytes.
|
||||
*/
|
||||
GGPO_API GGPOErrorCode __cdecl ggpo_start_session(GGPOSession **session,
|
||||
GGPOSessionCallbacks *cb,
|
||||
const char *game,
|
||||
int num_players,
|
||||
int input_size,
|
||||
unsigned short localport,
|
||||
const void *verification,
|
||||
int verification_size);
|
||||
|
||||
|
||||
/*
|
||||
* ggpo_add_player --
|
||||
*
|
||||
* Must be called for each player in the session (e.g. in a 3 player session, must
|
||||
* be called 3 times).
|
||||
*
|
||||
* player - A GGPOPlayer struct used to describe the player.
|
||||
*
|
||||
* handle - An out parameter to a handle used to identify this player in the future.
|
||||
* (e.g. in the on_event callbacks).
|
||||
*/
|
||||
GGPO_API GGPOErrorCode __cdecl ggpo_add_player(GGPOSession *session,
|
||||
GGPOPlayer *player,
|
||||
GGPOPlayerHandle *handle);
|
||||
|
||||
|
||||
/*
|
||||
* ggpo_start_synctest --
|
||||
*
|
||||
* Used to being a new GGPO.net sync test session. During a sync test, every
|
||||
* frame of execution is run twice: once in prediction mode and once again to
|
||||
* verify the result of the prediction. If the checksums of your save states
|
||||
* do not match, the test is aborted.
|
||||
*
|
||||
* cb - A GGPOSessionCallbacks structure which contains the callbacks you implement
|
||||
* to help GGPO.net synchronize the two games. You must implement all functions in
|
||||
* cb, even if they do nothing but 'return true';
|
||||
*
|
||||
* game - The name of the game. This is used internally for GGPO for logging purposes only.
|
||||
*
|
||||
* num_players - The number of players which will be in this game. The number of players
|
||||
* per session is fixed. If you need to change the number of players or any player
|
||||
* disconnects, you must start a new session.
|
||||
*
|
||||
* input_size - The size of the game inputs which will be passsed to ggpo_add_local_input.
|
||||
*
|
||||
* frames - The number of frames to run before verifying the prediction. The
|
||||
* recommended value is 1.
|
||||
*
|
||||
*/
|
||||
GGPO_API GGPOErrorCode __cdecl ggpo_start_synctest(GGPOSession **session,
|
||||
GGPOSessionCallbacks *cb,
|
||||
const char *game,
|
||||
int num_players,
|
||||
int input_size,
|
||||
int frames);
|
||||
|
||||
|
||||
/*
|
||||
* ggpo_start_spectating --
|
||||
*
|
||||
* Start a spectator session.
|
||||
*
|
||||
* cb - A GGPOSessionCallbacks structure which contains the callbacks you implement
|
||||
* to help GGPO.net synchronize the two games. You must implement all functions in
|
||||
* cb, even if they do nothing but 'return true';
|
||||
*
|
||||
* game - The name of the game. This is used internally for GGPO for logging purposes only.
|
||||
*
|
||||
* num_players - The number of players which will be in this game. The number of players
|
||||
* per session is fixed. If you need to change the number of players or any player
|
||||
* disconnects, you must start a new session.
|
||||
*
|
||||
* input_size - The size of the game inputs which will be passsed to ggpo_add_local_input.
|
||||
*
|
||||
* local_port - The port GGPO should bind to for UDP traffic.
|
||||
*
|
||||
* host_ip - The IP address of the host who will serve you the inputs for the game. Any
|
||||
* player partcipating in the session can serve as a host.
|
||||
*
|
||||
* host_port - The port of the session on the host
|
||||
*
|
||||
* verification - Some optional data that will be matched with the peers during initial sync.
|
||||
* Can be set to null if verification_size is zero. This can be used to check that all peers are
|
||||
* running the same version of the application and of the game, are using the same settings, etc.
|
||||
*
|
||||
* verification_size - Size of the verification data. Can be set to zero to not exchange verification data.
|
||||
* Maximum size is 256 bytes.
|
||||
*/
|
||||
GGPO_API GGPOErrorCode __cdecl ggpo_start_spectating(GGPOSession **session,
|
||||
GGPOSessionCallbacks *cb,
|
||||
const char *game,
|
||||
int num_players,
|
||||
int input_size,
|
||||
unsigned short local_port,
|
||||
char *host_ip,
|
||||
unsigned short host_port,
|
||||
const void *verification,
|
||||
int verification_size);
|
||||
|
||||
/*
|
||||
* ggpo_close_session --
|
||||
* Used to close a session. You must call ggpo_close_session to
|
||||
* free the resources allocated in ggpo_start_session.
|
||||
*/
|
||||
GGPO_API GGPOErrorCode __cdecl ggpo_close_session(GGPOSession *);
|
||||
|
||||
|
||||
/*
|
||||
* ggpo_set_frame_delay --
|
||||
*
|
||||
* Change the amount of frames ggpo will delay local input. Must be called
|
||||
* before the first call to ggpo_synchronize_input.
|
||||
*/
|
||||
GGPO_API GGPOErrorCode __cdecl ggpo_set_frame_delay(GGPOSession *,
|
||||
GGPOPlayerHandle player,
|
||||
int frame_delay);
|
||||
|
||||
/*
|
||||
* ggpo_idle --
|
||||
* Should be called periodically by your application to give GGPO.net
|
||||
* a chance to do some work. Most packet transmissions and rollbacks occur
|
||||
* in ggpo_idle.
|
||||
*
|
||||
* timeout - The amount of time GGPO.net is allowed to spend in this function,
|
||||
* in milliseconds.
|
||||
*/
|
||||
GGPO_API GGPOErrorCode __cdecl ggpo_idle(GGPOSession *,
|
||||
int timeout);
|
||||
|
||||
/*
|
||||
* ggpo_add_local_input --
|
||||
*
|
||||
* Used to notify GGPO.net of inputs that should be trasmitted to remote
|
||||
* players. ggpo_add_local_input must be called once every frame for
|
||||
* all player of type GGPO_PLAYERTYPE_LOCAL.
|
||||
*
|
||||
* player - The player handle returned for this player when you called
|
||||
* ggpo_add_local_player.
|
||||
*
|
||||
* values - The controller inputs for this player.
|
||||
*
|
||||
* size - The size of the controller inputs. This must be exactly equal to the
|
||||
* size passed into ggpo_start_session.
|
||||
*/
|
||||
GGPO_API GGPOErrorCode __cdecl ggpo_add_local_input(GGPOSession *,
|
||||
GGPOPlayerHandle player,
|
||||
void *values,
|
||||
int size);
|
||||
|
||||
/*
|
||||
* ggpo_synchronize_input --
|
||||
*
|
||||
* You should call ggpo_synchronize_input before every frame of execution,
|
||||
* including those frames which happen during rollback.
|
||||
*
|
||||
* values - When the function returns, the values parameter will contain
|
||||
* inputs for this frame for all players. The values array must be at
|
||||
* least (size * players) large.
|
||||
*
|
||||
* size - The size of the values array.
|
||||
*
|
||||
* disconnect_flags - Indicated whether the input in slot (1 << flag) is
|
||||
* valid. If a player has disconnected, the input in the values array for
|
||||
* that player will be zeroed and the i-th flag will be set. For example,
|
||||
* if only player 3 has disconnected, disconnect flags will be 8 (i.e. 1 << 3).
|
||||
*/
|
||||
GGPO_API GGPOErrorCode __cdecl ggpo_synchronize_input(GGPOSession *,
|
||||
void *values,
|
||||
int size,
|
||||
int *disconnect_flags);
|
||||
|
||||
/*
|
||||
* ggpo_disconnect_player --
|
||||
*
|
||||
* Disconnects a remote player from a game. Will return GGPO_ERRORCODE_PLAYER_DISCONNECTED
|
||||
* if you try to disconnect a player who has already been disconnected.
|
||||
*/
|
||||
GGPO_API GGPOErrorCode __cdecl ggpo_disconnect_player(GGPOSession *,
|
||||
GGPOPlayerHandle player);
|
||||
|
||||
/*
|
||||
* ggpo_advance_frame --
|
||||
*
|
||||
* You should call ggpo_advance_frame to notify GGPO.net that you have
|
||||
* advanced your gamestate by a single frame. You should call this everytime
|
||||
* you advance the gamestate by a frame, even during rollbacks. GGPO.net
|
||||
* may call your save_state callback before this function returns.
|
||||
*/
|
||||
GGPO_API GGPOErrorCode __cdecl ggpo_advance_frame(GGPOSession *);
|
||||
|
||||
/*
|
||||
* ggpo_get_network_stats --
|
||||
*
|
||||
* Used to fetch some statistics about the quality of the network connection.
|
||||
*
|
||||
* player - The player handle returned from the ggpo_add_player function you used
|
||||
* to add the remote player.
|
||||
*
|
||||
* stats - Out parameter to the network statistics.
|
||||
*/
|
||||
GGPO_API GGPOErrorCode __cdecl ggpo_get_network_stats(GGPOSession *,
|
||||
GGPOPlayerHandle player,
|
||||
GGPONetworkStats *stats);
|
||||
|
||||
/*
|
||||
* ggpo_set_disconnect_timeout --
|
||||
*
|
||||
* Sets the disconnect timeout. The session will automatically disconnect
|
||||
* from a remote peer if it has not received a packet in the timeout window.
|
||||
* You will be notified of the disconnect via a GGPO_EVENTCODE_DISCONNECTED_FROM_PEER
|
||||
* event.
|
||||
*
|
||||
* Setting a timeout value of 0 will disable automatic disconnects.
|
||||
*
|
||||
* timeout - The time in milliseconds to wait before disconnecting a peer.
|
||||
*/
|
||||
GGPO_API GGPOErrorCode __cdecl ggpo_set_disconnect_timeout(GGPOSession *,
|
||||
int timeout);
|
||||
|
||||
/*
|
||||
* ggpo_set_disconnect_notify_start --
|
||||
*
|
||||
* The time to wait before the first GGPO_EVENTCODE_NETWORK_INTERRUPTED timeout
|
||||
* will be sent.
|
||||
*
|
||||
* timeout - The amount of time which needs to elapse without receiving a packet
|
||||
* before the GGPO_EVENTCODE_NETWORK_INTERRUPTED event is sent.
|
||||
*/
|
||||
GGPO_API GGPOErrorCode __cdecl ggpo_set_disconnect_notify_start(GGPOSession *,
|
||||
int timeout);
|
||||
|
||||
/*
|
||||
* ggpo_log --
|
||||
*
|
||||
* Used to write to the ggpo.net log. In the current versions of the
|
||||
* SDK, a log file is only generated if the "quark.log" environment
|
||||
* variable is set to 1. This will change in future versions of the
|
||||
* SDK.
|
||||
*/
|
||||
GGPO_API void __cdecl ggpo_log(GGPOSession *,
|
||||
const char *fmt, ...);
|
||||
/*
|
||||
* ggpo_logv --
|
||||
*
|
||||
* A varargs compatible version of ggpo_log. See ggpo_log for
|
||||
* more details.
|
||||
*/
|
||||
GGPO_API void __cdecl ggpo_logv(GGPOSession *,
|
||||
const char *fmt,
|
||||
va_list args);
|
||||
|
||||
/*
|
||||
* ggpo_send_message --
|
||||
*
|
||||
* Sends application-specific data to other peers. The message is
|
||||
* delivered by the on_user_message callback.
|
||||
* If spectators is true, the message is also sent to spectators.
|
||||
*/
|
||||
GGPO_API GGPOErrorCode __cdecl ggpo_send_message(GGPOSession *,
|
||||
const void *msg,
|
||||
int len,
|
||||
bool spectators);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,34 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
* GGPO.net (http://ggpo.net) - Copyright 2009 GroundStorm Studios, LLC.
|
||||
*
|
||||
* Use of this software is governed by the MIT license that can be found
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef _BACKEND_H
|
||||
#define _BACKEND_H
|
||||
|
||||
#include "../ggpo_types.h"
|
||||
#include "ggponet.h"
|
||||
|
||||
struct GGPOSession {
|
||||
virtual ~GGPOSession() { }
|
||||
virtual GGPOErrorCode DoPoll(int timeout) { return GGPO_OK; }
|
||||
virtual GGPOErrorCode AddPlayer(GGPOPlayer *player, GGPOPlayerHandle *handle) = 0;
|
||||
virtual GGPOErrorCode AddLocalInput(GGPOPlayerHandle player, void *values, int size) = 0;
|
||||
virtual GGPOErrorCode SyncInput(void *values, int size, int *disconnect_flags) = 0;
|
||||
virtual GGPOErrorCode IncrementFrame(void) { return GGPO_OK; }
|
||||
virtual GGPOErrorCode DisconnectPlayer(GGPOPlayerHandle handle) { return GGPO_OK; }
|
||||
virtual GGPOErrorCode GetNetworkStats(GGPONetworkStats *stats, GGPOPlayerHandle handle) { return GGPO_OK; }
|
||||
virtual GGPOErrorCode Logv(const char *fmt, va_list list) { ::Logv(fmt, list); return GGPO_OK; }
|
||||
|
||||
virtual GGPOErrorCode SetFrameDelay(GGPOPlayerHandle player, int delay) { return GGPO_ERRORCODE_UNSUPPORTED; }
|
||||
virtual GGPOErrorCode SetDisconnectTimeout(int timeout) { return GGPO_ERRORCODE_UNSUPPORTED; }
|
||||
virtual GGPOErrorCode SetDisconnectNotifyStart(int timeout) { return GGPO_ERRORCODE_UNSUPPORTED; }
|
||||
virtual GGPOErrorCode SendMessage(const void *msg, int len, bool spectators) { return GGPO_ERRORCODE_UNSUPPORTED; }
|
||||
};
|
||||
|
||||
typedef struct GGPOSession Quark, IQuarkBackend; /* XXX: nuke this */
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,664 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
* GGPO.net (http://ggpo.net) - Copyright 2009 GroundStorm Studios, LLC.
|
||||
*
|
||||
* Use of this software is governed by the MIT license that can be found
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "p2p.h"
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
static const int RECOMMENDATION_INTERVAL = 240;
|
||||
static const int DEFAULT_DISCONNECT_TIMEOUT = 5000;
|
||||
static const int DEFAULT_DISCONNECT_NOTIFY_START = 750;
|
||||
|
||||
Peer2PeerBackend::Peer2PeerBackend(GGPOSessionCallbacks *cb,
|
||||
const char *gamename,
|
||||
uint16 localport,
|
||||
int num_players,
|
||||
int input_size,
|
||||
const void *verification,
|
||||
int verification_size) :
|
||||
_sync(_local_connect_status),
|
||||
_endpoints(nullptr),
|
||||
_num_spectators(0),
|
||||
_input_size(input_size),
|
||||
_num_players(num_players),
|
||||
_next_spectator_frame(0),
|
||||
_disconnect_timeout(DEFAULT_DISCONNECT_TIMEOUT),
|
||||
_disconnect_notify_start(DEFAULT_DISCONNECT_NOTIFY_START)
|
||||
{
|
||||
_callbacks = *cb;
|
||||
_synchronizing = true;
|
||||
_next_recommended_sleep = 0;
|
||||
|
||||
/*
|
||||
* Initialize the synchronziation layer
|
||||
*/
|
||||
Sync::Config config = { 0 };
|
||||
config.num_players = num_players;
|
||||
config.input_size = input_size;
|
||||
config.callbacks = _callbacks;
|
||||
config.num_prediction_frames = MAX_PREDICTION_FRAMES;
|
||||
_sync.Init(config);
|
||||
|
||||
/*
|
||||
* Initialize the UDP port
|
||||
*/
|
||||
_udp.Init(localport, &_poll, this);
|
||||
|
||||
_endpoints = new UdpProtocol[_num_players];
|
||||
for (int i = 0; i < _num_players; i++)
|
||||
_endpoints[i].SetVerificationData(verification, verification_size);
|
||||
memset(_local_connect_status, 0, sizeof(_local_connect_status));
|
||||
for (unsigned i = 0; i < ARRAY_SIZE(_local_connect_status); i++) {
|
||||
_local_connect_status[i].last_frame = -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Preload the ROM
|
||||
*/
|
||||
_callbacks.begin_game(gamename);
|
||||
}
|
||||
|
||||
Peer2PeerBackend::~Peer2PeerBackend()
|
||||
{
|
||||
delete [] _endpoints;
|
||||
}
|
||||
|
||||
void
|
||||
Peer2PeerBackend::AddRemotePlayer(char *ip,
|
||||
uint16 port,
|
||||
int queue)
|
||||
{
|
||||
/*
|
||||
* Start the state machine (xxx: no)
|
||||
*/
|
||||
_synchronizing = true;
|
||||
|
||||
_endpoints[queue].Init(&_udp, _poll, queue, ip, port, _local_connect_status);
|
||||
_endpoints[queue].SetDisconnectTimeout(_disconnect_timeout);
|
||||
_endpoints[queue].SetDisconnectNotifyStart(_disconnect_notify_start);
|
||||
_endpoints[queue].Synchronize();
|
||||
}
|
||||
|
||||
GGPOErrorCode Peer2PeerBackend::AddSpectator(char *ip,
|
||||
uint16 port)
|
||||
{
|
||||
if (_num_spectators == GGPO_MAX_SPECTATORS) {
|
||||
return GGPO_ERRORCODE_TOO_MANY_SPECTATORS;
|
||||
}
|
||||
/*
|
||||
* Currently, we can only add spectators before the game starts.
|
||||
*/
|
||||
if (!_synchronizing) {
|
||||
return GGPO_ERRORCODE_INVALID_REQUEST;
|
||||
}
|
||||
int queue = _num_spectators++;
|
||||
|
||||
_spectators[queue].Init(&_udp, _poll, queue + 1000, ip, port, _local_connect_status);
|
||||
_spectators[queue].SetDisconnectTimeout(_disconnect_timeout);
|
||||
_spectators[queue].SetDisconnectNotifyStart(_disconnect_notify_start);
|
||||
_spectators[queue].Synchronize();
|
||||
|
||||
return GGPO_OK;
|
||||
}
|
||||
|
||||
GGPOErrorCode
|
||||
Peer2PeerBackend::DoPoll(int timeout)
|
||||
{
|
||||
if (!_sync.InRollback()) {
|
||||
_poll.Pump(0);
|
||||
|
||||
PollUdpProtocolEvents();
|
||||
|
||||
if (!_synchronizing) {
|
||||
_sync.CheckSimulation(timeout);
|
||||
|
||||
// notify all of our endpoints of their local frame number for their
|
||||
// next connection quality report
|
||||
int current_frame = _sync.GetFrameCount();
|
||||
for (int i = 0; i < _num_players; i++) {
|
||||
_endpoints[i].SetLocalFrameNumber(current_frame);
|
||||
}
|
||||
|
||||
int total_min_confirmed;
|
||||
if (_num_players <= 2) {
|
||||
total_min_confirmed = Poll2Players(current_frame);
|
||||
} else {
|
||||
total_min_confirmed = PollNPlayers(current_frame);
|
||||
}
|
||||
|
||||
Log("last confirmed frame in p2p backend is %d.\n", total_min_confirmed);
|
||||
if (total_min_confirmed >= 0) {
|
||||
ASSERT(total_min_confirmed != INT_MAX);
|
||||
if (_num_spectators > 0) {
|
||||
while (_next_spectator_frame <= total_min_confirmed) {
|
||||
Log("pushing frame %d to spectators.\n", _next_spectator_frame);
|
||||
|
||||
GameInput input;
|
||||
input.frame = _next_spectator_frame;
|
||||
input.size = _input_size * _num_players;
|
||||
_sync.GetConfirmedInputs(input.bits, _input_size * _num_players, _next_spectator_frame);
|
||||
for (int i = 0; i < _num_spectators; i++) {
|
||||
_spectators[i].SendInput(input);
|
||||
}
|
||||
_next_spectator_frame++;
|
||||
}
|
||||
}
|
||||
Log("setting confirmed frame in sync to %d.\n", total_min_confirmed);
|
||||
_sync.SetLastConfirmedFrame(total_min_confirmed);
|
||||
}
|
||||
|
||||
// send timesync notifications if now is the proper time
|
||||
if (current_frame > _next_recommended_sleep) {
|
||||
int interval = 0;
|
||||
for (int i = 0; i < _num_players; i++) {
|
||||
interval = MAX(interval, _endpoints[i].RecommendFrameDelay());
|
||||
}
|
||||
|
||||
if (interval > 0) {
|
||||
GGPOEvent info;
|
||||
info.code = GGPO_EVENTCODE_TIMESYNC;
|
||||
info.u.timesync.frames_ahead = interval;
|
||||
_callbacks.on_event(&info);
|
||||
_next_recommended_sleep = current_frame + RECOMMENDATION_INTERVAL;
|
||||
}
|
||||
}
|
||||
// XXX: this is obviously a farce...
|
||||
if (timeout)
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
}
|
||||
}
|
||||
return GGPO_OK;
|
||||
}
|
||||
|
||||
int Peer2PeerBackend::Poll2Players(int current_frame)
|
||||
{
|
||||
int i;
|
||||
|
||||
// discard confirmed frames as appropriate
|
||||
int total_min_confirmed = MAX_INT;
|
||||
for (i = 0; i < _num_players; i++) {
|
||||
bool queue_connected = true;
|
||||
if (_endpoints[i].IsRunning()) {
|
||||
int ignore;
|
||||
queue_connected = _endpoints[i].GetPeerConnectStatus(i, &ignore);
|
||||
}
|
||||
if (!_local_connect_status[i].disconnected) {
|
||||
total_min_confirmed = MIN(_local_connect_status[i].last_frame, total_min_confirmed);
|
||||
}
|
||||
Log(" local endp: connected = %d, last_received = %d, total_min_confirmed = %d.\n", !_local_connect_status[i].disconnected, _local_connect_status[i].last_frame, total_min_confirmed);
|
||||
if (!queue_connected && !_local_connect_status[i].disconnected) {
|
||||
Log("disconnecting i %d by remote request.\n", i);
|
||||
DisconnectPlayerQueue(i, total_min_confirmed);
|
||||
}
|
||||
Log(" total_min_confirmed = %d.\n", total_min_confirmed);
|
||||
}
|
||||
return total_min_confirmed;
|
||||
}
|
||||
|
||||
int Peer2PeerBackend::PollNPlayers(int current_frame)
|
||||
{
|
||||
int i, queue, last_received;
|
||||
|
||||
// discard confirmed frames as appropriate
|
||||
int total_min_confirmed = MAX_INT;
|
||||
for (queue = 0; queue < _num_players; queue++) {
|
||||
bool queue_connected = true;
|
||||
int queue_min_confirmed = MAX_INT;
|
||||
Log("considering queue %d.\n", queue);
|
||||
for (i = 0; i < _num_players; i++) {
|
||||
// we're going to do a lot of logic here in consideration of endpoint i.
|
||||
// keep accumulating the minimum confirmed point for all n*n packets and
|
||||
// throw away the rest.
|
||||
if (_endpoints[i].IsRunning()) {
|
||||
bool connected = _endpoints[i].GetPeerConnectStatus(queue, &last_received);
|
||||
|
||||
queue_connected = queue_connected && connected;
|
||||
queue_min_confirmed = MIN(last_received, queue_min_confirmed);
|
||||
Log(" endpoint %d: connected = %d, last_received = %d, queue_min_confirmed = %d.\n", i, connected, last_received, queue_min_confirmed);
|
||||
} else {
|
||||
Log(" endpoint %d: ignoring... not running.\n", i);
|
||||
}
|
||||
}
|
||||
// merge in our local status only if we're still connected!
|
||||
if (!_local_connect_status[queue].disconnected) {
|
||||
queue_min_confirmed = MIN(_local_connect_status[queue].last_frame, queue_min_confirmed);
|
||||
}
|
||||
Log(" local endp: connected = %d, last_received = %d, queue_min_confirmed = %d.\n", !_local_connect_status[queue].disconnected, _local_connect_status[queue].last_frame, queue_min_confirmed);
|
||||
|
||||
if (queue_connected) {
|
||||
total_min_confirmed = MIN(queue_min_confirmed, total_min_confirmed);
|
||||
} else {
|
||||
// check to see if this disconnect notification is further back than we've been before. If
|
||||
// so, we need to re-adjust. This can happen when we detect our own disconnect at frame n
|
||||
// and later receive a disconnect notification for frame n-1.
|
||||
if (!_local_connect_status[queue].disconnected || _local_connect_status[queue].last_frame > queue_min_confirmed) {
|
||||
Log("disconnecting queue %d by remote request.\n", queue);
|
||||
DisconnectPlayerQueue(queue, queue_min_confirmed);
|
||||
}
|
||||
}
|
||||
Log(" total_min_confirmed = %d.\n", total_min_confirmed);
|
||||
}
|
||||
return total_min_confirmed;
|
||||
}
|
||||
|
||||
|
||||
GGPOErrorCode
|
||||
Peer2PeerBackend::AddPlayer(GGPOPlayer *player,
|
||||
GGPOPlayerHandle *handle)
|
||||
{
|
||||
if (player->type == GGPO_PLAYERTYPE_SPECTATOR) {
|
||||
return AddSpectator(player->u.remote.ip_address, player->u.remote.port);
|
||||
}
|
||||
|
||||
int queue = player->player_num - 1;
|
||||
if (player->player_num < 1 || player->player_num > _num_players) {
|
||||
return GGPO_ERRORCODE_PLAYER_OUT_OF_RANGE;
|
||||
}
|
||||
*handle = QueueToPlayerHandle(queue);
|
||||
|
||||
if (player->type == GGPO_PLAYERTYPE_REMOTE) {
|
||||
AddRemotePlayer(player->u.remote.ip_address, player->u.remote.port, queue);
|
||||
}
|
||||
return GGPO_OK;
|
||||
}
|
||||
|
||||
GGPOErrorCode
|
||||
Peer2PeerBackend::AddLocalInput(GGPOPlayerHandle player,
|
||||
void *values,
|
||||
int size)
|
||||
{
|
||||
int queue;
|
||||
GameInput input;
|
||||
GGPOErrorCode result;
|
||||
|
||||
if (_sync.InRollback()) {
|
||||
return GGPO_ERRORCODE_IN_ROLLBACK;
|
||||
}
|
||||
if (_synchronizing) {
|
||||
return GGPO_ERRORCODE_NOT_SYNCHRONIZED;
|
||||
}
|
||||
|
||||
result = PlayerHandleToQueue(player, &queue);
|
||||
if (!GGPO_SUCCEEDED(result)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
input.init(-1, (char *)values, size);
|
||||
|
||||
// Feed the input for the current frame into the synchronzation layer.
|
||||
if (!_sync.AddLocalInput(queue, input)) {
|
||||
return GGPO_ERRORCODE_PREDICTION_THRESHOLD;
|
||||
}
|
||||
|
||||
if (input.frame != GameInput::NullFrame) { // xxx: <- comment why this is the case
|
||||
// Update the local connect status state to indicate that we've got a
|
||||
// confirmed local frame for this player. this must come first so it
|
||||
// gets incorporated into the next packet we send.
|
||||
|
||||
Log("setting local connect status for local queue %d to %d", queue, input.frame);
|
||||
_local_connect_status[queue].last_frame = input.frame;
|
||||
|
||||
// Send the input to all the remote players.
|
||||
for (int i = 0; i < _num_players; i++) {
|
||||
if (_endpoints[i].IsInitialized()) {
|
||||
_endpoints[i].SendInput(input);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return GGPO_OK;
|
||||
}
|
||||
|
||||
|
||||
GGPOErrorCode
|
||||
Peer2PeerBackend::SyncInput(void *values,
|
||||
int size,
|
||||
int *disconnect_flags)
|
||||
{
|
||||
int flags;
|
||||
|
||||
// Wait until we've started to return inputs.
|
||||
if (_synchronizing) {
|
||||
return GGPO_ERRORCODE_NOT_SYNCHRONIZED;
|
||||
}
|
||||
flags = _sync.SynchronizeInputs(values, size);
|
||||
if (disconnect_flags) {
|
||||
*disconnect_flags = flags;
|
||||
}
|
||||
return GGPO_OK;
|
||||
}
|
||||
|
||||
GGPOErrorCode
|
||||
Peer2PeerBackend::IncrementFrame(void)
|
||||
{
|
||||
Log("End of frame (%d)...\n", _sync.GetFrameCount());
|
||||
_sync.IncrementFrame();
|
||||
DoPoll(0);
|
||||
PollSyncEvents();
|
||||
|
||||
return GGPO_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Peer2PeerBackend::PollSyncEvents(void)
|
||||
{
|
||||
Sync::Event e;
|
||||
while (_sync.GetEvent(e)) {
|
||||
OnSyncEvent(e);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
Peer2PeerBackend::PollUdpProtocolEvents(void)
|
||||
{
|
||||
UdpProtocol::Event evt;
|
||||
for (int i = 0; i < _num_players; i++) {
|
||||
while (_endpoints[i].GetEvent(evt)) {
|
||||
OnUdpProtocolPeerEvent(evt, i);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < _num_spectators; i++) {
|
||||
while (_spectators[i].GetEvent(evt)) {
|
||||
OnUdpProtocolSpectatorEvent(evt, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Peer2PeerBackend::OnUdpProtocolPeerEvent(UdpProtocol::Event &evt, int queue)
|
||||
{
|
||||
OnUdpProtocolEvent(evt, QueueToPlayerHandle(queue));
|
||||
switch (evt.type) {
|
||||
case UdpProtocol::Event::Input:
|
||||
if (!_local_connect_status[queue].disconnected) {
|
||||
int current_remote_frame = _local_connect_status[queue].last_frame;
|
||||
int new_remote_frame = evt.u.input.input.frame;
|
||||
ASSERT(current_remote_frame == -1 || new_remote_frame == (current_remote_frame + 1));
|
||||
|
||||
_sync.AddRemoteInput(queue, evt.u.input.input);
|
||||
// Notify the other endpoints which frame we received from a peer
|
||||
Log("setting remote connect status for queue %d to %d\n", queue, evt.u.input.input.frame);
|
||||
_local_connect_status[queue].last_frame = evt.u.input.input.frame;
|
||||
}
|
||||
break;
|
||||
|
||||
case UdpProtocol::Event::Disconnected:
|
||||
DisconnectPlayer(QueueToPlayerHandle(queue));
|
||||
break;
|
||||
|
||||
case UdpProtocol::Event::AppData:
|
||||
if (evt.u.app_data.spectators)
|
||||
for (int i = 0; i < _num_spectators; i++)
|
||||
if (_spectators[i].IsInitialized())
|
||||
_spectators[i].SendAppData(evt.u.app_data.data, evt.u.app_data.size, true);
|
||||
Log("calling on_message callback with %d bytes", evt.u.app_data.size);
|
||||
if (_callbacks.on_message != nullptr)
|
||||
_callbacks.on_message(evt.u.app_data.data, evt.u.app_data.size);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Peer2PeerBackend::OnUdpProtocolSpectatorEvent(UdpProtocol::Event &evt, int queue)
|
||||
{
|
||||
GGPOPlayerHandle handle = QueueToSpectatorHandle(queue);
|
||||
OnUdpProtocolEvent(evt, handle);
|
||||
|
||||
if (evt.type == UdpProtocol::Event::Disconnected)
|
||||
{
|
||||
_spectators[queue].Disconnect();
|
||||
|
||||
GGPOEvent info;
|
||||
info.code = GGPO_EVENTCODE_DISCONNECTED_FROM_PEER;
|
||||
info.u.disconnected.player = handle;
|
||||
_callbacks.on_event(&info);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Peer2PeerBackend::OnUdpProtocolEvent(UdpProtocol::Event &evt, GGPOPlayerHandle handle)
|
||||
{
|
||||
GGPOEvent info;
|
||||
|
||||
switch (evt.type) {
|
||||
case UdpProtocol::Event::Connected:
|
||||
info.code = GGPO_EVENTCODE_CONNECTED_TO_PEER;
|
||||
info.u.connected.player = handle;
|
||||
_callbacks.on_event(&info);
|
||||
break;
|
||||
case UdpProtocol::Event::Synchronizing:
|
||||
info.code = GGPO_EVENTCODE_SYNCHRONIZING_WITH_PEER;
|
||||
info.u.synchronizing.player = handle;
|
||||
info.u.synchronizing.count = evt.u.synchronizing.count;
|
||||
info.u.synchronizing.total = evt.u.synchronizing.total;
|
||||
_callbacks.on_event(&info);
|
||||
break;
|
||||
case UdpProtocol::Event::Synchronzied:
|
||||
info.code = GGPO_EVENTCODE_SYNCHRONIZED_WITH_PEER;
|
||||
info.u.synchronized.player = handle;
|
||||
_callbacks.on_event(&info);
|
||||
|
||||
CheckInitialSync();
|
||||
break;
|
||||
|
||||
case UdpProtocol::Event::NetworkInterrupted:
|
||||
info.code = GGPO_EVENTCODE_CONNECTION_INTERRUPTED;
|
||||
info.u.connection_interrupted.player = handle;
|
||||
info.u.connection_interrupted.disconnect_timeout = evt.u.network_interrupted.disconnect_timeout;
|
||||
_callbacks.on_event(&info);
|
||||
break;
|
||||
|
||||
case UdpProtocol::Event::NetworkResumed:
|
||||
info.code = GGPO_EVENTCODE_CONNECTION_RESUMED;
|
||||
info.u.connection_resumed.player = handle;
|
||||
_callbacks.on_event(&info);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Called only as the result of a local decision to disconnect. The remote
|
||||
* decisions to disconnect are a result of us parsing the peer_connect_settings
|
||||
* blob in every endpoint periodically.
|
||||
*/
|
||||
GGPOErrorCode
|
||||
Peer2PeerBackend::DisconnectPlayer(GGPOPlayerHandle player)
|
||||
{
|
||||
int queue;
|
||||
GGPOErrorCode result;
|
||||
|
||||
result = PlayerHandleToQueue(player, &queue);
|
||||
if (!GGPO_SUCCEEDED(result)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (_local_connect_status[queue].disconnected) {
|
||||
return GGPO_ERRORCODE_PLAYER_DISCONNECTED;
|
||||
}
|
||||
|
||||
if (!_endpoints[queue].IsInitialized()) {
|
||||
int current_frame = _sync.GetFrameCount();
|
||||
// xxx: we should be tracking who the local player is, but for now assume
|
||||
// that if the endpoint is not initalized, this must be the local player.
|
||||
Log("Disconnecting local player %d at frame %d by user request.\n", queue, _local_connect_status[queue].last_frame);
|
||||
for (int i = 0; i < _num_players; i++) {
|
||||
if (_endpoints[i].IsInitialized()) {
|
||||
DisconnectPlayerQueue(i, current_frame);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Log("Disconnecting queue %d at frame %d by user request.\n", queue, _local_connect_status[queue].last_frame);
|
||||
DisconnectPlayerQueue(queue, _local_connect_status[queue].last_frame);
|
||||
}
|
||||
return GGPO_OK;
|
||||
}
|
||||
|
||||
void
|
||||
Peer2PeerBackend::DisconnectPlayerQueue(int queue, int syncto)
|
||||
{
|
||||
GGPOEvent info;
|
||||
int framecount = _sync.GetFrameCount();
|
||||
|
||||
_endpoints[queue].Disconnect();
|
||||
|
||||
Log("Changing queue %d local connect status for last frame from %d to %d on disconnect request (current: %d).\n",
|
||||
queue, _local_connect_status[queue].last_frame, syncto, framecount);
|
||||
|
||||
_local_connect_status[queue].disconnected = 1;
|
||||
_local_connect_status[queue].last_frame = syncto;
|
||||
|
||||
if (syncto != GameInput::NullFrame && syncto < framecount) {
|
||||
Log("adjusting simulation to account for the fact that %d disconnected @ %d.\n", queue, syncto);
|
||||
_sync.AdjustSimulation(syncto);
|
||||
Log("finished adjusting simulation.\n");
|
||||
}
|
||||
|
||||
info.code = GGPO_EVENTCODE_DISCONNECTED_FROM_PEER;
|
||||
info.u.disconnected.player = QueueToPlayerHandle(queue);
|
||||
_callbacks.on_event(&info);
|
||||
|
||||
CheckInitialSync();
|
||||
}
|
||||
|
||||
|
||||
GGPOErrorCode
|
||||
Peer2PeerBackend::GetNetworkStats(GGPONetworkStats *stats, GGPOPlayerHandle player)
|
||||
{
|
||||
int queue;
|
||||
GGPOErrorCode result;
|
||||
|
||||
result = PlayerHandleToQueue(player, &queue);
|
||||
if (!GGPO_SUCCEEDED(result)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
memset(stats, 0, sizeof *stats);
|
||||
_endpoints[queue].GetNetworkStats(stats);
|
||||
stats->sync.predicted_frames = _sync.GetPredictedFrames();
|
||||
|
||||
return GGPO_OK;
|
||||
}
|
||||
|
||||
GGPOErrorCode
|
||||
Peer2PeerBackend::SetFrameDelay(GGPOPlayerHandle player, int delay)
|
||||
{
|
||||
int queue;
|
||||
GGPOErrorCode result;
|
||||
|
||||
result = PlayerHandleToQueue(player, &queue);
|
||||
if (!GGPO_SUCCEEDED(result)) {
|
||||
return result;
|
||||
}
|
||||
_sync.SetFrameDelay(queue, delay);
|
||||
return GGPO_OK;
|
||||
}
|
||||
|
||||
GGPOErrorCode
|
||||
Peer2PeerBackend::SetDisconnectTimeout(int timeout)
|
||||
{
|
||||
_disconnect_timeout = timeout;
|
||||
for (int i = 0; i < _num_players; i++) {
|
||||
if (_endpoints[i].IsInitialized()) {
|
||||
_endpoints[i].SetDisconnectTimeout(_disconnect_timeout);
|
||||
}
|
||||
}
|
||||
return GGPO_OK;
|
||||
}
|
||||
|
||||
GGPOErrorCode
|
||||
Peer2PeerBackend::SetDisconnectNotifyStart(int timeout)
|
||||
{
|
||||
_disconnect_notify_start = timeout;
|
||||
for (int i = 0; i < _num_players; i++) {
|
||||
if (_endpoints[i].IsInitialized()) {
|
||||
_endpoints[i].SetDisconnectNotifyStart(_disconnect_notify_start);
|
||||
}
|
||||
}
|
||||
return GGPO_OK;
|
||||
}
|
||||
|
||||
GGPOErrorCode
|
||||
Peer2PeerBackend::PlayerHandleToQueue(GGPOPlayerHandle player, int *queue)
|
||||
{
|
||||
int offset = ((int)player - 1);
|
||||
if (offset < 0 || offset >= _num_players) {
|
||||
return GGPO_ERRORCODE_INVALID_PLAYER_HANDLE;
|
||||
}
|
||||
*queue = offset;
|
||||
return GGPO_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Peer2PeerBackend::OnMsg(sockaddr_in &from, UdpMsg *msg, int len)
|
||||
{
|
||||
for (int i = 0; i < _num_players; i++) {
|
||||
if (_endpoints[i].HandlesMsg(from, msg)) {
|
||||
_endpoints[i].OnMsg(msg, len);
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < _num_spectators; i++) {
|
||||
if (_spectators[i].HandlesMsg(from, msg)) {
|
||||
_spectators[i].OnMsg(msg, len);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Peer2PeerBackend::CheckInitialSync()
|
||||
{
|
||||
int i;
|
||||
|
||||
if (_synchronizing) {
|
||||
// Check to see if everyone is now synchronized. If so,
|
||||
// go ahead and tell the client that we're ok to accept input.
|
||||
for (i = 0; i < _num_players; i++) {
|
||||
// xxx: IsInitialized() must go... we're actually using it as a proxy for "represents the local player"
|
||||
if (_endpoints[i].IsInitialized() && !_endpoints[i].IsSynchronized() && !_local_connect_status[i].disconnected) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < _num_spectators; i++) {
|
||||
if (_spectators[i].IsInitialized() && !_spectators[i].IsSynchronized()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
GGPOEvent info;
|
||||
info.code = GGPO_EVENTCODE_RUNNING;
|
||||
_callbacks.on_event(&info);
|
||||
_synchronizing = false;
|
||||
}
|
||||
}
|
||||
|
||||
GGPOErrorCode Peer2PeerBackend::SendMessage(const void *msg, int len, bool spectators)
|
||||
{
|
||||
if (_synchronizing)
|
||||
return GGPO_ERRORCODE_NOT_SYNCHRONIZED;
|
||||
if (len > MAX_APPDATA_SIZE)
|
||||
return GGPO_ERRORCODE_INVALID_REQUEST;
|
||||
for (int i = 0; i < _num_players; i++)
|
||||
if (_endpoints[i].IsInitialized())
|
||||
_endpoints[i].SendAppData(msg, len, spectators);
|
||||
if (spectators)
|
||||
for (int i = 0; i < _num_spectators; i++)
|
||||
if (_spectators[i].IsInitialized())
|
||||
_spectators[i].SendAppData(msg, len, spectators);
|
||||
|
||||
return GGPO_ERRORCODE_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
* GGPO.net (http://ggpo.net) - Copyright 2009 GroundStorm Studios, LLC.
|
||||
*
|
||||
* Use of this software is governed by the MIT license that can be found
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef _P2P_H
|
||||
#define _P2P_H
|
||||
|
||||
#include "ggpo_types.h"
|
||||
#include "ggpo_poll.h"
|
||||
#include "sync.h"
|
||||
#include "backend.h"
|
||||
#include "timesync.h"
|
||||
#include "network/udp_proto.h"
|
||||
|
||||
class Peer2PeerBackend : public IQuarkBackend, IPollSink, Udp::Callbacks {
|
||||
public:
|
||||
Peer2PeerBackend(GGPOSessionCallbacks *cb, const char *gamename, uint16 localport, int num_players, int input_size,
|
||||
const void *verification, int verification_size);
|
||||
virtual ~Peer2PeerBackend();
|
||||
|
||||
|
||||
public:
|
||||
GGPOErrorCode DoPoll(int timeout) override;
|
||||
GGPOErrorCode AddPlayer(GGPOPlayer *player, GGPOPlayerHandle *handle) override;
|
||||
GGPOErrorCode AddLocalInput(GGPOPlayerHandle player, void *values, int size) override;
|
||||
GGPOErrorCode SyncInput(void *values, int size, int *disconnect_flags) override;
|
||||
GGPOErrorCode IncrementFrame(void) override;
|
||||
GGPOErrorCode DisconnectPlayer(GGPOPlayerHandle handle) override;
|
||||
GGPOErrorCode GetNetworkStats(GGPONetworkStats *stats, GGPOPlayerHandle handle) override;
|
||||
GGPOErrorCode SetFrameDelay(GGPOPlayerHandle player, int delay) override;
|
||||
GGPOErrorCode SetDisconnectTimeout(int timeout) override;
|
||||
GGPOErrorCode SetDisconnectNotifyStart(int timeout) override;
|
||||
GGPOErrorCode SendMessage(const void *msg, int len, bool spectators) override;
|
||||
|
||||
public:
|
||||
void OnMsg(sockaddr_in &from, UdpMsg *msg, int len) override;
|
||||
|
||||
protected:
|
||||
GGPOErrorCode PlayerHandleToQueue(GGPOPlayerHandle player, int *queue);
|
||||
GGPOPlayerHandle QueueToPlayerHandle(int queue) { return (GGPOPlayerHandle)(queue + 1); }
|
||||
GGPOPlayerHandle QueueToSpectatorHandle(int queue) { return (GGPOPlayerHandle)(queue + 1000); } /* out of range of the player array, basically */
|
||||
void DisconnectPlayerQueue(int queue, int syncto);
|
||||
void PollSyncEvents(void);
|
||||
void PollUdpProtocolEvents(void);
|
||||
void CheckInitialSync(void);
|
||||
int Poll2Players(int current_frame);
|
||||
int PollNPlayers(int current_frame);
|
||||
void AddRemotePlayer(char *remoteip, uint16 reportport, int queue);
|
||||
GGPOErrorCode AddSpectator(char *remoteip, uint16 reportport);
|
||||
virtual void OnSyncEvent(Sync::Event &e) { }
|
||||
virtual void OnUdpProtocolEvent(UdpProtocol::Event &e, GGPOPlayerHandle handle);
|
||||
virtual void OnUdpProtocolPeerEvent(UdpProtocol::Event &e, int queue);
|
||||
virtual void OnUdpProtocolSpectatorEvent(UdpProtocol::Event &e, int queue);
|
||||
|
||||
protected:
|
||||
GGPOSessionCallbacks _callbacks;
|
||||
Poll _poll;
|
||||
Sync _sync;
|
||||
Udp _udp;
|
||||
UdpProtocol *_endpoints;
|
||||
UdpProtocol _spectators[GGPO_MAX_SPECTATORS];
|
||||
int _num_spectators;
|
||||
int _input_size;
|
||||
|
||||
bool _synchronizing;
|
||||
int _num_players;
|
||||
int _next_recommended_sleep;
|
||||
|
||||
int _next_spectator_frame;
|
||||
int _disconnect_timeout;
|
||||
int _disconnect_notify_start;
|
||||
|
||||
UdpMsg::connect_status _local_connect_status[UDP_MSG_MAX_PLAYERS];
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,189 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
* GGPO.net (http://ggpo.net) - Copyright 2009 GroundStorm Studios, LLC.
|
||||
*
|
||||
* Use of this software is governed by the MIT license that can be found
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "spectator.h"
|
||||
|
||||
SpectatorBackend::SpectatorBackend(GGPOSessionCallbacks *cb,
|
||||
const char* gamename,
|
||||
uint16 localport,
|
||||
int num_players,
|
||||
int input_size,
|
||||
char *hostip,
|
||||
u_short hostport,
|
||||
const void *verification,
|
||||
int verification_size) :
|
||||
_input_size(input_size),
|
||||
_num_players(num_players),
|
||||
_next_input_to_send(0)
|
||||
{
|
||||
_callbacks = *cb;
|
||||
_synchronizing = true;
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(_inputs); i++) {
|
||||
_inputs[i].frame = -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the UDP port
|
||||
*/
|
||||
_udp.Init(localport, &_poll, this);
|
||||
|
||||
/*
|
||||
* Init the host endpoint
|
||||
*/
|
||||
_host.SetVerificationData(verification, verification_size);
|
||||
_host.Init(&_udp, _poll, 0, hostip, hostport, NULL);
|
||||
_host.Synchronize();
|
||||
|
||||
/*
|
||||
* Preload the ROM
|
||||
*/
|
||||
_callbacks.begin_game(gamename);
|
||||
}
|
||||
|
||||
SpectatorBackend::~SpectatorBackend()
|
||||
{
|
||||
}
|
||||
|
||||
GGPOErrorCode
|
||||
SpectatorBackend::DoPoll(int timeout)
|
||||
{
|
||||
_poll.Pump(0);
|
||||
|
||||
PollUdpProtocolEvents();
|
||||
return GGPO_OK;
|
||||
}
|
||||
|
||||
GGPOErrorCode
|
||||
SpectatorBackend::SyncInput(void *values,
|
||||
int size,
|
||||
int *disconnect_flags)
|
||||
{
|
||||
// Wait until we've started to return inputs.
|
||||
if (_synchronizing) {
|
||||
return GGPO_ERRORCODE_NOT_SYNCHRONIZED;
|
||||
}
|
||||
|
||||
GameInput &input = _inputs[_next_input_to_send % SPECTATOR_FRAME_BUFFER_SIZE];
|
||||
if (input.frame < _next_input_to_send) {
|
||||
// Haven't received the input from the host yet. Wait
|
||||
return GGPO_ERRORCODE_PREDICTION_THRESHOLD;
|
||||
}
|
||||
if (input.frame > _next_input_to_send) {
|
||||
// The host is way way way far ahead of the spectator. How'd this
|
||||
// happen? Anyway, the input we need is gone forever.
|
||||
return GGPO_ERRORCODE_GENERAL_FAILURE;
|
||||
}
|
||||
|
||||
ASSERT(size >= _input_size * _num_players);
|
||||
memcpy(values, input.bits, _input_size * _num_players);
|
||||
if (disconnect_flags) {
|
||||
*disconnect_flags = 0; // xxx: should get them from the host!
|
||||
}
|
||||
_next_input_to_send++;
|
||||
|
||||
return GGPO_OK;
|
||||
}
|
||||
|
||||
GGPOErrorCode
|
||||
SpectatorBackend::IncrementFrame(void)
|
||||
{
|
||||
Log("End of frame (%d)...\n", _next_input_to_send - 1);
|
||||
DoPoll(0);
|
||||
PollUdpProtocolEvents();
|
||||
|
||||
return GGPO_OK;
|
||||
}
|
||||
|
||||
void
|
||||
SpectatorBackend::PollUdpProtocolEvents(void)
|
||||
{
|
||||
UdpProtocol::Event evt;
|
||||
while (_host.GetEvent(evt)) {
|
||||
OnUdpProtocolEvent(evt);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SpectatorBackend::OnUdpProtocolEvent(UdpProtocol::Event &evt)
|
||||
{
|
||||
GGPOEvent info;
|
||||
|
||||
switch (evt.type) {
|
||||
case UdpProtocol::Event::Connected:
|
||||
info.code = GGPO_EVENTCODE_CONNECTED_TO_PEER;
|
||||
info.u.connected.player = 0;
|
||||
_callbacks.on_event(&info);
|
||||
break;
|
||||
case UdpProtocol::Event::Synchronizing:
|
||||
info.code = GGPO_EVENTCODE_SYNCHRONIZING_WITH_PEER;
|
||||
info.u.synchronizing.player = 0;
|
||||
info.u.synchronizing.count = evt.u.synchronizing.count;
|
||||
info.u.synchronizing.total = evt.u.synchronizing.total;
|
||||
_callbacks.on_event(&info);
|
||||
break;
|
||||
case UdpProtocol::Event::Synchronzied:
|
||||
if (_synchronizing) {
|
||||
info.code = GGPO_EVENTCODE_SYNCHRONIZED_WITH_PEER;
|
||||
info.u.synchronized.player = 0;
|
||||
_callbacks.on_event(&info);
|
||||
|
||||
info.code = GGPO_EVENTCODE_RUNNING;
|
||||
_callbacks.on_event(&info);
|
||||
_synchronizing = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case UdpProtocol::Event::NetworkInterrupted:
|
||||
info.code = GGPO_EVENTCODE_CONNECTION_INTERRUPTED;
|
||||
info.u.connection_interrupted.player = 0;
|
||||
info.u.connection_interrupted.disconnect_timeout = evt.u.network_interrupted.disconnect_timeout;
|
||||
_callbacks.on_event(&info);
|
||||
break;
|
||||
|
||||
case UdpProtocol::Event::NetworkResumed:
|
||||
info.code = GGPO_EVENTCODE_CONNECTION_RESUMED;
|
||||
info.u.connection_resumed.player = 0;
|
||||
_callbacks.on_event(&info);
|
||||
break;
|
||||
|
||||
case UdpProtocol::Event::Disconnected:
|
||||
info.code = GGPO_EVENTCODE_DISCONNECTED_FROM_PEER;
|
||||
info.u.disconnected.player = 0;
|
||||
_callbacks.on_event(&info);
|
||||
break;
|
||||
|
||||
case UdpProtocol::Event::Input:
|
||||
{
|
||||
GameInput& input = evt.u.input.input;
|
||||
|
||||
_host.SetLocalFrameNumber(input.frame);
|
||||
_host.SendInputAck();
|
||||
_inputs[input.frame % SPECTATOR_FRAME_BUFFER_SIZE] = input;
|
||||
}
|
||||
break;
|
||||
|
||||
case UdpProtocol::Event::AppData:
|
||||
Log("calling on_message callback with %d bytes", evt.u.app_data.size);
|
||||
if (_callbacks.on_message != nullptr)
|
||||
_callbacks.on_message(evt.u.app_data.data, evt.u.app_data.size);
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SpectatorBackend::OnMsg(sockaddr_in &from, UdpMsg *msg, int len)
|
||||
{
|
||||
if (_host.HandlesMsg(from, msg)) {
|
||||
_host.OnMsg(msg, len);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
* GGPO.net (http://ggpo.net) - Copyright 2009 GroundStorm Studios, LLC.
|
||||
*
|
||||
* Use of this software is governed by the MIT license that can be found
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef _SPECTATOR_H
|
||||
#define _SPECTATOR_H
|
||||
|
||||
#include "../ggpo_poll.h"
|
||||
#include "../ggpo_types.h"
|
||||
#include "sync.h"
|
||||
#include "backend.h"
|
||||
#include "timesync.h"
|
||||
#include "network/udp_proto.h"
|
||||
|
||||
#define SPECTATOR_FRAME_BUFFER_SIZE 64
|
||||
|
||||
class SpectatorBackend : public IQuarkBackend, IPollSink, Udp::Callbacks {
|
||||
public:
|
||||
SpectatorBackend(GGPOSessionCallbacks *cb, const char *gamename, uint16 localport, int num_players, int input_size, char *hostip, u_short hostport,
|
||||
const void *verification, int verification_size);
|
||||
virtual ~SpectatorBackend();
|
||||
|
||||
|
||||
public:
|
||||
GGPOErrorCode DoPoll(int timeout) override;
|
||||
GGPOErrorCode AddPlayer(GGPOPlayer *player, GGPOPlayerHandle *handle) override { return GGPO_ERRORCODE_UNSUPPORTED; }
|
||||
GGPOErrorCode AddLocalInput(GGPOPlayerHandle player, void *values, int size) override { return GGPO_OK; }
|
||||
GGPOErrorCode SyncInput(void *values, int size, int *disconnect_flags) override;
|
||||
GGPOErrorCode IncrementFrame(void) override;
|
||||
GGPOErrorCode DisconnectPlayer(GGPOPlayerHandle handle) override { return GGPO_ERRORCODE_UNSUPPORTED; }
|
||||
GGPOErrorCode GetNetworkStats(GGPONetworkStats *stats, GGPOPlayerHandle handle) override { return GGPO_ERRORCODE_UNSUPPORTED; }
|
||||
GGPOErrorCode SetFrameDelay(GGPOPlayerHandle player, int delay) override { return GGPO_ERRORCODE_UNSUPPORTED; }
|
||||
GGPOErrorCode SetDisconnectTimeout(int timeout) override { return GGPO_ERRORCODE_UNSUPPORTED; }
|
||||
GGPOErrorCode SetDisconnectNotifyStart(int timeout) override { return GGPO_ERRORCODE_UNSUPPORTED; }
|
||||
|
||||
public:
|
||||
void OnMsg(sockaddr_in &from, UdpMsg *msg, int len) override;
|
||||
|
||||
protected:
|
||||
void PollUdpProtocolEvents(void);
|
||||
void CheckInitialSync(void);
|
||||
|
||||
void OnUdpProtocolEvent(UdpProtocol::Event &e);
|
||||
|
||||
protected:
|
||||
GGPOSessionCallbacks _callbacks;
|
||||
Poll _poll;
|
||||
Udp _udp;
|
||||
UdpProtocol _host;
|
||||
bool _synchronizing;
|
||||
int _input_size;
|
||||
int _num_players;
|
||||
int _next_input_to_send;
|
||||
GameInput _inputs[SPECTATOR_FRAME_BUFFER_SIZE];
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,224 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
* GGPO.net (http://ggpo.net) - Copyright 2009 GroundStorm Studios, LLC.
|
||||
*
|
||||
* Use of this software is governed by the MIT license that can be found
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "synctest.h"
|
||||
|
||||
SyncTestBackend::SyncTestBackend(GGPOSessionCallbacks *cb,
|
||||
const char *gamename,
|
||||
int frames,
|
||||
int num_players) :
|
||||
_sync(NULL)
|
||||
{
|
||||
_callbacks = *cb;
|
||||
_num_players = num_players;
|
||||
_check_distance = frames;
|
||||
_last_verified = 0;
|
||||
_rollingback = false;
|
||||
_running = false;
|
||||
_logfp = NULL;
|
||||
_current_input.erase();
|
||||
strcpy(_game, gamename);
|
||||
|
||||
/*
|
||||
* Initialize the synchronziation layer
|
||||
*/
|
||||
Sync::Config config = { 0 };
|
||||
config.callbacks = _callbacks;
|
||||
config.num_prediction_frames = MAX_PREDICTION_FRAMES;
|
||||
_sync.Init(config);
|
||||
|
||||
/*
|
||||
* Preload the ROM
|
||||
*/
|
||||
_callbacks.begin_game(gamename);
|
||||
}
|
||||
|
||||
SyncTestBackend::~SyncTestBackend()
|
||||
{
|
||||
}
|
||||
|
||||
GGPOErrorCode
|
||||
SyncTestBackend::DoPoll(int timeout)
|
||||
{
|
||||
if (!_running) {
|
||||
GGPOEvent info;
|
||||
|
||||
info.code = GGPO_EVENTCODE_RUNNING;
|
||||
_callbacks.on_event(&info);
|
||||
_running = true;
|
||||
}
|
||||
return GGPO_OK;
|
||||
}
|
||||
|
||||
GGPOErrorCode
|
||||
SyncTestBackend::AddPlayer(GGPOPlayer *player, GGPOPlayerHandle *handle)
|
||||
{
|
||||
if (player->player_num < 1 || player->player_num > _num_players) {
|
||||
return GGPO_ERRORCODE_PLAYER_OUT_OF_RANGE;
|
||||
}
|
||||
*handle = (GGPOPlayerHandle)(player->player_num - 1);
|
||||
return GGPO_OK;
|
||||
}
|
||||
|
||||
GGPOErrorCode
|
||||
SyncTestBackend::AddLocalInput(GGPOPlayerHandle player, void *values, int size)
|
||||
{
|
||||
if (!_running) {
|
||||
return GGPO_ERRORCODE_NOT_SYNCHRONIZED;
|
||||
}
|
||||
|
||||
int index = (int)player;
|
||||
for (int i = 0; i < size; i++) {
|
||||
_current_input.bits[(index * size) + i] |= ((char *)values)[i];
|
||||
}
|
||||
return GGPO_OK;
|
||||
}
|
||||
|
||||
GGPOErrorCode
|
||||
SyncTestBackend::SyncInput(void *values,
|
||||
int size,
|
||||
int *disconnect_flags)
|
||||
{
|
||||
BeginLog(false);
|
||||
if (_rollingback) {
|
||||
_last_input = _saved_frames.front().input;
|
||||
} else {
|
||||
if (_sync.GetFrameCount() == 0 && _sync.GetLastSavedFrame().buf == nullptr) {
|
||||
_sync.SaveCurrentFrame();
|
||||
}
|
||||
_last_input = _current_input;
|
||||
}
|
||||
memcpy(values, _last_input.bits, size);
|
||||
if (disconnect_flags) {
|
||||
*disconnect_flags = 0;
|
||||
}
|
||||
return GGPO_OK;
|
||||
}
|
||||
|
||||
GGPOErrorCode
|
||||
SyncTestBackend::IncrementFrame(void)
|
||||
{
|
||||
_sync.IncrementFrame();
|
||||
_current_input.erase();
|
||||
|
||||
Log("End of frame(%d)...\n", _sync.GetFrameCount());
|
||||
EndLog();
|
||||
|
||||
if (_rollingback) {
|
||||
return GGPO_OK;
|
||||
}
|
||||
|
||||
int frame = _sync.GetFrameCount();
|
||||
// Hold onto the current frame in our queue of saved states. We'll need
|
||||
// the checksum later to verify that our replay of the same frame got the
|
||||
// same results.
|
||||
SavedInfo info;
|
||||
info.frame = frame;
|
||||
info.input = _last_input;
|
||||
info.cbuf = _sync.GetLastSavedFrame().cbuf;
|
||||
info.buf = (char *)malloc(info.cbuf);
|
||||
memcpy(info.buf, _sync.GetLastSavedFrame().buf, info.cbuf);
|
||||
info.checksum = _sync.GetLastSavedFrame().checksum;
|
||||
_saved_frames.push(info);
|
||||
|
||||
if (frame - _last_verified == _check_distance) {
|
||||
// We've gone far enough ahead and should now start replaying frames.
|
||||
// Load the last verified frame and set the rollback flag to true.
|
||||
_sync.LoadFrame(_last_verified);
|
||||
|
||||
_rollingback = true;
|
||||
while(!_saved_frames.empty()) {
|
||||
_callbacks.advance_frame(0);
|
||||
|
||||
// Verify that the checksumn of this frame is the same as the one in our
|
||||
// list.
|
||||
info = _saved_frames.front();
|
||||
_saved_frames.pop();
|
||||
|
||||
if (info.frame != _sync.GetFrameCount()) {
|
||||
RaiseSyncError("Frame number %d does not match saved frame number %d", info.frame, frame);
|
||||
}
|
||||
int checksum = _sync.GetLastSavedFrame().checksum;
|
||||
if (info.checksum != checksum) {
|
||||
LogSaveStates(info);
|
||||
RaiseSyncError("Checksum for frame %d does not match saved (%d != %d)", frame, checksum, info.checksum);
|
||||
}
|
||||
else
|
||||
printf("Checksum %08d for frame %d matches.\n", checksum, info.frame);
|
||||
free(info.buf);
|
||||
}
|
||||
_last_verified = frame;
|
||||
_rollingback = false;
|
||||
}
|
||||
|
||||
return GGPO_OK;
|
||||
}
|
||||
|
||||
void
|
||||
SyncTestBackend::RaiseSyncError(const char *fmt, ...)
|
||||
{
|
||||
char buf[1024];
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vsnprintf(buf, ARRAY_SIZE(buf), fmt, args);
|
||||
va_end(args);
|
||||
|
||||
puts(buf);
|
||||
#ifdef _WIN32
|
||||
OutputDebugStringA(buf);
|
||||
#endif
|
||||
EndLog();
|
||||
// DebugBreak();
|
||||
}
|
||||
|
||||
GGPOErrorCode
|
||||
SyncTestBackend::Logv(char *fmt, va_list list)
|
||||
{
|
||||
if (_logfp) {
|
||||
vfprintf(_logfp, fmt, list);
|
||||
}
|
||||
return GGPO_OK;
|
||||
}
|
||||
|
||||
void
|
||||
SyncTestBackend::BeginLog(int saving)
|
||||
{
|
||||
EndLog();
|
||||
|
||||
char filename[MAX_PATH];
|
||||
#ifdef _WIN32
|
||||
CreateDirectoryA("synclogs", NULL);
|
||||
#else
|
||||
mkdir("synclogs", 0755);
|
||||
#endif
|
||||
snprintf(filename, ARRAY_SIZE(filename), "synclogs/%s-%04d-%s.log",
|
||||
saving ? "state" : "log",
|
||||
_sync.GetFrameCount(),
|
||||
_rollingback ? "replay" : "original");
|
||||
|
||||
_logfp = fopen(filename, "w");
|
||||
}
|
||||
|
||||
void
|
||||
SyncTestBackend::EndLog()
|
||||
{
|
||||
if (_logfp) {
|
||||
fprintf(_logfp, "Closing log file.\n");
|
||||
fclose(_logfp);
|
||||
_logfp = NULL;
|
||||
}
|
||||
}
|
||||
void
|
||||
SyncTestBackend::LogSaveStates(SavedInfo &info)
|
||||
{
|
||||
char filename[MAX_PATH];
|
||||
snprintf(filename, ARRAY_SIZE(filename), "synclogs/state-%04d-original.log", _sync.GetFrameCount());
|
||||
_callbacks.log_game_state(filename, (unsigned char *)info.buf, info.cbuf);
|
||||
|
||||
snprintf(filename, ARRAY_SIZE(filename), "synclogs/state-%04d-replay.log", _sync.GetFrameCount());
|
||||
_callbacks.log_game_state(filename, _sync.GetLastSavedFrame().buf, _sync.GetLastSavedFrame().cbuf);
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
* GGPO.net (http://ggpo.net) - Copyright 2009 GroundStorm Studios, LLC.
|
||||
*
|
||||
* Use of this software is governed by the MIT license that can be found
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef _SYNCTEST_H
|
||||
#define _SYNCTEST_H
|
||||
|
||||
#include "ggpo_types.h"
|
||||
#include "backend.h"
|
||||
#include "sync.h"
|
||||
|
||||
#include "ring_buffer.h"
|
||||
|
||||
class SyncTestBackend : public IQuarkBackend {
|
||||
public:
|
||||
SyncTestBackend(GGPOSessionCallbacks *cb, const char *gamename, int frames, int num_players);
|
||||
virtual ~SyncTestBackend();
|
||||
|
||||
virtual GGPOErrorCode DoPoll(int timeout);
|
||||
virtual GGPOErrorCode AddPlayer(GGPOPlayer *player, GGPOPlayerHandle *handle);
|
||||
virtual GGPOErrorCode AddLocalInput(GGPOPlayerHandle player, void *values, int size);
|
||||
virtual GGPOErrorCode SyncInput(void *values, int size, int *disconnect_flags);
|
||||
virtual GGPOErrorCode IncrementFrame(void);
|
||||
virtual GGPOErrorCode Logv(char *fmt, va_list list);
|
||||
|
||||
protected:
|
||||
struct SavedInfo {
|
||||
int frame;
|
||||
int checksum;
|
||||
char *buf;
|
||||
int cbuf;
|
||||
GameInput input;
|
||||
};
|
||||
|
||||
void RaiseSyncError(const char *fmt, ...);
|
||||
void BeginLog(int saving);
|
||||
void EndLog();
|
||||
void LogSaveStates(SavedInfo &info);
|
||||
|
||||
protected:
|
||||
GGPOSessionCallbacks _callbacks;
|
||||
Sync _sync;
|
||||
int _num_players;
|
||||
int _check_distance;
|
||||
int _last_verified;
|
||||
bool _rollingback;
|
||||
bool _running;
|
||||
FILE *_logfp;
|
||||
char _game[128];
|
||||
|
||||
GameInput _current_input;
|
||||
GameInput _last_input;
|
||||
RingBuffer<SavedInfo, 32> _saved_frames;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
* GGPO.net (http://ggpo.net) - Copyright 2009 GroundStorm Studios, LLC.
|
||||
*
|
||||
* Use of this software is governed by the MIT license that can be found
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "ggpo_types.h"
|
||||
#include "bitvector.h"
|
||||
|
||||
void
|
||||
BitVector_SetBit(uint8 *vector, int *offset)
|
||||
{
|
||||
vector[(*offset) / 8] |= (1 << ((*offset) % 8));
|
||||
*offset += 1;
|
||||
}
|
||||
|
||||
void
|
||||
BitVector_ClearBit(uint8 *vector, int *offset)
|
||||
{
|
||||
vector[(*offset) / 8] &= ~(1 << ((*offset) % 8));
|
||||
*offset += 1;
|
||||
}
|
||||
|
||||
void
|
||||
BitVector_WriteNibblet(uint8 *vector, int nibble, int *offset)
|
||||
{
|
||||
ASSERT(nibble < (1 << BITVECTOR_NIBBLE_SIZE));
|
||||
for (int i = 0; i < BITVECTOR_NIBBLE_SIZE; i++) {
|
||||
if (nibble & (1 << i)) {
|
||||
BitVector_SetBit(vector, offset);
|
||||
} else {
|
||||
BitVector_ClearBit(vector, offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
BitVector_ReadBit(uint8 *vector, int *offset)
|
||||
{
|
||||
int retval = !!(vector[(*offset) / 8] & (1 << ((*offset) % 8)));
|
||||
*offset += 1;
|
||||
return retval;
|
||||
}
|
||||
|
||||
int
|
||||
BitVector_ReadNibblet(uint8 *vector, int *offset)
|
||||
{
|
||||
int nibblet = 0;
|
||||
for (int i = 0; i < BITVECTOR_NIBBLE_SIZE; i++) {
|
||||
nibblet |= (BitVector_ReadBit(vector, offset) << i);
|
||||
}
|
||||
return nibblet;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
* GGPO.net (http://ggpo.net) - Copyright 2009 GroundStorm Studios, LLC.
|
||||
*
|
||||
* Use of this software is governed by the MIT license that can be found
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef _BITVECTOR_H
|
||||
#define _BITVECTOR_H
|
||||
|
||||
#define BITVECTOR_NIBBLE_SIZE 8
|
||||
|
||||
void BitVector_SetBit(uint8 *vector, int *offset);
|
||||
void BitVector_ClearBit(uint8 *vector, int *offset);
|
||||
void BitVector_WriteNibblet(uint8 *vector, int nibble, int *offset);
|
||||
int BitVector_ReadBit(uint8 *vector, int *offset);
|
||||
int BitVector_ReadNibblet(uint8 *vector, int *offset);
|
||||
|
||||
#endif // _BITVECTOR_H
|
||||
@@ -0,0 +1,89 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
* GGPO.net (http://ggpo.net) - Copyright 2009 GroundStorm Studios, LLC.
|
||||
*
|
||||
* Use of this software is governed by the MIT license that can be found
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "game_input.h"
|
||||
|
||||
#include "ggpo_types.h"
|
||||
#include "log.h"
|
||||
|
||||
void
|
||||
GameInput::init(int iframe, char *ibits, int isize, int offset)
|
||||
{
|
||||
ASSERT(isize);
|
||||
ASSERT(isize <= GAMEINPUT_MAX_BYTES);
|
||||
frame = iframe;
|
||||
size = isize;
|
||||
memset(bits, 0, sizeof(bits));
|
||||
if (ibits) {
|
||||
memcpy(bits + (offset * isize), ibits, isize);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GameInput::init(int iframe, char *ibits, int isize)
|
||||
{
|
||||
ASSERT(isize);
|
||||
ASSERT(isize <= GAMEINPUT_MAX_BYTES * GAMEINPUT_MAX_PLAYERS);
|
||||
frame = iframe;
|
||||
size = isize;
|
||||
memset(bits, 0, sizeof(bits));
|
||||
if (ibits) {
|
||||
memcpy(bits, ibits, isize);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GameInput::desc(char *buf, size_t buf_size, bool show_frame) const
|
||||
{
|
||||
ASSERT(size);
|
||||
size_t remaining = buf_size;
|
||||
if (show_frame) {
|
||||
remaining -= snprintf(buf, buf_size, "(frame:%d size:%d ", frame, size);
|
||||
} else {
|
||||
remaining -= snprintf(buf, buf_size, "(size:%d ", size);
|
||||
}
|
||||
|
||||
for (int i = 0; i < size * 8; i++) {
|
||||
char buf2[16];
|
||||
if (value(i)) {
|
||||
int c = snprintf(buf2, ARRAY_SIZE(buf2), "%2d ", i);
|
||||
strncat(buf, buf2, ARRAY_SIZE(buf2));
|
||||
remaining -= c;
|
||||
}
|
||||
}
|
||||
strcat(buf, ")");
|
||||
}
|
||||
|
||||
void
|
||||
GameInput::log(char *prefix, bool show_frame) const
|
||||
{
|
||||
char buf[1024];
|
||||
size_t c = strlen(prefix);
|
||||
strcpy(buf, prefix);
|
||||
desc(buf + c, ARRAY_SIZE(buf) - c, show_frame);
|
||||
strcat(buf, "\n");
|
||||
Log(buf);
|
||||
}
|
||||
|
||||
bool
|
||||
GameInput::equal(GameInput &other, bool bitsonly)
|
||||
{
|
||||
if (!bitsonly && frame != other.frame) {
|
||||
Log("frames don't match: %d, %d\n", frame, other.frame);
|
||||
}
|
||||
if (size != other.size) {
|
||||
Log("sizes don't match: %d, %d\n", size, other.size);
|
||||
}
|
||||
if (memcmp(bits, other.bits, size)) {
|
||||
Log("bits don't match\n");
|
||||
}
|
||||
ASSERT(size && other.size);
|
||||
return (bitsonly || frame == other.frame) &&
|
||||
size == other.size &&
|
||||
memcmp(bits, other.bits, size) == 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
* GGPO.net (http://ggpo.net) - Copyright 2009 GroundStorm Studios, LLC.
|
||||
*
|
||||
* Use of this software is governed by the MIT license that can be found
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef _GAMEINPUT_H
|
||||
#define _GAMEINPUT_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <memory.h>
|
||||
|
||||
// GAMEINPUT_MAX_BYTES * GAMEINPUT_MAX_PLAYERS * 8 must be less than
|
||||
// 2^BITVECTOR_NIBBLE_SIZE (see bitvector.h)
|
||||
|
||||
#define GAMEINPUT_MAX_BYTES 9
|
||||
#define GAMEINPUT_MAX_PLAYERS 2
|
||||
|
||||
struct GameInput {
|
||||
enum Constants {
|
||||
NullFrame = -1
|
||||
};
|
||||
int frame;
|
||||
int size; /* size in bytes of the entire input for all players */
|
||||
char bits[GAMEINPUT_MAX_BYTES * GAMEINPUT_MAX_PLAYERS];
|
||||
|
||||
bool is_null() { return frame == NullFrame; }
|
||||
void init(int frame, char *bits, int size, int offset);
|
||||
void init(int frame, char *bits, int size);
|
||||
bool value(int i) const { return (bits[i/8] & (1 << (i%8))) != 0; }
|
||||
void set(int i) { bits[i/8] |= (1 << (i%8)); }
|
||||
void clear(int i) { bits[i/8] &= ~(1 << (i%8)); }
|
||||
void erase() { memset(bits, 0, sizeof(bits)); }
|
||||
void desc(char *buf, size_t buf_size, bool show_frame = true) const;
|
||||
void log(char *prefix, bool show_frame = true) const;
|
||||
bool equal(GameInput &input, bool bitsonly = false);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,66 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
* GGPO.net (http://ggpo.net) - Copyright 2009 GroundStorm Studios, LLC.
|
||||
*
|
||||
* Use of this software is governed by the MIT license that can be found
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef _POLL_H
|
||||
#define _POLL_H
|
||||
|
||||
#include "static_buffer.h"
|
||||
|
||||
#define MAX_POLLABLE_HANDLES 64
|
||||
|
||||
|
||||
class IPollSink {
|
||||
public:
|
||||
virtual ~IPollSink() { }
|
||||
virtual bool OnHandlePoll(void *) { return true; }
|
||||
virtual bool OnMsgPoll(void *) { return true; }
|
||||
virtual bool OnPeriodicPoll(void *, int ) { return true; }
|
||||
virtual bool OnLoopPoll(void *) { return true; }
|
||||
};
|
||||
|
||||
class Poll {
|
||||
public:
|
||||
Poll(void);
|
||||
// void RegisterHandle(IPollSink *sink, HANDLE h, void *cookie = NULL);
|
||||
void RegisterMsgLoop(IPollSink *sink, void *cookie = NULL);
|
||||
void RegisterPeriodic(IPollSink *sink, int interval, void *cookie = NULL);
|
||||
void RegisterLoop(IPollSink *sink, void *cookie = NULL);
|
||||
|
||||
void Run();
|
||||
bool Pump(int timeout);
|
||||
|
||||
protected:
|
||||
int ComputeWaitTime(int elapsed);
|
||||
|
||||
struct PollSinkCb {
|
||||
IPollSink *sink;
|
||||
void *cookie;
|
||||
PollSinkCb() : sink(NULL), cookie(NULL) { }
|
||||
PollSinkCb(IPollSink *s, void *c) : sink(s), cookie(c) { }
|
||||
};
|
||||
|
||||
struct PollPeriodicSinkCb : public PollSinkCb {
|
||||
int interval;
|
||||
int last_fired;
|
||||
PollPeriodicSinkCb() : PollSinkCb(NULL, NULL), interval(0), last_fired(0) { }
|
||||
PollPeriodicSinkCb(IPollSink *s, void *c, int i) :
|
||||
PollSinkCb(s, c), interval(i), last_fired(0) { }
|
||||
};
|
||||
|
||||
int _start_time;
|
||||
int _handle_count;
|
||||
#ifdef _WIN32
|
||||
HANDLE _handles[MAX_POLLABLE_HANDLES];
|
||||
#endif
|
||||
PollSinkCb _handle_sinks[MAX_POLLABLE_HANDLES];
|
||||
|
||||
StaticBuffer<PollSinkCb, 16> _msg_sinks;
|
||||
StaticBuffer<PollSinkCb, 16> _loop_sinks;
|
||||
StaticBuffer<PollPeriodicSinkCb, 16> _periodic_sinks;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,99 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
* GGPO.net (http://ggpo.net) - Copyright 2009 GroundStorm Studios, LLC.
|
||||
*
|
||||
* Use of this software is governed by the MIT license that can be found
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef _TYPES_H
|
||||
#define _TYPES_H
|
||||
/*
|
||||
* Keep the compiler happy
|
||||
*/
|
||||
|
||||
#ifdef _MSC_VER
|
||||
/*
|
||||
* Disable specific compiler warnings
|
||||
* 4018 - '<' : signed/unsigned mismatch
|
||||
* 4100 - 'xxx' : unreferenced formal parameter
|
||||
* 4127 - conditional expression is constant
|
||||
* 4201 - nonstandard extension used : nameless struct/union
|
||||
* 4389 - '!=' : signed/unsigned mismatch
|
||||
* 4800 - 'int' : forcing value to bool 'true' or 'false' (performance warning)
|
||||
*/
|
||||
#pragma warning(disable: 4018 4100 4127 4201 4389 4800)
|
||||
#endif
|
||||
|
||||
#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP)
|
||||
#define TARGET_UWP
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Simple types
|
||||
*/
|
||||
typedef unsigned char uint8;
|
||||
typedef unsigned short uint16;
|
||||
typedef unsigned int uint32;
|
||||
typedef unsigned char byte;
|
||||
typedef char int8;
|
||||
typedef short int16;
|
||||
typedef int int32;
|
||||
|
||||
#include "ggponet.h"
|
||||
#include <stdexcept>
|
||||
|
||||
class GGPOException : public std::runtime_error {
|
||||
public:
|
||||
GGPOException(const char *what, GGPOErrorCode ggpoError)
|
||||
: std::runtime_error(what), ggpoError(ggpoError) {}
|
||||
|
||||
GGPOErrorCode ggpoError;
|
||||
};
|
||||
|
||||
/*
|
||||
* Additional headers
|
||||
*/
|
||||
#if defined(_WIN32)
|
||||
# include "platform_windows.h"
|
||||
#elif defined(__unix__) || defined(__APPLE__) || defined(__SWITCH__)
|
||||
# include "platform_linux.h"
|
||||
#else
|
||||
# error Unsupported platform
|
||||
#endif
|
||||
|
||||
#include "log.h"
|
||||
|
||||
/*
|
||||
* Macros
|
||||
*/
|
||||
#define ASSERT(x) \
|
||||
do { \
|
||||
if (!(x)) { \
|
||||
char assert_buf[1024]; \
|
||||
snprintf(assert_buf, sizeof(assert_buf) - 1, "Assertion: %s @ %s:%d (pid:%ld)", #x, __FILE__, __LINE__, (long)GGPOPlatform::GetProcessID()); \
|
||||
Log("%s\n", assert_buf); \
|
||||
Log("\n"); \
|
||||
Log("\n"); \
|
||||
Log("\n"); \
|
||||
GGPOPlatform::AssertFailed(assert_buf); \
|
||||
exit(0); \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
#ifndef ARRAY_SIZE
|
||||
# define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
|
||||
#endif
|
||||
|
||||
#ifndef MAX_INT
|
||||
# define MAX_INT 0xEFFFFFF
|
||||
#endif
|
||||
|
||||
#ifndef MAX
|
||||
# define MAX(x, y) (((x) > (y)) ? (x) : (y))
|
||||
#endif
|
||||
|
||||
#ifndef MIN
|
||||
# define MIN(x, y) (((x) < (y)) ? (x) : (y))
|
||||
#endif
|
||||
|
||||
#endif // _TYPES_H
|
||||
@@ -0,0 +1,321 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
* GGPO.net (http://ggpo.net) - Copyright 2009 GroundStorm Studios, LLC.
|
||||
*
|
||||
* Use of this software is governed by the MIT license that can be found
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "input_queue.h"
|
||||
#include "ggpo_types.h"
|
||||
|
||||
#define PREVIOUS_FRAME(offset) (((offset) == 0) ? (INPUT_QUEUE_LENGTH - 1) : ((offset) - 1))
|
||||
|
||||
InputQueue::InputQueue(int input_size)
|
||||
{
|
||||
Init(-1, input_size);
|
||||
}
|
||||
|
||||
InputQueue::~InputQueue()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
InputQueue::Init(int id, int input_size)
|
||||
{
|
||||
_id = id;
|
||||
_head = 0;
|
||||
_tail = 0;
|
||||
_length = 0;
|
||||
_frame_delay = 0;
|
||||
_first_frame = true;
|
||||
_last_user_added_frame = GameInput::NullFrame;
|
||||
_first_incorrect_frame = GameInput::NullFrame;
|
||||
_last_frame_requested = GameInput::NullFrame;
|
||||
_last_added_frame = GameInput::NullFrame;
|
||||
|
||||
_prediction.init(GameInput::NullFrame, NULL, input_size);
|
||||
|
||||
/*
|
||||
* This is safe because we know the GameInput is a proper structure (as in,
|
||||
* no virtual methods, no contained classes, etc.).
|
||||
*/
|
||||
memset(_inputs, 0, sizeof _inputs);
|
||||
for (size_t i = 0; i < ARRAY_SIZE(_inputs); i++) {
|
||||
_inputs[i].size = input_size;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
InputQueue::GetLastConfirmedFrame()
|
||||
{
|
||||
Log("returning last confirmed frame %d.\n", _last_added_frame);
|
||||
return _last_added_frame;
|
||||
}
|
||||
|
||||
int
|
||||
InputQueue::GetFirstIncorrectFrame()
|
||||
{
|
||||
return _first_incorrect_frame;
|
||||
}
|
||||
|
||||
void
|
||||
InputQueue::DiscardConfirmedFrames(int frame)
|
||||
{
|
||||
ASSERT(frame >= 0);
|
||||
|
||||
if (_last_frame_requested != GameInput::NullFrame) {
|
||||
frame = MIN(frame, _last_frame_requested);
|
||||
}
|
||||
|
||||
Log("discarding confirmed frames up to %d (last_added:%d length:%d [head:%d tail:%d]).\n",
|
||||
frame, _last_added_frame, _length, _head, _tail);
|
||||
if (frame >= _last_added_frame) {
|
||||
_tail = _head;
|
||||
} else {
|
||||
int offset = frame - _inputs[_tail].frame + 1;
|
||||
|
||||
Log("difference of %d frames.\n", offset);
|
||||
ASSERT(offset >= 0);
|
||||
|
||||
_tail = (_tail + offset) % INPUT_QUEUE_LENGTH;
|
||||
_length -= offset;
|
||||
}
|
||||
|
||||
Log("after discarding, new tail is %d (frame:%d).\n", _tail, _inputs[_tail].frame);
|
||||
ASSERT(_length >= 0);
|
||||
}
|
||||
|
||||
void
|
||||
InputQueue::ResetPrediction(int frame)
|
||||
{
|
||||
ASSERT(_first_incorrect_frame == GameInput::NullFrame || frame <= _first_incorrect_frame);
|
||||
|
||||
Log("resetting all prediction errors back to frame %d.\n", frame);
|
||||
|
||||
/*
|
||||
* There's nothing really to do other than reset our prediction
|
||||
* state and the incorrect frame counter...
|
||||
*/
|
||||
_prediction.frame = GameInput::NullFrame;
|
||||
_first_incorrect_frame = GameInput::NullFrame;
|
||||
_last_frame_requested = GameInput::NullFrame;
|
||||
}
|
||||
|
||||
bool
|
||||
InputQueue::GetConfirmedInput(int requested_frame, GameInput *input)
|
||||
{
|
||||
ASSERT(_first_incorrect_frame == GameInput::NullFrame || requested_frame < _first_incorrect_frame);
|
||||
int offset = requested_frame % INPUT_QUEUE_LENGTH;
|
||||
if (_inputs[offset].frame != requested_frame) {
|
||||
return false;
|
||||
}
|
||||
*input = _inputs[offset];
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
InputQueue::GetInput(int requested_frame, GameInput *input)
|
||||
{
|
||||
Log("requesting input frame %d.\n", requested_frame);
|
||||
|
||||
/*
|
||||
* No one should ever try to grab any input when we have a prediction
|
||||
* error. Doing so means that we're just going further down the wrong
|
||||
* path. ASSERT this to verify that it's true.
|
||||
*/
|
||||
ASSERT(_first_incorrect_frame == GameInput::NullFrame);
|
||||
|
||||
/*
|
||||
* Remember the last requested frame number for later. We'll need
|
||||
* this in AddInput() to drop out of prediction mode.
|
||||
*/
|
||||
_last_frame_requested = requested_frame;
|
||||
|
||||
ASSERT(requested_frame >= _inputs[_tail].frame);
|
||||
|
||||
if (_prediction.frame == GameInput::NullFrame) {
|
||||
/*
|
||||
* If the frame requested is in our range, fetch it out of the queue and
|
||||
* return it.
|
||||
*/
|
||||
int offset = requested_frame - _inputs[_tail].frame;
|
||||
|
||||
if (offset < _length) {
|
||||
offset = (offset + _tail) % INPUT_QUEUE_LENGTH;
|
||||
ASSERT(_inputs[offset].frame == requested_frame);
|
||||
*input = _inputs[offset];
|
||||
Log("returning confirmed frame number %d.\n", input->frame);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* The requested frame isn't in the queue. Bummer. This means we need
|
||||
* to return a prediction frame. Predict that the user will do the
|
||||
* same thing they did last time.
|
||||
*/
|
||||
if (requested_frame == 0) {
|
||||
Log("basing new prediction frame from nothing, you're client wants frame 0.\n");
|
||||
_prediction.erase();
|
||||
} else if (_last_added_frame == GameInput::NullFrame) {
|
||||
Log("basing new prediction frame from nothing, since we have no frames yet.\n");
|
||||
_prediction.erase();
|
||||
} else {
|
||||
Log("basing new prediction frame from previously added frame (queue entry:%d, frame:%d).\n",
|
||||
PREVIOUS_FRAME(_head), _inputs[PREVIOUS_FRAME(_head)].frame);
|
||||
_prediction = _inputs[PREVIOUS_FRAME(_head)];
|
||||
}
|
||||
_prediction.frame++;
|
||||
}
|
||||
|
||||
ASSERT(_prediction.frame >= 0);
|
||||
|
||||
/*
|
||||
* If we've made it this far, we must be predicting. Go ahead and
|
||||
* forward the prediction frame contents. Be sure to return the
|
||||
* frame number requested by the client, though.
|
||||
*/
|
||||
*input = _prediction;
|
||||
input->frame = requested_frame;
|
||||
Log("returning prediction frame number %d (%d).\n", input->frame, _prediction.frame);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
InputQueue::AddInput(GameInput &input)
|
||||
{
|
||||
int new_frame;
|
||||
|
||||
Log("adding input frame number %d to queue.\n", input.frame);
|
||||
|
||||
/*
|
||||
* These next two lines simply verify that inputs are passed in
|
||||
* sequentially by the user, regardless of frame delay.
|
||||
*/
|
||||
ASSERT(_last_user_added_frame == GameInput::NullFrame ||
|
||||
input.frame == _last_user_added_frame + 1);
|
||||
_last_user_added_frame = input.frame;
|
||||
|
||||
/*
|
||||
* Move the queue head to the correct point in preparation to
|
||||
* input the frame into the queue.
|
||||
*/
|
||||
new_frame = AdvanceQueueHead(input.frame);
|
||||
if (new_frame != GameInput::NullFrame) {
|
||||
AddDelayedInputToQueue(input, new_frame);
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the frame number for the input. This will also set the
|
||||
* frame to GameInput::NullFrame for frames that get dropped (by
|
||||
* design).
|
||||
*/
|
||||
input.frame = new_frame;
|
||||
}
|
||||
|
||||
void
|
||||
InputQueue::AddDelayedInputToQueue(GameInput &input, int frame_number)
|
||||
{
|
||||
Log("adding delayed input frame number %d to queue.\n", frame_number);
|
||||
|
||||
if (input.size != _prediction.size)
|
||||
throw GGPOException("Input size differs from peer", GGPO_ERRORCODE_INPUT_SIZE_DIFF);
|
||||
|
||||
ASSERT(_last_added_frame == GameInput::NullFrame || frame_number == _last_added_frame + 1);
|
||||
|
||||
ASSERT(frame_number == 0 || _inputs[PREVIOUS_FRAME(_head)].frame == frame_number - 1);
|
||||
|
||||
/*
|
||||
* Add the frame to the back of the queue
|
||||
*/
|
||||
_inputs[_head] = input;
|
||||
_inputs[_head].frame = frame_number;
|
||||
_head = (_head + 1) % INPUT_QUEUE_LENGTH;
|
||||
_length++;
|
||||
_first_frame = false;
|
||||
|
||||
_last_added_frame = frame_number;
|
||||
|
||||
if (_prediction.frame != GameInput::NullFrame) {
|
||||
ASSERT(frame_number == _prediction.frame);
|
||||
|
||||
/*
|
||||
* We've been predicting... See if the inputs we've gotten match
|
||||
* what we've been predicting. If so, don't worry about it. If not,
|
||||
* remember the first input which was incorrect so we can report it
|
||||
* in GetFirstIncorrectFrame()
|
||||
*/
|
||||
if (_first_incorrect_frame == GameInput::NullFrame && !_prediction.equal(input, true)) {
|
||||
Log("frame %d does not match prediction. marking error.\n", frame_number);
|
||||
_first_incorrect_frame = frame_number;
|
||||
}
|
||||
|
||||
/*
|
||||
* If this input is the same frame as the last one requested and we
|
||||
* still haven't found any mis-predicted inputs, we can dump out
|
||||
* of predition mode entirely! Otherwise, advance the prediction frame
|
||||
* count up.
|
||||
*/
|
||||
if (_prediction.frame == _last_frame_requested && _first_incorrect_frame == GameInput::NullFrame) {
|
||||
Log("prediction is correct! dumping out of prediction mode.\n");
|
||||
_prediction.frame = GameInput::NullFrame;
|
||||
} else {
|
||||
_prediction.frame++;
|
||||
}
|
||||
}
|
||||
ASSERT(_length <= INPUT_QUEUE_LENGTH);
|
||||
}
|
||||
|
||||
int
|
||||
InputQueue::AdvanceQueueHead(int frame)
|
||||
{
|
||||
Log("advancing queue head to frame %d.\n", frame);
|
||||
|
||||
int expected_frame = _first_frame ? 0 : _inputs[PREVIOUS_FRAME(_head)].frame + 1;
|
||||
|
||||
frame += _frame_delay;
|
||||
|
||||
if (expected_frame > frame) {
|
||||
/*
|
||||
* This can occur when the frame delay has dropped since the last
|
||||
* time we shoved a frame into the system. In this case, there's
|
||||
* no room on the queue. Toss it.
|
||||
*/
|
||||
Log("Dropping input frame %d (expected next frame to be %d).\n",
|
||||
frame, expected_frame);
|
||||
return GameInput::NullFrame;
|
||||
}
|
||||
|
||||
while (expected_frame < frame) {
|
||||
/*
|
||||
* This can occur when the frame delay has been increased since the last
|
||||
* time we shoved a frame into the system. We need to replicate the
|
||||
* last frame in the queue several times in order to fill the space
|
||||
* left.
|
||||
*/
|
||||
Log("Adding padding frame %d to account for change in frame delay.\n",
|
||||
expected_frame);
|
||||
GameInput &last_frame = _inputs[PREVIOUS_FRAME(_head)];
|
||||
AddDelayedInputToQueue(last_frame, expected_frame);
|
||||
expected_frame++;
|
||||
}
|
||||
|
||||
ASSERT(frame == 0 || frame == _inputs[PREVIOUS_FRAME(_head)].frame + 1);
|
||||
return frame;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
InputQueue::Log(const char *fmt, ...)
|
||||
{
|
||||
char buf[1024];
|
||||
size_t offset;
|
||||
va_list args;
|
||||
|
||||
offset = snprintf(buf, ARRAY_SIZE(buf), "input q%d | ", _id);
|
||||
va_start(args, fmt);
|
||||
vsnprintf(buf + offset, ARRAY_SIZE(buf) - offset - 1, fmt, args);
|
||||
buf[ARRAY_SIZE(buf)-1] = '\0';
|
||||
::Log(buf);
|
||||
va_end(args);
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
* GGPO.net (http://ggpo.net) - Copyright 2009 GroundStorm Studios, LLC.
|
||||
*
|
||||
* Use of this software is governed by the MIT license that can be found
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef _INPUT_QUEUE_H
|
||||
#define _INPUT_QUEUE_H
|
||||
|
||||
#include "game_input.h"
|
||||
|
||||
#define INPUT_QUEUE_LENGTH 128
|
||||
#define DEFAULT_INPUT_SIZE 4
|
||||
|
||||
class InputQueue {
|
||||
public:
|
||||
InputQueue(int input_size = DEFAULT_INPUT_SIZE);
|
||||
~InputQueue();
|
||||
|
||||
public:
|
||||
void Init(int id, int input_size);
|
||||
int GetLastConfirmedFrame();
|
||||
int GetFirstIncorrectFrame();
|
||||
int GetLength() { return _length; }
|
||||
|
||||
void SetFrameDelay(int delay) { _frame_delay = delay; }
|
||||
void ResetPrediction(int frame);
|
||||
void DiscardConfirmedFrames(int frame);
|
||||
bool GetConfirmedInput(int frame, GameInput *input);
|
||||
bool GetInput(int frame, GameInput *input);
|
||||
void AddInput(GameInput &input);
|
||||
|
||||
protected:
|
||||
int AdvanceQueueHead(int frame);
|
||||
void AddDelayedInputToQueue(GameInput &input, int i);
|
||||
void Log(const char *fmt, ...);
|
||||
|
||||
protected:
|
||||
int _id;
|
||||
int _head;
|
||||
int _tail;
|
||||
int _length;
|
||||
bool _first_frame;
|
||||
|
||||
int _last_user_added_frame;
|
||||
int _last_added_frame;
|
||||
int _first_incorrect_frame;
|
||||
int _last_frame_requested;
|
||||
|
||||
int _frame_delay;
|
||||
|
||||
GameInput _inputs[INPUT_QUEUE_LENGTH];
|
||||
GameInput _prediction;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
* GGPO.net (http://ggpo.net) - Copyright 2009 GroundStorm Studios, LLC.
|
||||
*
|
||||
* Use of this software is governed by the MIT license that can be found
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "ggpo_types.h"
|
||||
#include "log/Log.h"
|
||||
#include "log/LogManager.h"
|
||||
#include <string>
|
||||
|
||||
void Log(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
Logv(fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void Logv(const char* fmt, va_list args)
|
||||
{
|
||||
std::string copy;
|
||||
if (fmt[strlen(fmt) - 1] == '\n') {
|
||||
copy = fmt;
|
||||
copy.pop_back();
|
||||
fmt = copy.c_str();
|
||||
}
|
||||
if (LogManager::GetInstance())
|
||||
LogManager::GetInstance()->Log(LogTypes::LDEBUG, LogTypes::NETWORK, __FILE__, __LINE__, fmt, args);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
* GGPO.net (http://ggpo.net) - Copyright 2009 GroundStorm Studios, LLC.
|
||||
*
|
||||
* Use of this software is governed by the MIT license that can be found
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef _LOG_H
|
||||
#define _LOG_H
|
||||
|
||||
extern void Log(const char *fmt, ...);
|
||||
extern void Logv(const char *fmt, va_list list);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,276 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
* GGPO.net (http://ggpo.net) - Copyright 2009 GroundStorm Studios, LLC.
|
||||
*
|
||||
* Use of this software is governed by the MIT license that can be found
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "backends/p2p.h"
|
||||
#include "backends/synctest.h"
|
||||
#include "backends/spectator.h"
|
||||
#include "ggpo_types.h"
|
||||
#include "ggponet.h"
|
||||
|
||||
struct Init
|
||||
{
|
||||
Init() {
|
||||
srand(GGPOPlatform::GetCurrentTimeMS() + GGPOPlatform::GetProcessID());
|
||||
#ifdef _WIN32
|
||||
WSADATA wsaData;
|
||||
WSAStartup(MAKEWORD(2, 0), &wsaData);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
static Init init;
|
||||
|
||||
void
|
||||
ggpo_log(GGPOSession *ggpo, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
ggpo_logv(ggpo, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void
|
||||
ggpo_logv(GGPOSession *ggpo, const char *fmt, va_list args)
|
||||
{
|
||||
if (ggpo)
|
||||
ggpo->Logv(fmt, args);
|
||||
}
|
||||
|
||||
GGPOErrorCode
|
||||
ggpo_start_session(GGPOSession **session,
|
||||
GGPOSessionCallbacks *cb,
|
||||
const char *game,
|
||||
int num_players,
|
||||
int input_size,
|
||||
unsigned short localport,
|
||||
const void *verification,
|
||||
int verification_size)
|
||||
{
|
||||
try {
|
||||
*session= (GGPOSession *)new Peer2PeerBackend(cb,
|
||||
game,
|
||||
localport,
|
||||
num_players,
|
||||
input_size,
|
||||
verification,
|
||||
verification_size);
|
||||
return GGPO_OK;
|
||||
} catch (const GGPOException& e) {
|
||||
Log("GGPOException in ggpo_start_session: %s", e.what());
|
||||
return e.ggpoError;
|
||||
}
|
||||
}
|
||||
|
||||
GGPOErrorCode
|
||||
ggpo_add_player(GGPOSession *ggpo,
|
||||
GGPOPlayer *player,
|
||||
GGPOPlayerHandle *handle)
|
||||
{
|
||||
if (!ggpo)
|
||||
return GGPO_ERRORCODE_INVALID_SESSION;
|
||||
try {
|
||||
return ggpo->AddPlayer(player, handle);
|
||||
} catch (const GGPOException& e) {
|
||||
Log("GGPOException in ggpo_add_player: %s", e.what());
|
||||
return e.ggpoError;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
GGPOErrorCode
|
||||
ggpo_start_synctest(GGPOSession **ggpo,
|
||||
GGPOSessionCallbacks *cb,
|
||||
const char *game,
|
||||
int num_players,
|
||||
int input_size,
|
||||
int frames)
|
||||
{
|
||||
try {
|
||||
*ggpo = (GGPOSession *)new SyncTestBackend(cb, game, frames, num_players);
|
||||
return GGPO_OK;
|
||||
} catch (const GGPOException& e) {
|
||||
Log("GGPOException in ggpo_start_synctest: %s", e.what());
|
||||
return e.ggpoError;
|
||||
}
|
||||
}
|
||||
|
||||
GGPOErrorCode
|
||||
ggpo_set_frame_delay(GGPOSession *ggpo,
|
||||
GGPOPlayerHandle player,
|
||||
int frame_delay)
|
||||
{
|
||||
if (!ggpo)
|
||||
return GGPO_ERRORCODE_INVALID_SESSION;
|
||||
try {
|
||||
return ggpo->SetFrameDelay(player, frame_delay);
|
||||
} catch (const GGPOException& e) {
|
||||
Log("GGPOException in ggpo_set_frame_delay: %s", e.what());
|
||||
return e.ggpoError;
|
||||
}
|
||||
}
|
||||
|
||||
GGPOErrorCode
|
||||
ggpo_idle(GGPOSession *ggpo, int timeout)
|
||||
{
|
||||
if (!ggpo)
|
||||
return GGPO_ERRORCODE_INVALID_SESSION;
|
||||
try {
|
||||
return ggpo->DoPoll(timeout);
|
||||
} catch (const GGPOException& e) {
|
||||
Log("GGPOException in ggpo_idle: %s", e.what());
|
||||
return e.ggpoError;
|
||||
}
|
||||
}
|
||||
|
||||
GGPOErrorCode
|
||||
ggpo_add_local_input(GGPOSession *ggpo,
|
||||
GGPOPlayerHandle player,
|
||||
void *values,
|
||||
int size)
|
||||
{
|
||||
if (!ggpo)
|
||||
return GGPO_ERRORCODE_INVALID_SESSION;
|
||||
try {
|
||||
return ggpo->AddLocalInput(player, values, size);
|
||||
} catch (const GGPOException& e) {
|
||||
Log("GGPOException in ggpo_add_local_input: %s", e.what());
|
||||
return e.ggpoError;
|
||||
}
|
||||
}
|
||||
|
||||
GGPOErrorCode
|
||||
ggpo_synchronize_input(GGPOSession *ggpo,
|
||||
void *values,
|
||||
int size,
|
||||
int *disconnect_flags)
|
||||
{
|
||||
if (!ggpo)
|
||||
return GGPO_ERRORCODE_INVALID_SESSION;
|
||||
try {
|
||||
return ggpo->SyncInput(values, size, disconnect_flags);
|
||||
} catch (const GGPOException& e) {
|
||||
Log("GGPOException in ggpo_synchronize_input: %s", e.what());
|
||||
return e.ggpoError;
|
||||
}
|
||||
}
|
||||
|
||||
GGPOErrorCode ggpo_disconnect_player(GGPOSession *ggpo,
|
||||
GGPOPlayerHandle player)
|
||||
{
|
||||
if (!ggpo)
|
||||
return GGPO_ERRORCODE_INVALID_SESSION;
|
||||
try {
|
||||
return ggpo->DisconnectPlayer(player);
|
||||
} catch (const GGPOException& e) {
|
||||
Log("GGPOException in ggpo_disconnect_player: %s", e.what());
|
||||
return e.ggpoError;
|
||||
}
|
||||
}
|
||||
|
||||
GGPOErrorCode
|
||||
ggpo_advance_frame(GGPOSession *ggpo)
|
||||
{
|
||||
if (!ggpo)
|
||||
return GGPO_ERRORCODE_INVALID_SESSION;
|
||||
try {
|
||||
return ggpo->IncrementFrame();
|
||||
} catch (const GGPOException& e) {
|
||||
Log("GGPOException in ggpo_advance_frame: %s", e.what());
|
||||
return e.ggpoError;
|
||||
}
|
||||
}
|
||||
|
||||
GGPOErrorCode
|
||||
ggpo_get_network_stats(GGPOSession *ggpo,
|
||||
GGPOPlayerHandle player,
|
||||
GGPONetworkStats *stats)
|
||||
{
|
||||
if (!ggpo)
|
||||
return GGPO_ERRORCODE_INVALID_SESSION;
|
||||
try {
|
||||
return ggpo->GetNetworkStats(stats, player);
|
||||
} catch (const GGPOException& e) {
|
||||
Log("GGPOException in ggpo_get_network_stats: %s", e.what());
|
||||
return e.ggpoError;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
GGPOErrorCode
|
||||
ggpo_close_session(GGPOSession *ggpo)
|
||||
{
|
||||
if (!ggpo) {
|
||||
return GGPO_ERRORCODE_INVALID_SESSION;
|
||||
}
|
||||
delete ggpo;
|
||||
return GGPO_OK;
|
||||
}
|
||||
|
||||
GGPOErrorCode
|
||||
ggpo_set_disconnect_timeout(GGPOSession *ggpo, int timeout)
|
||||
{
|
||||
if (!ggpo)
|
||||
return GGPO_ERRORCODE_INVALID_SESSION;
|
||||
try {
|
||||
return ggpo->SetDisconnectTimeout(timeout);
|
||||
} catch (const GGPOException& e) {
|
||||
Log("GGPOException in ggpo_set_disconnect_timeout: %s", e.what());
|
||||
return e.ggpoError;
|
||||
}
|
||||
}
|
||||
|
||||
GGPOErrorCode
|
||||
ggpo_set_disconnect_notify_start(GGPOSession *ggpo, int timeout)
|
||||
{
|
||||
if (!ggpo)
|
||||
return GGPO_ERRORCODE_INVALID_SESSION;
|
||||
try {
|
||||
return ggpo->SetDisconnectNotifyStart(timeout);
|
||||
} catch (const GGPOException& e) {
|
||||
Log("GGPOException in ggpo_set_disconnect_notify_start: %s", e.what());
|
||||
return e.ggpoError;
|
||||
}
|
||||
}
|
||||
|
||||
GGPOErrorCode ggpo_start_spectating(GGPOSession **session,
|
||||
GGPOSessionCallbacks *cb,
|
||||
const char *game,
|
||||
int num_players,
|
||||
int input_size,
|
||||
unsigned short local_port,
|
||||
char *host_ip,
|
||||
unsigned short host_port,
|
||||
const void *verification,
|
||||
int verification_size)
|
||||
{
|
||||
try {
|
||||
*session= (GGPOSession *)new SpectatorBackend(cb,
|
||||
game,
|
||||
local_port,
|
||||
num_players,
|
||||
input_size,
|
||||
host_ip,
|
||||
host_port,
|
||||
verification,
|
||||
verification_size);
|
||||
return GGPO_OK;
|
||||
} catch (const GGPOException& e) {
|
||||
Log("GGPOException in ggpo_start_spectating: %s", e.what());
|
||||
return e.ggpoError;
|
||||
}
|
||||
}
|
||||
|
||||
GGPOErrorCode ggpo_send_message(GGPOSession *ggpo,
|
||||
const void *msg,
|
||||
int len,
|
||||
bool spectators)
|
||||
{
|
||||
if (ggpo == nullptr)
|
||||
return GGPO_ERRORCODE_INVALID_SESSION;
|
||||
return ggpo->SendMessage(msg, len, spectators);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
* GGPO.net (http://ggpo.net) - Copyright 2009 GroundStorm Studios, LLC.
|
||||
*
|
||||
* Use of this software is governed by the MIT license that can be found
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "ggpo_types.h"
|
||||
#include "udp.h"
|
||||
|
||||
SOCKET
|
||||
CreateSocket(uint16 bind_port, int retries)
|
||||
{
|
||||
SOCKET s;
|
||||
sockaddr_in sin;
|
||||
uint16 port;
|
||||
int optval = 1;
|
||||
|
||||
s = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char *)&optval, sizeof optval);
|
||||
optval = 0;
|
||||
setsockopt(s, SOL_SOCKET, SO_LINGER, (const char *)&optval, sizeof optval);
|
||||
|
||||
// non-blocking...
|
||||
#ifndef _WIN32
|
||||
fcntl(s, F_SETFL, O_NONBLOCK);
|
||||
#else
|
||||
u_long iMode = 1;
|
||||
ioctlsocket(s, FIONBIO, &iMode);
|
||||
#endif
|
||||
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
for (port = bind_port; port <= bind_port + retries; port++) {
|
||||
sin.sin_port = htons(port);
|
||||
if (bind(s, (sockaddr *)&sin, sizeof sin) == 0) {
|
||||
Log("Udp bound to port: %d.\n", port);
|
||||
return s;
|
||||
}
|
||||
}
|
||||
closesocket(s);
|
||||
return INVALID_SOCKET;
|
||||
}
|
||||
|
||||
Udp::Udp() :
|
||||
_socket(INVALID_SOCKET),
|
||||
_callbacks(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
Udp::~Udp(void)
|
||||
{
|
||||
if (_socket != INVALID_SOCKET) {
|
||||
closesocket(_socket);
|
||||
_socket = INVALID_SOCKET;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Udp::Init(uint16 port, Poll *poll, Callbacks *callbacks)
|
||||
{
|
||||
_callbacks = callbacks;
|
||||
poll->RegisterLoop(this);
|
||||
|
||||
Log("binding udp socket to port %d.\n", port);
|
||||
_socket = CreateSocket(port, 0);
|
||||
if (_socket == INVALID_SOCKET)
|
||||
throw GGPOException("Socket creation or bind failed", GGPO_ERRORCODE_NETWORK_ERROR);
|
||||
}
|
||||
|
||||
void
|
||||
Udp::SendTo(char *buffer, int len, int flags, struct sockaddr *dst, int destlen)
|
||||
{
|
||||
struct sockaddr_in *to = (struct sockaddr_in *)dst;
|
||||
|
||||
int res = sendto(_socket, buffer, len, flags, dst, destlen);
|
||||
if (res == SOCKET_ERROR) {
|
||||
int err = WSAGetLastError();
|
||||
Log("unknown error in sendto (erro: %d wsaerr: %d).\n", res, err);
|
||||
ASSERT(false && "Unknown error in sendto");
|
||||
}
|
||||
char dst_ip[1024];
|
||||
Log("sent packet length %d to %s:%d (ret:%d).\n", len, inet_ntop(AF_INET, (void *)&to->sin_addr, dst_ip, ARRAY_SIZE(dst_ip)), ntohs(to->sin_port), res);
|
||||
}
|
||||
|
||||
bool
|
||||
Udp::OnLoopPoll(void *cookie)
|
||||
{
|
||||
uint8 recv_buf[MAX_UDP_PACKET_SIZE];
|
||||
sockaddr_in recv_addr;
|
||||
socklen_t recv_addr_len;
|
||||
|
||||
for (;;) {
|
||||
recv_addr_len = sizeof(recv_addr);
|
||||
int len = recvfrom(_socket, (char *)recv_buf, MAX_UDP_PACKET_SIZE, 0, (struct sockaddr *)&recv_addr, &recv_addr_len);
|
||||
|
||||
// TODO: handle len == 0... indicates a disconnect.
|
||||
|
||||
if (len == -1) {
|
||||
int error = WSAGetLastError();
|
||||
if (error != WSAEWOULDBLOCK) {
|
||||
Log("recvfrom WSAGetLastError returned %d (%x).\n", error, error);
|
||||
}
|
||||
break;
|
||||
} else if (len > 0) {
|
||||
char src_ip[1024];
|
||||
Log("recvfrom returned (len:%d from:%s:%d).\n", len, inet_ntop(AF_INET, (void*)&recv_addr.sin_addr, src_ip, ARRAY_SIZE(src_ip)), ntohs(recv_addr.sin_port) );
|
||||
UdpMsg *msg = (UdpMsg *)recv_buf;
|
||||
_callbacks->OnMsg(recv_addr, msg, len);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Udp::Log(const char *fmt, ...)
|
||||
{
|
||||
char buf[1024];
|
||||
size_t offset;
|
||||
va_list args;
|
||||
|
||||
strcpy(buf, "udp | ");
|
||||
offset = strlen(buf);
|
||||
va_start(args, fmt);
|
||||
vsnprintf(buf + offset, ARRAY_SIZE(buf) - offset - 1, fmt, args);
|
||||
buf[ARRAY_SIZE(buf)-1] = '\0';
|
||||
::Log(buf);
|
||||
va_end(args);
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
* GGPO.net (http://ggpo.net) - Copyright 2009 GroundStorm Studios, LLC.
|
||||
*
|
||||
* Use of this software is governed by the MIT license that can be found
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef _UDP_H
|
||||
#define _UDP_H
|
||||
|
||||
#include "ggpo_poll.h"
|
||||
#include "udp_msg.h"
|
||||
#include "ggponet.h"
|
||||
#include "ring_buffer.h"
|
||||
|
||||
#define MAX_UDP_ENDPOINTS 16
|
||||
|
||||
constexpr size_t MAX_UDP_PACKET_SIZE = sizeof(UdpMsg);
|
||||
|
||||
class Udp : public IPollSink
|
||||
{
|
||||
public:
|
||||
struct Stats {
|
||||
int bytes_sent;
|
||||
int packets_sent;
|
||||
float kbps_sent;
|
||||
};
|
||||
|
||||
struct Callbacks {
|
||||
virtual ~Callbacks() { }
|
||||
virtual void OnMsg(sockaddr_in &from, UdpMsg *msg, int len) = 0;
|
||||
};
|
||||
|
||||
|
||||
protected:
|
||||
void Log(const char *fmt, ...);
|
||||
|
||||
public:
|
||||
Udp();
|
||||
|
||||
void Init(uint16 port, Poll *p, Callbacks *callbacks);
|
||||
|
||||
void SendTo(char *buffer, int len, int flags, struct sockaddr *dst, int destlen);
|
||||
|
||||
virtual bool OnLoopPoll(void *cookie);
|
||||
|
||||
public:
|
||||
~Udp(void);
|
||||
|
||||
protected:
|
||||
// Network transmission information
|
||||
SOCKET _socket;
|
||||
|
||||
// state management
|
||||
Callbacks *_callbacks;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,121 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
* GGPO.net (http://ggpo.net) - Copyright 2009 GroundStorm Studios, LLC.
|
||||
*
|
||||
* Use of this software is governed by the MIT license that can be found
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef _UDP_MSG_H
|
||||
#define _UDP_MSG_H
|
||||
|
||||
#define MAX_COMPRESSED_BITS 4096
|
||||
#define UDP_MSG_MAX_PLAYERS 4
|
||||
#define MAX_VERIFICATION_SIZE 256
|
||||
#define MAX_APPDATA_SIZE 512
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
struct UdpMsg
|
||||
{
|
||||
enum MsgType {
|
||||
Invalid = 0,
|
||||
SyncRequest = 1,
|
||||
SyncReply = 2,
|
||||
Input = 3,
|
||||
QualityReport = 4,
|
||||
QualityReply = 5,
|
||||
KeepAlive = 6,
|
||||
InputAck = 7,
|
||||
AppData = 8
|
||||
};
|
||||
|
||||
struct connect_status {
|
||||
unsigned int disconnected:1;
|
||||
int last_frame:31;
|
||||
};
|
||||
|
||||
struct {
|
||||
uint16 magic;
|
||||
uint16 sequence_number;
|
||||
uint8 type; /* packet type */
|
||||
} hdr;
|
||||
union {
|
||||
struct {
|
||||
uint32 random_request; /* please reply back with this random data */
|
||||
uint16 remote_magic;
|
||||
uint8 remote_endpoint;
|
||||
uint8 verification[MAX_VERIFICATION_SIZE];
|
||||
} sync_request;
|
||||
|
||||
struct {
|
||||
uint32 random_reply; /* OK, here's your random data back */
|
||||
uint8 verification_failure; /* set to one by peer if verification failed */
|
||||
} sync_reply;
|
||||
|
||||
struct {
|
||||
int8 frame_advantage; /* what's the other guy's frame advantage? */
|
||||
uint32 ping;
|
||||
} quality_report;
|
||||
|
||||
struct {
|
||||
uint32 pong;
|
||||
} quality_reply;
|
||||
|
||||
struct {
|
||||
connect_status peer_connect_status[UDP_MSG_MAX_PLAYERS];
|
||||
|
||||
uint32 start_frame;
|
||||
|
||||
int disconnect_requested:1;
|
||||
int ack_frame:31;
|
||||
|
||||
uint16 num_bits;
|
||||
uint8 input_size; // XXX: shouldn't be in every single packet!
|
||||
uint8 bits[MAX_COMPRESSED_BITS / 8]; /* must be last */
|
||||
} input;
|
||||
|
||||
struct {
|
||||
int ack_frame:31;
|
||||
} input_ack;
|
||||
|
||||
struct {
|
||||
uint16 size;
|
||||
uint8 spectators;
|
||||
uint8 data[MAX_APPDATA_SIZE];
|
||||
} app_data;
|
||||
|
||||
} u;
|
||||
|
||||
int verification_size = 0;
|
||||
|
||||
public:
|
||||
int PacketSize() {
|
||||
return sizeof(hdr) + PayloadSize();
|
||||
}
|
||||
|
||||
int PayloadSize() {
|
||||
switch (hdr.type) {
|
||||
case SyncRequest: return (int)(&u.sync_request.verification[0] - (uint8 *)&u) + verification_size;
|
||||
case SyncReply: return sizeof(u.sync_reply);
|
||||
case QualityReport: return sizeof(u.quality_report);
|
||||
case QualityReply: return sizeof(u.quality_reply);
|
||||
case InputAck: return sizeof(u.input_ack);
|
||||
case KeepAlive: return 0;
|
||||
case Input:
|
||||
{
|
||||
int size = (int)((char *)&u.input.bits - (char *)&u.input);
|
||||
size += (u.input.num_bits + 7) / 8;
|
||||
return size;
|
||||
}
|
||||
case AppData: return sizeof(u.app_data) - sizeof(u.app_data.data) + u.app_data.size;
|
||||
}
|
||||
ASSERT(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
UdpMsg(MsgType t) { hdr.type = (uint8)t; }
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,830 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
* GGPO.net (http://ggpo.net) - Copyright 2009 GroundStorm Studios, LLC.
|
||||
*
|
||||
* Use of this software is governed by the MIT license that can be found
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "udp_proto.h"
|
||||
|
||||
#include "../ggpo_types.h"
|
||||
#include "bitvector.h"
|
||||
|
||||
static const int UDP_HEADER_SIZE = 28; /* Size of IP + UDP headers */
|
||||
static const int NUM_SYNC_PACKETS = 5;
|
||||
static const int SYNC_RETRY_INTERVAL = 2000;
|
||||
static const int SYNC_FIRST_RETRY_INTERVAL = 500;
|
||||
static const int RUNNING_RETRY_INTERVAL = 200;
|
||||
static const int KEEP_ALIVE_INTERVAL = 200;
|
||||
static const int QUALITY_REPORT_INTERVAL = 1000;
|
||||
static const int NETWORK_STATS_INTERVAL = 1000;
|
||||
static const int UDP_SHUTDOWN_TIMER = 5000;
|
||||
static const int MAX_SEQ_DISTANCE = (1 << 15);
|
||||
|
||||
UdpProtocol::UdpProtocol() :
|
||||
_udp(NULL),
|
||||
_magic_number(0),
|
||||
_queue(-1),
|
||||
_remote_magic_number(0),
|
||||
_connected(false),
|
||||
_packets_sent(0),
|
||||
_bytes_sent(0),
|
||||
_stats_start_time(0),
|
||||
_local_frame_advantage(0),
|
||||
_remote_frame_advantage(0),
|
||||
_last_send_time(0),
|
||||
_shutdown_timeout(0),
|
||||
_disconnect_event_sent(false),
|
||||
_disconnect_timeout(0),
|
||||
_disconnect_notify_start(0),
|
||||
_disconnect_notify_sent(false),
|
||||
_next_send_seq(0),
|
||||
_next_recv_seq(0)
|
||||
{
|
||||
_last_sent_input.init(-1, NULL, 1);
|
||||
_last_received_input.init(-1, NULL, 1);
|
||||
_last_acked_input.init(-1, NULL, 1);
|
||||
|
||||
memset(&_state, 0, sizeof _state);
|
||||
memset(_peer_connect_status, 0, sizeof(_peer_connect_status));
|
||||
for (unsigned i = 0; i < ARRAY_SIZE(_peer_connect_status); i++) {
|
||||
_peer_connect_status[i].last_frame = -1;
|
||||
}
|
||||
memset(&_peer_addr, 0, sizeof _peer_addr);
|
||||
_oo_packet.msg = NULL;
|
||||
|
||||
_send_latency = GGPOPlatform::GetConfigInt("GGPO_NETWORK_DELAY");
|
||||
_oop_percent = GGPOPlatform::GetConfigInt("GGPO_OOP_PERCENT");
|
||||
}
|
||||
|
||||
UdpProtocol::~UdpProtocol()
|
||||
{
|
||||
ClearSendQueue();
|
||||
}
|
||||
|
||||
void
|
||||
UdpProtocol::Init(Udp *udp,
|
||||
Poll &poll,
|
||||
int queue,
|
||||
char *ip,
|
||||
u_short port,
|
||||
UdpMsg::connect_status *status)
|
||||
{
|
||||
_udp = udp;
|
||||
_queue = queue;
|
||||
_local_connect_status = status;
|
||||
|
||||
_peer_addr.sin_family = AF_INET;
|
||||
if (ip != nullptr && ip[0] != '\0')
|
||||
{
|
||||
_peer_addr.sin_port = htons(port);
|
||||
inet_pton(AF_INET, ip, &_peer_addr.sin_addr.s_addr);
|
||||
}
|
||||
|
||||
do {
|
||||
_magic_number = (uint16)rand();
|
||||
} while (_magic_number == 0);
|
||||
poll.RegisterLoop(this);
|
||||
}
|
||||
|
||||
void
|
||||
UdpProtocol::SendInput(GameInput &input)
|
||||
{
|
||||
if (_udp) {
|
||||
if (_current_state == Running) {
|
||||
/*
|
||||
* Check to see if this is a good time to adjust for the rift...
|
||||
*/
|
||||
_timesync.advance_frame(input, _local_frame_advantage, _remote_frame_advantage);
|
||||
|
||||
/*
|
||||
* Save this input packet
|
||||
*
|
||||
* XXX: This queue may fill up for spectators who do not ack input packets in a timely
|
||||
* manner. When this happens, we can either resize the queue (ug) or disconnect them
|
||||
* (better, but still ug). For the meantime, make this queue really big to decrease
|
||||
* the odds of this happening...
|
||||
*/
|
||||
_pending_output.push(input);
|
||||
}
|
||||
SendPendingOutput();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
UdpProtocol::SendPendingOutput()
|
||||
{
|
||||
UdpMsg *msg = new UdpMsg(UdpMsg::Input);
|
||||
int i, j, offset = 0;
|
||||
uint8 *bits;
|
||||
GameInput last;
|
||||
|
||||
if (_pending_output.size()) {
|
||||
last = _last_acked_input;
|
||||
bits = msg->u.input.bits;
|
||||
|
||||
msg->u.input.start_frame = _pending_output.front().frame;
|
||||
msg->u.input.input_size = (uint8)_pending_output.front().size;
|
||||
|
||||
ASSERT(last.frame == -1 || last.frame + 1 == (int)msg->u.input.start_frame);
|
||||
for (j = 0; j < _pending_output.size(); j++) {
|
||||
GameInput ¤t = _pending_output.item(j);
|
||||
if (memcmp(current.bits, last.bits, current.size) != 0) {
|
||||
ASSERT((GAMEINPUT_MAX_BYTES * GAMEINPUT_MAX_PLAYERS * 8) < (1 << BITVECTOR_NIBBLE_SIZE));
|
||||
for (i = 0; i < current.size * 8; i++) {
|
||||
ASSERT(i < (1 << BITVECTOR_NIBBLE_SIZE));
|
||||
if (current.value(i) != last.value(i)) {
|
||||
BitVector_SetBit(msg->u.input.bits, &offset);
|
||||
(current.value(i) ? BitVector_SetBit : BitVector_ClearBit)(bits, &offset);
|
||||
BitVector_WriteNibblet(bits, i, &offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
BitVector_ClearBit(msg->u.input.bits, &offset);
|
||||
last = _last_sent_input = current;
|
||||
}
|
||||
} else {
|
||||
msg->u.input.start_frame = 0;
|
||||
msg->u.input.input_size = 0;
|
||||
}
|
||||
msg->u.input.ack_frame = _last_received_input.frame;
|
||||
msg->u.input.num_bits = (uint16)offset;
|
||||
|
||||
msg->u.input.disconnect_requested = _current_state == Disconnected;
|
||||
if (_local_connect_status) {
|
||||
memcpy(msg->u.input.peer_connect_status, _local_connect_status, sizeof(UdpMsg::connect_status) * UDP_MSG_MAX_PLAYERS);
|
||||
} else {
|
||||
memset(msg->u.input.peer_connect_status, 0, sizeof(UdpMsg::connect_status) * UDP_MSG_MAX_PLAYERS);
|
||||
}
|
||||
|
||||
ASSERT(offset < MAX_COMPRESSED_BITS);
|
||||
|
||||
SendMsg(msg);
|
||||
}
|
||||
|
||||
void
|
||||
UdpProtocol::SendInputAck()
|
||||
{
|
||||
UdpMsg *msg = new UdpMsg(UdpMsg::InputAck);
|
||||
msg->u.input_ack.ack_frame = _last_received_input.frame;
|
||||
SendMsg(msg);
|
||||
}
|
||||
|
||||
bool
|
||||
UdpProtocol::GetEvent(UdpProtocol::Event &e)
|
||||
{
|
||||
if (_event_queue.size() == 0) {
|
||||
return false;
|
||||
}
|
||||
e = _event_queue.front();
|
||||
_event_queue.pop();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
UdpProtocol::OnLoopPoll(void *cookie)
|
||||
{
|
||||
if (!_udp) {
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned int now = GGPOPlatform::GetCurrentTimeMS();
|
||||
unsigned int next_interval;
|
||||
|
||||
PumpSendQueue();
|
||||
switch (_current_state) {
|
||||
case Syncing:
|
||||
next_interval = (_state.sync.roundtrips_remaining == NUM_SYNC_PACKETS) ? SYNC_FIRST_RETRY_INTERVAL : SYNC_RETRY_INTERVAL;
|
||||
if (_last_send_time && _last_send_time + next_interval < now && _peer_addr.sin_addr.s_addr != 0) {
|
||||
Log("No luck syncing after %d ms... Re-queueing sync packet.\n", next_interval);
|
||||
SendSyncRequest();
|
||||
}
|
||||
break;
|
||||
|
||||
case Running:
|
||||
// xxx: rig all this up with a timer wrapper
|
||||
if (!_state.running.last_input_packet_recv_time || _state.running.last_input_packet_recv_time + RUNNING_RETRY_INTERVAL < now) {
|
||||
Log("Haven't exchanged packets in a while (last received:%d last sent:%d). Resending.\n", _last_received_input.frame, _last_sent_input.frame);
|
||||
SendPendingOutput();
|
||||
_state.running.last_input_packet_recv_time = now;
|
||||
}
|
||||
|
||||
if (!_state.running.last_quality_report_time || _state.running.last_quality_report_time + QUALITY_REPORT_INTERVAL < now) {
|
||||
UdpMsg *msg = new UdpMsg(UdpMsg::QualityReport);
|
||||
msg->u.quality_report.ping = GGPOPlatform::GetCurrentTimeMS();
|
||||
msg->u.quality_report.frame_advantage = (uint8)_local_frame_advantage;
|
||||
SendMsg(msg);
|
||||
_state.running.last_quality_report_time = now;
|
||||
}
|
||||
|
||||
if (!_state.running.last_network_stats_interval || _state.running.last_network_stats_interval + NETWORK_STATS_INTERVAL < now) {
|
||||
UpdateNetworkStats();
|
||||
_state.running.last_network_stats_interval = now;
|
||||
}
|
||||
|
||||
if (_last_send_time && _last_send_time + KEEP_ALIVE_INTERVAL < now) {
|
||||
Log("Sending keep alive packet\n");
|
||||
SendMsg(new UdpMsg(UdpMsg::KeepAlive));
|
||||
}
|
||||
|
||||
if (_disconnect_timeout && _disconnect_notify_start &&
|
||||
!_disconnect_notify_sent && (_last_recv_time + _disconnect_notify_start < now)) {
|
||||
Log("Endpoint has stopped receiving packets for %d ms. Sending notification.\n", _disconnect_notify_start);
|
||||
Event e(Event::NetworkInterrupted);
|
||||
e.u.network_interrupted.disconnect_timeout = _disconnect_timeout - _disconnect_notify_start;
|
||||
QueueEvent(e);
|
||||
_disconnect_notify_sent = true;
|
||||
}
|
||||
|
||||
if (_disconnect_timeout && (_last_recv_time + _disconnect_timeout < now)) {
|
||||
if (!_disconnect_event_sent) {
|
||||
Log("Endpoint has stopped receiving packets for %d ms. Disconnecting.\n", _disconnect_timeout);
|
||||
QueueEvent(Event(Event::Disconnected));
|
||||
_disconnect_event_sent = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Disconnected:
|
||||
if (_shutdown_timeout < now) {
|
||||
Log("Shutting down udp connection.\n");
|
||||
_udp = NULL;
|
||||
_shutdown_timeout = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
UdpProtocol::Disconnect()
|
||||
{
|
||||
_current_state = Disconnected;
|
||||
_shutdown_timeout = GGPOPlatform::GetCurrentTimeMS() + UDP_SHUTDOWN_TIMER;
|
||||
}
|
||||
|
||||
void
|
||||
UdpProtocol::SendSyncRequest()
|
||||
{
|
||||
_state.sync.random = rand() & 0xFFFF;
|
||||
UdpMsg *msg = new UdpMsg(UdpMsg::SyncRequest);
|
||||
msg->u.sync_request.random_request = _state.sync.random;
|
||||
msg->verification_size = verification.size();
|
||||
if (!verification.empty())
|
||||
memcpy(&msg->u.sync_request.verification[0], &verification[0], verification.size());
|
||||
SendMsg(msg);
|
||||
}
|
||||
|
||||
void
|
||||
UdpProtocol::SendMsg(UdpMsg *msg)
|
||||
{
|
||||
LogMsg("send", msg);
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_send_mutex);
|
||||
_packets_sent++;
|
||||
_last_send_time = GGPOPlatform::GetCurrentTimeMS();
|
||||
_bytes_sent += msg->PacketSize();
|
||||
|
||||
msg->hdr.magic = _magic_number;
|
||||
msg->hdr.sequence_number = _next_send_seq++;
|
||||
|
||||
_send_queue.push(QueueEntry(GGPOPlatform::GetCurrentTimeMS(), _peer_addr, msg));
|
||||
}
|
||||
PumpSendQueue();
|
||||
}
|
||||
|
||||
bool
|
||||
UdpProtocol::HandlesMsg(sockaddr_in &from,
|
||||
UdpMsg *msg)
|
||||
{
|
||||
if (!_udp) {
|
||||
return false;
|
||||
}
|
||||
if (_peer_addr.sin_addr.s_addr == 0)
|
||||
{
|
||||
_peer_addr.sin_addr.s_addr = from.sin_addr.s_addr;
|
||||
_peer_addr.sin_port = from.sin_port;
|
||||
return true;
|
||||
}
|
||||
return _peer_addr.sin_addr.s_addr == from.sin_addr.s_addr &&
|
||||
_peer_addr.sin_port == from.sin_port;
|
||||
}
|
||||
|
||||
void
|
||||
UdpProtocol::OnMsg(UdpMsg *msg, int len)
|
||||
{
|
||||
bool handled = false;
|
||||
typedef bool (UdpProtocol::*DispatchFn)(UdpMsg *msg, int len);
|
||||
static const DispatchFn table[] = {
|
||||
&UdpProtocol::OnInvalid, /* Invalid */
|
||||
&UdpProtocol::OnSyncRequest, /* SyncRequest */
|
||||
&UdpProtocol::OnSyncReply, /* SyncReply */
|
||||
&UdpProtocol::OnInput, /* Input */
|
||||
&UdpProtocol::OnQualityReport, /* QualityReport */
|
||||
&UdpProtocol::OnQualityReply, /* QualityReply */
|
||||
&UdpProtocol::OnKeepAlive, /* KeepAlive */
|
||||
&UdpProtocol::OnInputAck, /* InputAck */
|
||||
&UdpProtocol::OnAppData, /* AppData */
|
||||
};
|
||||
|
||||
// filter out messages that don't match what we expect
|
||||
uint16 seq = msg->hdr.sequence_number;
|
||||
if (msg->hdr.type != UdpMsg::SyncRequest &&
|
||||
msg->hdr.type != UdpMsg::SyncReply) {
|
||||
if (msg->hdr.magic != _remote_magic_number) {
|
||||
LogMsg("recv rejecting", msg);
|
||||
return;
|
||||
}
|
||||
|
||||
// filter out out-of-order packets
|
||||
uint16 skipped = (uint16)((int)seq - (int)_next_recv_seq);
|
||||
// Log("checking sequence number -> next - seq : %d - %d = %d\n", seq, _next_recv_seq, skipped);
|
||||
if (skipped > MAX_SEQ_DISTANCE) {
|
||||
Log("dropping out of order packet (seq: %d, last seq:%d)\n", seq, _next_recv_seq);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
_next_recv_seq = seq;
|
||||
LogMsg("recv", msg);
|
||||
if (msg->hdr.type >= ARRAY_SIZE(table)) {
|
||||
OnInvalid(msg, len);
|
||||
} else {
|
||||
handled = (this->*(table[msg->hdr.type]))(msg, len);
|
||||
}
|
||||
if (handled) {
|
||||
_last_recv_time = GGPOPlatform::GetCurrentTimeMS();
|
||||
if (_disconnect_notify_sent && _current_state == Running) {
|
||||
QueueEvent(Event(Event::NetworkResumed));
|
||||
_disconnect_notify_sent = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
UdpProtocol::UpdateNetworkStats(void)
|
||||
{
|
||||
int now = GGPOPlatform::GetCurrentTimeMS();
|
||||
|
||||
if (_stats_start_time == 0) {
|
||||
_stats_start_time = now;
|
||||
}
|
||||
|
||||
int total_bytes_sent = _bytes_sent + (UDP_HEADER_SIZE * _packets_sent);
|
||||
float seconds = (float)((now - _stats_start_time) / 1000.0);
|
||||
float Bps = total_bytes_sent / seconds;
|
||||
float udp_overhead = (float)(100.0 * (UDP_HEADER_SIZE * _packets_sent) / _bytes_sent);
|
||||
|
||||
_kbps_sent = int(Bps / 1024);
|
||||
|
||||
Log("Network Stats -- Bandwidth: %.2f KBps Packets Sent: %5d (%.2f pps) "
|
||||
"KB Sent: %.2f UDP Overhead: %.2f %%.\n",
|
||||
_kbps_sent,
|
||||
_packets_sent,
|
||||
(float)_packets_sent * 1000 / (now - _stats_start_time),
|
||||
total_bytes_sent / 1024.0,
|
||||
udp_overhead);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
UdpProtocol::QueueEvent(const UdpProtocol::Event &evt)
|
||||
{
|
||||
LogEvent("Queuing event", evt);
|
||||
_event_queue.push(evt);
|
||||
}
|
||||
|
||||
void
|
||||
UdpProtocol::Synchronize()
|
||||
{
|
||||
if (_udp) {
|
||||
_current_state = Syncing;
|
||||
_state.sync.roundtrips_remaining = NUM_SYNC_PACKETS;
|
||||
if (_peer_addr.sin_addr.s_addr != 0)
|
||||
SendSyncRequest();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
UdpProtocol::GetPeerConnectStatus(int id, int *frame)
|
||||
{
|
||||
*frame = _peer_connect_status[id].last_frame;
|
||||
return !_peer_connect_status[id].disconnected;
|
||||
}
|
||||
|
||||
void
|
||||
UdpProtocol::Log(const char *fmt, ...)
|
||||
{
|
||||
char buf[1024];
|
||||
size_t offset;
|
||||
va_list args;
|
||||
|
||||
snprintf(buf, ARRAY_SIZE(buf), "udpproto%d | ", _queue);
|
||||
offset = strlen(buf);
|
||||
va_start(args, fmt);
|
||||
vsnprintf(buf + offset, ARRAY_SIZE(buf) - offset - 1, fmt, args);
|
||||
buf[ARRAY_SIZE(buf)-1] = '\0';
|
||||
::Log(buf);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void
|
||||
UdpProtocol::LogMsg(const char *prefix, UdpMsg *msg)
|
||||
{
|
||||
switch (msg->hdr.type) {
|
||||
case UdpMsg::SyncRequest:
|
||||
Log("%s sync-request (%d).\n", prefix,
|
||||
msg->u.sync_request.random_request);
|
||||
break;
|
||||
case UdpMsg::SyncReply:
|
||||
Log("%s sync-reply (%d).\n", prefix,
|
||||
msg->u.sync_reply.random_reply);
|
||||
break;
|
||||
case UdpMsg::QualityReport:
|
||||
Log("%s quality report.\n", prefix);
|
||||
break;
|
||||
case UdpMsg::QualityReply:
|
||||
Log("%s quality reply.\n", prefix);
|
||||
break;
|
||||
case UdpMsg::KeepAlive:
|
||||
Log("%s keep alive.\n", prefix);
|
||||
break;
|
||||
case UdpMsg::Input:
|
||||
Log("%s game-compressed-input %d (+ %d bits).\n", prefix, msg->u.input.start_frame, msg->u.input.num_bits);
|
||||
break;
|
||||
case UdpMsg::InputAck:
|
||||
Log("%s input ack.\n", prefix);
|
||||
break;
|
||||
case UdpMsg::AppData:
|
||||
Log("%s app data (%d bytes).\n", prefix, msg->u.app_data.size);
|
||||
break;
|
||||
default:
|
||||
ASSERT(false && "Unknown UdpMsg type.");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
UdpProtocol::LogEvent(const char *prefix, const UdpProtocol::Event &evt)
|
||||
{
|
||||
if (evt.type == UdpProtocol::Event::Synchronzied)
|
||||
Log("%s (event: Synchronzied).\n", prefix);
|
||||
}
|
||||
|
||||
bool
|
||||
UdpProtocol::OnInvalid(UdpMsg *msg, int len)
|
||||
{
|
||||
ASSERT(false && "Invalid msg in UdpProtocol");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
UdpProtocol::OnSyncRequest(UdpMsg *msg, int len)
|
||||
{
|
||||
if (_remote_magic_number != 0 && msg->hdr.magic != _remote_magic_number) {
|
||||
Log("Ignoring sync request from unknown endpoint (%d != %d).\n",
|
||||
msg->hdr.magic, _remote_magic_number);
|
||||
return false;
|
||||
}
|
||||
UdpMsg *reply = new UdpMsg(UdpMsg::SyncReply);
|
||||
reply->u.sync_reply.random_reply = msg->u.sync_request.random_request;
|
||||
// Calculate incoming verif data size
|
||||
msg->verification_size = 0;
|
||||
int msgVerifSize = len - msg->PacketSize();
|
||||
if (msgVerifSize != (int)verification.size()
|
||||
|| (msgVerifSize != 0 && memcmp(&msg->u.sync_request.verification[0], &verification[0], msgVerifSize)))
|
||||
{
|
||||
Log("Verification mismatch: size received %d expected %d", msgVerifSize, (int)verification.size());
|
||||
reply->u.sync_reply.verification_failure = 1;
|
||||
SendMsg(reply);
|
||||
throw GGPOException("Verification mismatch", GGPO_ERRORCODE_VERIFICATION_ERROR);
|
||||
}
|
||||
// FIXME
|
||||
if (_state.sync.roundtrips_remaining == NUM_SYNC_PACKETS && msg->hdr.sequence_number == 0) {
|
||||
Log("Sync request 0 received... Re-queueing sync packet.\n");
|
||||
SendSyncRequest();
|
||||
}
|
||||
|
||||
reply->u.sync_reply.verification_failure = 0;
|
||||
SendMsg(reply);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
UdpProtocol::OnSyncReply(UdpMsg *msg, int len)
|
||||
{
|
||||
if (_current_state != Syncing) {
|
||||
Log("Ignoring SyncReply while not synching.\n");
|
||||
return msg->hdr.magic == _remote_magic_number;
|
||||
}
|
||||
|
||||
if (msg->u.sync_reply.random_reply != _state.sync.random) {
|
||||
Log("sync reply %d != %d. Keep looking...\n",
|
||||
msg->u.sync_reply.random_reply, _state.sync.random);
|
||||
return false;
|
||||
}
|
||||
if (msg->u.sync_reply.verification_failure == 1)
|
||||
throw GGPOException("Peer reported verification failure", GGPO_ERRORCODE_VERIFICATION_ERROR);
|
||||
|
||||
if (!_connected) {
|
||||
QueueEvent(Event(Event::Connected));
|
||||
_connected = true;
|
||||
}
|
||||
|
||||
Log("Checking sync state (%d round trips remaining).\n", _state.sync.roundtrips_remaining);
|
||||
if (--_state.sync.roundtrips_remaining == 0) {
|
||||
Log("Synchronized!\n");
|
||||
QueueEvent(UdpProtocol::Event(UdpProtocol::Event::Synchronzied));
|
||||
_current_state = Running;
|
||||
_last_received_input.frame = -1;
|
||||
_remote_magic_number = msg->hdr.magic;
|
||||
} else {
|
||||
UdpProtocol::Event evt(UdpProtocol::Event::Synchronizing);
|
||||
evt.u.synchronizing.total = NUM_SYNC_PACKETS;
|
||||
evt.u.synchronizing.count = NUM_SYNC_PACKETS - _state.sync.roundtrips_remaining;
|
||||
QueueEvent(evt);
|
||||
SendSyncRequest();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
UdpProtocol::OnInput(UdpMsg *msg, int len)
|
||||
{
|
||||
/*
|
||||
* If a disconnect is requested, go ahead and disconnect now.
|
||||
*/
|
||||
bool disconnect_requested = msg->u.input.disconnect_requested;
|
||||
if (disconnect_requested) {
|
||||
if (_current_state != Disconnected && !_disconnect_event_sent) {
|
||||
Log("Disconnecting endpoint on remote request.\n");
|
||||
QueueEvent(Event(Event::Disconnected));
|
||||
_disconnect_event_sent = true;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Update the peer connection status if this peer is still considered to be part
|
||||
* of the network.
|
||||
*/
|
||||
UdpMsg::connect_status* remote_status = msg->u.input.peer_connect_status;
|
||||
for (unsigned i = 0; i < ARRAY_SIZE(_peer_connect_status); i++) {
|
||||
ASSERT(remote_status[i].last_frame >= _peer_connect_status[i].last_frame);
|
||||
_peer_connect_status[i].disconnected = _peer_connect_status[i].disconnected || remote_status[i].disconnected;
|
||||
_peer_connect_status[i].last_frame = MAX(_peer_connect_status[i].last_frame, remote_status[i].last_frame);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Decompress the input.
|
||||
*/
|
||||
int last_received_frame_number = _last_received_input.frame;
|
||||
if (msg->u.input.num_bits) {
|
||||
int offset = 0;
|
||||
uint8 *bits = (uint8 *)msg->u.input.bits;
|
||||
int numBits = msg->u.input.num_bits;
|
||||
int currentFrame = msg->u.input.start_frame;
|
||||
|
||||
_last_received_input.size = msg->u.input.input_size;
|
||||
if (_last_received_input.frame < 0) {
|
||||
_last_received_input.frame = msg->u.input.start_frame - 1;
|
||||
}
|
||||
while (offset < numBits) {
|
||||
/*
|
||||
* Keep walking through the frames (parsing bits) until we reach
|
||||
* the inputs for the frame right after the one we're on.
|
||||
*/
|
||||
ASSERT(currentFrame <= (_last_received_input.frame + 1));
|
||||
bool useInputs = currentFrame == _last_received_input.frame + 1;
|
||||
|
||||
while (BitVector_ReadBit(bits, &offset)) {
|
||||
int on = BitVector_ReadBit(bits, &offset);
|
||||
int button = BitVector_ReadNibblet(bits, &offset);
|
||||
if (useInputs) {
|
||||
if (on) {
|
||||
_last_received_input.set(button);
|
||||
} else {
|
||||
_last_received_input.clear(button);
|
||||
}
|
||||
}
|
||||
}
|
||||
ASSERT(offset <= numBits);
|
||||
|
||||
/*
|
||||
* Now if we want to use these inputs, go ahead and send them to
|
||||
* the emulator.
|
||||
*/
|
||||
if (useInputs) {
|
||||
/*
|
||||
* Move forward 1 frame in the stream.
|
||||
*/
|
||||
char desc[1024];
|
||||
ASSERT(currentFrame == _last_received_input.frame + 1);
|
||||
_last_received_input.frame = currentFrame;
|
||||
|
||||
/*
|
||||
* Send the event to the emualtor
|
||||
*/
|
||||
UdpProtocol::Event evt(UdpProtocol::Event::Input);
|
||||
evt.u.input.input = _last_received_input;
|
||||
|
||||
_last_received_input.desc(desc, ARRAY_SIZE(desc));
|
||||
|
||||
_state.running.last_input_packet_recv_time = GGPOPlatform::GetCurrentTimeMS();
|
||||
|
||||
Log("Sending frame %d to emu queue %d (%s).\n", _last_received_input.frame, _queue, desc);
|
||||
QueueEvent(evt);
|
||||
|
||||
} else {
|
||||
Log("Skipping past frame:(%d) current is %d.\n", currentFrame, _last_received_input.frame);
|
||||
}
|
||||
|
||||
/*
|
||||
* Move forward 1 frame in the input stream.
|
||||
*/
|
||||
currentFrame++;
|
||||
}
|
||||
}
|
||||
ASSERT(_last_received_input.frame >= last_received_frame_number);
|
||||
|
||||
/*
|
||||
* Get rid of our buffered input
|
||||
*/
|
||||
while (_pending_output.size() && _pending_output.front().frame < msg->u.input.ack_frame) {
|
||||
Log("Throwing away pending output frame %d\n", _pending_output.front().frame);
|
||||
_last_acked_input = _pending_output.front();
|
||||
_pending_output.pop();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
UdpProtocol::OnInputAck(UdpMsg *msg, int len)
|
||||
{
|
||||
/*
|
||||
* Get rid of our buffered input
|
||||
*/
|
||||
while (_pending_output.size() && _pending_output.front().frame < msg->u.input_ack.ack_frame) {
|
||||
Log("Throwing away pending output frame %d\n", _pending_output.front().frame);
|
||||
_last_acked_input = _pending_output.front();
|
||||
_pending_output.pop();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
UdpProtocol::OnQualityReport(UdpMsg *msg, int len)
|
||||
{
|
||||
// send a reply so the other side can compute the round trip transmit time.
|
||||
UdpMsg *reply = new UdpMsg(UdpMsg::QualityReply);
|
||||
reply->u.quality_reply.pong = msg->u.quality_report.ping;
|
||||
SendMsg(reply);
|
||||
|
||||
_remote_frame_advantage = msg->u.quality_report.frame_advantage;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
UdpProtocol::OnQualityReply(UdpMsg *msg, int len)
|
||||
{
|
||||
_round_trip_time = GGPOPlatform::GetCurrentTimeMS() - msg->u.quality_reply.pong;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
UdpProtocol::OnKeepAlive(UdpMsg *msg, int len)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
UdpProtocol::GetNetworkStats(struct GGPONetworkStats *s)
|
||||
{
|
||||
s->network.ping = _round_trip_time;
|
||||
s->network.send_queue_len = _pending_output.size();
|
||||
s->network.kbps_sent = _kbps_sent;
|
||||
s->timesync.remote_frames_behind = _remote_frame_advantage;
|
||||
s->timesync.local_frames_behind = _local_frame_advantage;
|
||||
}
|
||||
|
||||
void
|
||||
UdpProtocol::SetLocalFrameNumber(int localFrame)
|
||||
{
|
||||
/*
|
||||
* Estimate which frame the other guy is one by looking at the
|
||||
* last frame they gave us plus some delta for the one-way packet
|
||||
* trip time.
|
||||
*/
|
||||
int remoteFrame = _last_received_input.frame + (_round_trip_time * 60 / 1000);
|
||||
|
||||
/*
|
||||
* Our frame advantage is how many frames *behind* the other guy
|
||||
* we are. Counter-intuative, I know. It's an advantage because
|
||||
* it means they'll have to predict more often and our moves will
|
||||
* pop more frequenetly.
|
||||
*/
|
||||
_local_frame_advantage = remoteFrame - localFrame;
|
||||
}
|
||||
|
||||
int
|
||||
UdpProtocol::RecommendFrameDelay()
|
||||
{
|
||||
// XXX: require idle input should be a configuration parameter
|
||||
return _timesync.recommend_frame_wait_duration(false);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
UdpProtocol::SetDisconnectTimeout(int timeout)
|
||||
{
|
||||
_disconnect_timeout = timeout;
|
||||
}
|
||||
|
||||
void
|
||||
UdpProtocol::SetDisconnectNotifyStart(int timeout)
|
||||
{
|
||||
_disconnect_notify_start = timeout;
|
||||
}
|
||||
|
||||
void
|
||||
UdpProtocol::PumpSendQueue()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_send_mutex);
|
||||
while (!_send_queue.empty()) {
|
||||
QueueEntry &entry = _send_queue.front();
|
||||
|
||||
if (_send_latency) {
|
||||
// should really come up with a gaussian distributation based on the configured
|
||||
// value, but this will do for now.
|
||||
int jitter = (_send_latency * 2 / 3) + ((rand() % _send_latency) / 3);
|
||||
if ((int)GGPOPlatform::GetCurrentTimeMS() < _send_queue.front().queue_time + jitter) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (_oop_percent && !_oo_packet.msg && ((rand() % 100) < _oop_percent)) {
|
||||
int delay = rand() % (_send_latency * 10 + 1000);
|
||||
Log("creating rogue oop (seq: %d delay: %d)\n", entry.msg->hdr.sequence_number, delay);
|
||||
_oo_packet.send_time = GGPOPlatform::GetCurrentTimeMS() + delay;
|
||||
_oo_packet.msg = entry.msg;
|
||||
_oo_packet.dest_addr = entry.dest_addr;
|
||||
} else {
|
||||
ASSERT(entry.dest_addr.sin_addr.s_addr);
|
||||
|
||||
_udp->SendTo((char *)entry.msg, entry.msg->PacketSize(), 0,
|
||||
(struct sockaddr *)&entry.dest_addr, sizeof entry.dest_addr);
|
||||
|
||||
delete entry.msg;
|
||||
}
|
||||
_send_queue.pop();
|
||||
}
|
||||
if (_oo_packet.msg && _oo_packet.send_time < (int)GGPOPlatform::GetCurrentTimeMS()) {
|
||||
Log("sending rogue oop!");
|
||||
_udp->SendTo((char *)_oo_packet.msg, _oo_packet.msg->PacketSize(), 0,
|
||||
(struct sockaddr *)&_oo_packet.dest_addr, sizeof _oo_packet.dest_addr);
|
||||
|
||||
delete _oo_packet.msg;
|
||||
_oo_packet.msg = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
UdpProtocol::ClearSendQueue()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_send_mutex);
|
||||
while (!_send_queue.empty()) {
|
||||
delete _send_queue.front().msg;
|
||||
_send_queue.pop();
|
||||
}
|
||||
}
|
||||
|
||||
void UdpProtocol::SendAppData(const void *data, int len, bool spectators)
|
||||
{
|
||||
if (_udp == nullptr)
|
||||
return;
|
||||
if (_current_state != Synchronzied && _current_state != Running)
|
||||
return;
|
||||
|
||||
UdpMsg *msg = new UdpMsg(UdpMsg::AppData);
|
||||
msg->u.app_data.spectators = spectators;
|
||||
msg->u.app_data.size = len;
|
||||
memcpy(msg->u.app_data.data, data, len);
|
||||
|
||||
SendMsg(msg);
|
||||
}
|
||||
|
||||
bool UdpProtocol::OnAppData(UdpMsg *msg, int len)
|
||||
{
|
||||
UdpProtocol::Event evt(UdpProtocol::Event::AppData);
|
||||
evt.u.app_data.spectators = msg->u.app_data.spectators != 0;
|
||||
evt.u.app_data.size = msg->u.app_data.size;
|
||||
memcpy(evt.u.app_data.data, msg->u.app_data.data, msg->u.app_data.size);
|
||||
QueueEvent(evt);
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,224 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
* GGPO.net (http://ggpo.net) - Copyright 2009 GroundStorm Studios, LLC.
|
||||
*
|
||||
* Use of this software is governed by the MIT license that can be found
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef _UDP_PROTO_H_
|
||||
#define _UDP_PROTO_H_
|
||||
|
||||
#include "ggpo_poll.h"
|
||||
#include "udp.h"
|
||||
#include "udp_msg.h"
|
||||
#include "game_input.h"
|
||||
#include "timesync.h"
|
||||
#include "ggponet.h"
|
||||
#include "ring_buffer.h"
|
||||
#include <vector>
|
||||
#include <mutex>
|
||||
|
||||
class UdpProtocol : public IPollSink
|
||||
{
|
||||
public:
|
||||
struct Stats {
|
||||
int ping;
|
||||
int remote_frame_advantage;
|
||||
int local_frame_advantage;
|
||||
int send_queue_len;
|
||||
Udp::Stats udp;
|
||||
};
|
||||
|
||||
struct Event {
|
||||
enum Type {
|
||||
Unknown = -1,
|
||||
Connected,
|
||||
Synchronizing,
|
||||
Synchronzied,
|
||||
Input,
|
||||
Disconnected,
|
||||
NetworkInterrupted,
|
||||
NetworkResumed,
|
||||
AppData,
|
||||
};
|
||||
|
||||
Type type;
|
||||
union {
|
||||
struct {
|
||||
GameInput input;
|
||||
} input;
|
||||
struct {
|
||||
int total;
|
||||
int count;
|
||||
} synchronizing;
|
||||
struct {
|
||||
int disconnect_timeout;
|
||||
} network_interrupted;
|
||||
struct {
|
||||
bool spectators;
|
||||
int size;
|
||||
uint8 data[MAX_APPDATA_SIZE];
|
||||
} app_data;
|
||||
} u;
|
||||
|
||||
Event(Type t = Unknown) : type(t) { }
|
||||
};
|
||||
|
||||
public:
|
||||
virtual bool OnLoopPoll(void *cookie);
|
||||
|
||||
public:
|
||||
UdpProtocol();
|
||||
virtual ~UdpProtocol();
|
||||
|
||||
void Init(Udp *udp, Poll &p, int queue, char *ip, u_short port, UdpMsg::connect_status *status);
|
||||
|
||||
void Synchronize();
|
||||
bool GetPeerConnectStatus(int id, int *frame);
|
||||
bool IsInitialized() { return _udp != NULL; }
|
||||
bool IsSynchronized() { return _current_state == Running; }
|
||||
bool IsRunning() { return _current_state == Running; }
|
||||
void SendInput(GameInput &input);
|
||||
void SendInputAck();
|
||||
bool HandlesMsg(sockaddr_in &from, UdpMsg *msg);
|
||||
void OnMsg(UdpMsg *msg, int len);
|
||||
void Disconnect();
|
||||
void SendAppData(const void *data, int len, bool spectators);
|
||||
|
||||
void GetNetworkStats(struct GGPONetworkStats *stats);
|
||||
bool GetEvent(UdpProtocol::Event &e);
|
||||
void GGPONetworkStats(Stats *stats);
|
||||
void SetLocalFrameNumber(int num);
|
||||
int RecommendFrameDelay();
|
||||
void SetVerificationData(const void *verification, int verification_size) {
|
||||
ASSERT(verification_size <= MAX_VERIFICATION_SIZE);
|
||||
this->verification.resize(verification_size);
|
||||
memcpy(&this->verification[0], verification, verification_size);
|
||||
}
|
||||
|
||||
void SetDisconnectTimeout(int timeout);
|
||||
void SetDisconnectNotifyStart(int timeout);
|
||||
|
||||
protected:
|
||||
enum State {
|
||||
Syncing,
|
||||
Synchronzied,
|
||||
Running,
|
||||
Disconnected
|
||||
};
|
||||
struct QueueEntry {
|
||||
int queue_time;
|
||||
sockaddr_in dest_addr;
|
||||
UdpMsg *msg;
|
||||
|
||||
QueueEntry() {}
|
||||
QueueEntry(int time, sockaddr_in &dst, UdpMsg *m) : queue_time(time), dest_addr(dst), msg(m) { }
|
||||
};
|
||||
|
||||
bool CreateSocket(int retries);
|
||||
void UpdateNetworkStats(void);
|
||||
void QueueEvent(const UdpProtocol::Event &evt);
|
||||
void ClearSendQueue(void);
|
||||
void Log(const char *fmt, ...);
|
||||
void LogMsg(const char *prefix, UdpMsg *msg);
|
||||
void LogEvent(const char *prefix, const UdpProtocol::Event &evt);
|
||||
void SendSyncRequest();
|
||||
void SendMsg(UdpMsg *msg);
|
||||
void PumpSendQueue();
|
||||
void SendPendingOutput();
|
||||
bool OnInvalid(UdpMsg *msg, int len);
|
||||
bool OnSyncRequest(UdpMsg *msg, int len);
|
||||
bool OnSyncReply(UdpMsg *msg, int len);
|
||||
bool OnInput(UdpMsg *msg, int len);
|
||||
bool OnInputAck(UdpMsg *msg, int len);
|
||||
bool OnQualityReport(UdpMsg *msg, int len);
|
||||
bool OnQualityReply(UdpMsg *msg, int len);
|
||||
bool OnKeepAlive(UdpMsg *msg, int len);
|
||||
bool OnAppData(UdpMsg *msg, int len);
|
||||
|
||||
protected:
|
||||
/*
|
||||
* Network transmission information
|
||||
*/
|
||||
Udp *_udp;
|
||||
sockaddr_in _peer_addr;
|
||||
uint16 _magic_number;
|
||||
int _queue;
|
||||
uint16 _remote_magic_number;
|
||||
bool _connected;
|
||||
int _send_latency;
|
||||
int _oop_percent;
|
||||
struct {
|
||||
int send_time;
|
||||
sockaddr_in dest_addr;
|
||||
UdpMsg* msg;
|
||||
} _oo_packet;
|
||||
RingBuffer<QueueEntry, 64> _send_queue;
|
||||
std::mutex _send_mutex;
|
||||
|
||||
std::vector<uint8> verification;
|
||||
|
||||
/*
|
||||
* Stats
|
||||
*/
|
||||
int _round_trip_time;
|
||||
int _packets_sent;
|
||||
int _bytes_sent;
|
||||
int _kbps_sent;
|
||||
int _stats_start_time;
|
||||
|
||||
/*
|
||||
* The state machine
|
||||
*/
|
||||
UdpMsg::connect_status *_local_connect_status;
|
||||
UdpMsg::connect_status _peer_connect_status[UDP_MSG_MAX_PLAYERS];
|
||||
|
||||
State _current_state;
|
||||
union {
|
||||
struct {
|
||||
uint32 roundtrips_remaining;
|
||||
uint32 random;
|
||||
} sync;
|
||||
struct {
|
||||
uint32 last_quality_report_time;
|
||||
uint32 last_network_stats_interval;
|
||||
uint32 last_input_packet_recv_time;
|
||||
} running;
|
||||
} _state;
|
||||
|
||||
/*
|
||||
* Fairness.
|
||||
*/
|
||||
int _local_frame_advantage;
|
||||
int _remote_frame_advantage;
|
||||
|
||||
/*
|
||||
* Packet loss...
|
||||
*/
|
||||
RingBuffer<GameInput, 64> _pending_output;
|
||||
GameInput _last_received_input;
|
||||
GameInput _last_sent_input;
|
||||
GameInput _last_acked_input;
|
||||
unsigned int _last_send_time;
|
||||
unsigned int _last_recv_time;
|
||||
unsigned int _shutdown_timeout;
|
||||
unsigned int _disconnect_event_sent;
|
||||
unsigned int _disconnect_timeout;
|
||||
unsigned int _disconnect_notify_start;
|
||||
bool _disconnect_notify_sent;
|
||||
|
||||
uint16 _next_send_seq;
|
||||
uint16 _next_recv_seq;
|
||||
|
||||
/*
|
||||
* Rift synchronization.
|
||||
*/
|
||||
TimeSync _timesync;
|
||||
|
||||
/*
|
||||
* Event queue
|
||||
*/
|
||||
RingBuffer<UdpProtocol::Event, 64> _event_queue;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,38 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
* GGPO.net (http://ggpo.net) - Copyright 2009 GroundStorm Studios, LLC.
|
||||
*
|
||||
* Use of this software is governed by the MIT license that can be found
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
#if defined(__unix__) || defined(__APPLE__) || defined(__SWITCH__)
|
||||
|
||||
#include "platform_linux.h"
|
||||
#include <time.h>
|
||||
#include <strings.h>
|
||||
#include <chrono>
|
||||
|
||||
uint32_t GGPOPlatform::GetCurrentTimeMS()
|
||||
{
|
||||
using namespace std::chrono;
|
||||
static steady_clock::time_point startTime = steady_clock::now();
|
||||
|
||||
return (uint32_t)duration_cast<milliseconds>(steady_clock::now() - startTime).count();
|
||||
}
|
||||
|
||||
int GGPOPlatform::GetConfigInt(const char* name)
|
||||
{
|
||||
char *buf = getenv(name);
|
||||
if (buf == nullptr)
|
||||
return 0;
|
||||
return atoi(buf);
|
||||
}
|
||||
|
||||
bool GGPOPlatform::GetConfigBool(const char* name)
|
||||
{
|
||||
char *buf = getenv(name);
|
||||
if (buf == nullptr)
|
||||
return false;
|
||||
return atoi(buf) != 0 || strcasecmp(buf, "true") == 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,69 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
* GGPO.net (http://ggpo.net) - Copyright 2009 GroundStorm Studios, LLC.
|
||||
*
|
||||
* Use of this software is governed by the MIT license that can be found
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef _GGPO_LINUX_H_
|
||||
#define _GGPO_LINUX_H_
|
||||
|
||||
#include <limits>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <cstdint>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#ifdef __SWITCH__
|
||||
#include "nswitch.h"
|
||||
#else
|
||||
#include <netinet/ip.h>
|
||||
#endif
|
||||
#include <netinet/tcp.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
using SOCKET = int;
|
||||
#define closesocket close
|
||||
#define INVALID_SOCKET (-1)
|
||||
#define SOCKET_ERROR (-1)
|
||||
#define WSAEWOULDBLOCK EWOULDBLOCK
|
||||
|
||||
constexpr size_t MAX_PATH = 4096;
|
||||
#ifdef INT_MAX
|
||||
#undef INT_MAX
|
||||
#endif
|
||||
constexpr int INT_MAX = std::numeric_limits<int>::max();
|
||||
|
||||
class GGPOPlatform {
|
||||
public: // types
|
||||
typedef pid_t ProcessID;
|
||||
|
||||
public: // functions
|
||||
static ProcessID GetProcessID() { return getpid(); }
|
||||
static void AssertFailed(char *msg) { fprintf(stderr, "%s", msg); }
|
||||
static uint32_t GetCurrentTimeMS();
|
||||
static int GetConfigInt(const char* name);
|
||||
static bool GetConfigBool(const char* name);
|
||||
};
|
||||
|
||||
extern "C" {
|
||||
|
||||
inline static void DebugBreak()
|
||||
{
|
||||
__builtin_trap();
|
||||
}
|
||||
|
||||
inline static int WSAGetLastError() {
|
||||
return errno;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,28 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
* GGPO.net (http://ggpo.net) - Copyright 2009 GroundStorm Studios, LLC.
|
||||
*
|
||||
* Use of this software is governed by the MIT license that can be found
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
#ifdef _WIN32
|
||||
#include "platform_windows.h"
|
||||
|
||||
int
|
||||
GGPOPlatform::GetConfigInt(const char* name)
|
||||
{
|
||||
char buf[1024];
|
||||
if (GetEnvironmentVariableA(name, buf, ARRAY_SIZE(buf)) == 0) {
|
||||
return 0;
|
||||
}
|
||||
return atoi(buf);
|
||||
}
|
||||
|
||||
bool GGPOPlatform::GetConfigBool(const char* name)
|
||||
{
|
||||
char buf[1024];
|
||||
if (GetEnvironmentVariableA(name, buf, ARRAY_SIZE(buf)) == 0) {
|
||||
return false;
|
||||
}
|
||||
return atoi(buf) != 0 || _stricmp(buf, "true") == 0;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,44 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
* GGPO.net (http://ggpo.net) - Copyright 2009 GroundStorm Studios, LLC.
|
||||
*
|
||||
* Use of this software is governed by the MIT license that can be found
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef _GGPO_WINDOWS_H_
|
||||
#define _GGPO_WINDOWS_H_
|
||||
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <chrono>
|
||||
|
||||
#include "ggpo_types.h"
|
||||
|
||||
class GGPOPlatform {
|
||||
public: // types
|
||||
typedef DWORD ProcessID;
|
||||
|
||||
public: // functions
|
||||
static ProcessID GetProcessID() { return GetCurrentProcessId(); }
|
||||
static void AssertFailed(char *msg) {
|
||||
#ifndef TARGET_UWP
|
||||
MessageBoxA(NULL, msg, "GGPO Assertion Failed", MB_OK | MB_ICONEXCLAMATION);
|
||||
#endif
|
||||
}
|
||||
static uint32 GetCurrentTimeMS() {
|
||||
#ifdef TARGET_UWP
|
||||
using namespace std::chrono;
|
||||
static steady_clock::time_point startTime = steady_clock::now();
|
||||
|
||||
return (uint32_t)duration_cast<milliseconds>(steady_clock::now() - startTime).count();
|
||||
#else
|
||||
return timeGetTime();
|
||||
#endif
|
||||
}
|
||||
static int GetConfigInt(const char* name);
|
||||
static bool GetConfigBool(const char* name);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,127 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
* GGPO.net (http://ggpo.net) - Copyright 2009 GroundStorm Studios, LLC.
|
||||
*
|
||||
* Use of this software is governed by the MIT license that can be found
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "ggpo_poll.h"
|
||||
#include "ggpo_types.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
constexpr int INFINITE = -1;
|
||||
#endif
|
||||
|
||||
Poll::Poll(void) :
|
||||
_start_time(0),
|
||||
_handle_count(0)
|
||||
{
|
||||
/*
|
||||
* Create a dummy handle to simplify things.
|
||||
*/
|
||||
#ifdef _WIN32
|
||||
_handles[_handle_count++] = CreateEvent(NULL, true, false, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if 0
|
||||
void
|
||||
Poll::RegisterHandle(IPollSink *sink, HANDLE h, void *cookie)
|
||||
{
|
||||
ASSERT(_handle_count < MAX_POLLABLE_HANDLES - 1);
|
||||
|
||||
_handles[_handle_count] = h;
|
||||
_handle_sinks[_handle_count] = PollSinkCb(sink, cookie);
|
||||
_handle_count++;
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
Poll::RegisterMsgLoop(IPollSink *sink, void *cookie)
|
||||
{
|
||||
_msg_sinks.push_back(PollSinkCb(sink, cookie));
|
||||
}
|
||||
|
||||
void
|
||||
Poll::RegisterLoop(IPollSink *sink, void *cookie)
|
||||
{
|
||||
_loop_sinks.push_back(PollSinkCb(sink, cookie));
|
||||
}
|
||||
void
|
||||
Poll::RegisterPeriodic(IPollSink *sink, int interval, void *cookie)
|
||||
{
|
||||
_periodic_sinks.push_back(PollPeriodicSinkCb(sink, cookie, interval));
|
||||
}
|
||||
|
||||
void
|
||||
Poll::Run()
|
||||
{
|
||||
while (Pump(100)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Poll::Pump(int timeout)
|
||||
{
|
||||
int i;
|
||||
bool finished = false;
|
||||
|
||||
if (_start_time == 0) {
|
||||
_start_time = GGPOPlatform::GetCurrentTimeMS();
|
||||
}
|
||||
int elapsed = GGPOPlatform::GetCurrentTimeMS() - _start_time;
|
||||
int maxwait = ComputeWaitTime(elapsed);
|
||||
if (maxwait != INFINITE) {
|
||||
timeout = MIN(timeout, maxwait);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
DWORD res = WaitForMultipleObjects(_handle_count, _handles, false, timeout);
|
||||
if (res >= WAIT_OBJECT_0 && res < WAIT_OBJECT_0 + _handle_count) {
|
||||
i = res - WAIT_OBJECT_0;
|
||||
finished = !_handle_sinks[i].sink->OnHandlePoll(_handle_sinks[i].cookie) || finished;
|
||||
}
|
||||
#else
|
||||
if (timeout > 0)
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(timeout));
|
||||
#endif
|
||||
for (i = 0; i < _msg_sinks.size(); i++) {
|
||||
PollSinkCb &cb = _msg_sinks[i];
|
||||
finished = !cb.sink->OnMsgPoll(cb.cookie) || finished;
|
||||
}
|
||||
|
||||
for (i = 0; i < _periodic_sinks.size(); i++) {
|
||||
PollPeriodicSinkCb &cb = _periodic_sinks[i];
|
||||
if (cb.interval + cb.last_fired <= elapsed) {
|
||||
cb.last_fired = (elapsed / cb.interval) * cb.interval;
|
||||
finished = !cb.sink->OnPeriodicPoll(cb.cookie, cb.last_fired) || finished;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < _loop_sinks.size(); i++) {
|
||||
PollSinkCb &cb = _loop_sinks[i];
|
||||
finished = !cb.sink->OnLoopPoll(cb.cookie) || finished;
|
||||
}
|
||||
return finished;
|
||||
}
|
||||
|
||||
int
|
||||
Poll::ComputeWaitTime(int elapsed)
|
||||
{
|
||||
int waitTime = INFINITE;
|
||||
size_t count = _periodic_sinks.size();
|
||||
|
||||
if (count > 0) {
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
PollPeriodicSinkCb &cb = _periodic_sinks[i];
|
||||
int timeout = (cb.interval + cb.last_fired) - elapsed;
|
||||
if (waitTime == INFINITE || (timeout < waitTime)) {
|
||||
waitTime = MAX(timeout, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
return waitTime;
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
* GGPO.net (http://ggpo.net) - Copyright 2009 GroundStorm Studios, LLC.
|
||||
*
|
||||
* Use of this software is governed by the MIT license that can be found
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef _RING_BUFFER_H
|
||||
#define _RING_BUFFER_H
|
||||
|
||||
#include "ggpo_types.h"
|
||||
|
||||
template<class T, int N> class RingBuffer
|
||||
{
|
||||
public:
|
||||
RingBuffer<T, N>() :
|
||||
_head(0),
|
||||
_tail(0),
|
||||
_size(0) {
|
||||
}
|
||||
|
||||
T &front() {
|
||||
ASSERT(_size != N);
|
||||
return _elements[_tail];
|
||||
}
|
||||
|
||||
T &item(int i) {
|
||||
ASSERT(i < _size);
|
||||
return _elements[(_tail + i) % N];
|
||||
}
|
||||
|
||||
void pop() {
|
||||
ASSERT(_size != N);
|
||||
_tail = (_tail + 1) % N;
|
||||
_size--;
|
||||
}
|
||||
|
||||
void push(const T &t) {
|
||||
ASSERT(_size != (N-1));
|
||||
_elements[_head] = t;
|
||||
_head = (_head + 1) % N;
|
||||
_size++;
|
||||
}
|
||||
|
||||
int size() {
|
||||
return _size;
|
||||
}
|
||||
|
||||
bool empty() {
|
||||
return _size == 0;
|
||||
}
|
||||
|
||||
protected:
|
||||
T _elements[N];
|
||||
int _head;
|
||||
int _tail;
|
||||
int _size;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,40 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
* GGPO.net (http://ggpo.net) - Copyright 2009 GroundStorm Studios, LLC.
|
||||
*
|
||||
* Use of this software is governed by the MIT license that can be found
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef _STATIC_BUFFER_H
|
||||
#define _STATIC_BUFFER_H
|
||||
|
||||
#include "ggpo_types.h"
|
||||
|
||||
template<class T, int N> class StaticBuffer
|
||||
{
|
||||
public:
|
||||
StaticBuffer<T, N>() :
|
||||
_size(0) {
|
||||
}
|
||||
|
||||
T& operator[](int i) {
|
||||
ASSERT(i >= 0 && i < _size);
|
||||
return _elements[i];
|
||||
}
|
||||
|
||||
void push_back(const T &t) {
|
||||
ASSERT(_size != (N-1));
|
||||
_elements[_size++] = t;
|
||||
}
|
||||
|
||||
int size() {
|
||||
return _size;
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
T _elements[N];
|
||||
int _size;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,304 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
* GGPO.net (http://ggpo.net) - Copyright 2009 GroundStorm Studios, LLC.
|
||||
*
|
||||
* Use of this software is governed by the MIT license that can be found
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "sync.h"
|
||||
|
||||
Sync::Sync(UdpMsg::connect_status *connect_status) :
|
||||
_input_queues(NULL),
|
||||
_local_connect_status(connect_status)
|
||||
{
|
||||
_framecount = 0;
|
||||
_last_confirmed_frame = -1;
|
||||
_max_prediction_frames = 0;
|
||||
memset(&_savedstate, 0, sizeof(_savedstate));
|
||||
}
|
||||
|
||||
Sync::~Sync()
|
||||
{
|
||||
/*
|
||||
* Delete frames manually here rather than in a destructor of the SavedFrame
|
||||
* structure so we can efficently copy frames via weak references.
|
||||
*/
|
||||
for (size_t i = 0; i < ARRAY_SIZE(_savedstate.frames); i++) {
|
||||
_callbacks.free_buffer(_savedstate.frames[i].buf);
|
||||
}
|
||||
delete [] _input_queues;
|
||||
_input_queues = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
Sync::Init(Sync::Config &config)
|
||||
{
|
||||
_config = config;
|
||||
_callbacks = config.callbacks;
|
||||
_framecount = 0;
|
||||
_rollingback = false;
|
||||
|
||||
_max_prediction_frames = config.num_prediction_frames;
|
||||
|
||||
CreateQueues(config);
|
||||
}
|
||||
|
||||
void
|
||||
Sync::SetLastConfirmedFrame(int frame)
|
||||
{
|
||||
_last_confirmed_frame = frame;
|
||||
if (_last_confirmed_frame > 0) {
|
||||
for (int i = 0; i < _config.num_players; i++) {
|
||||
_input_queues[i].DiscardConfirmedFrames(frame - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Sync::AddLocalInput(int queue, GameInput &input)
|
||||
{
|
||||
int frames_behind = _framecount - _last_confirmed_frame;
|
||||
if (_framecount >= _max_prediction_frames && frames_behind >= _max_prediction_frames) {
|
||||
Log("Rejecting input from emulator: reached prediction barrier.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_framecount == 0) {
|
||||
SaveCurrentFrame();
|
||||
}
|
||||
|
||||
Log("Sending undelayed local frame %d to queue %d.\n", _framecount, queue);
|
||||
input.frame = _framecount;
|
||||
_input_queues[queue].AddInput(input);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
Sync::AddRemoteInput(int queue, GameInput &input)
|
||||
{
|
||||
_input_queues[queue].AddInput(input);
|
||||
}
|
||||
|
||||
int
|
||||
Sync::GetConfirmedInputs(void *values, int size, int frame)
|
||||
{
|
||||
int disconnect_flags = 0;
|
||||
char *output = (char *)values;
|
||||
|
||||
ASSERT(size >= _config.num_players * _config.input_size);
|
||||
|
||||
memset(output, 0, size);
|
||||
for (int i = 0; i < _config.num_players; i++) {
|
||||
GameInput input;
|
||||
if (_local_connect_status[i].disconnected && frame > _local_connect_status[i].last_frame) {
|
||||
disconnect_flags |= (1 << i);
|
||||
input.erase();
|
||||
} else {
|
||||
_input_queues[i].GetConfirmedInput(frame, &input);
|
||||
}
|
||||
memcpy(output + (i * _config.input_size), input.bits, _config.input_size);
|
||||
}
|
||||
return disconnect_flags;
|
||||
}
|
||||
|
||||
int
|
||||
Sync::SynchronizeInputs(void *values, int size)
|
||||
{
|
||||
int disconnect_flags = 0;
|
||||
char *output = (char *)values;
|
||||
|
||||
ASSERT(size >= _config.num_players * _config.input_size);
|
||||
|
||||
memset(output, 0, size);
|
||||
for (int i = 0; i < _config.num_players; i++) {
|
||||
GameInput input;
|
||||
if (_local_connect_status[i].disconnected && _framecount > _local_connect_status[i].last_frame) {
|
||||
disconnect_flags |= (1 << i);
|
||||
input.erase();
|
||||
} else {
|
||||
_input_queues[i].GetInput(_framecount, &input);
|
||||
}
|
||||
memcpy(output + (i * _config.input_size), input.bits, _config.input_size);
|
||||
}
|
||||
return disconnect_flags;
|
||||
}
|
||||
|
||||
void
|
||||
Sync::CheckSimulation(int timeout)
|
||||
{
|
||||
int seek_to;
|
||||
if (!CheckSimulationConsistency(&seek_to)) {
|
||||
AdjustSimulation(seek_to);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Sync::IncrementFrame(void)
|
||||
{
|
||||
_framecount++;
|
||||
SaveCurrentFrame();
|
||||
}
|
||||
|
||||
void
|
||||
Sync::AdjustSimulation(int seek_to)
|
||||
{
|
||||
int framecount = _framecount;
|
||||
int count = _framecount - seek_to;
|
||||
|
||||
Log("Catching up\n");
|
||||
_rollingback = true;
|
||||
|
||||
/*
|
||||
* Flush our input queue and load the last frame.
|
||||
*/
|
||||
LoadFrame(seek_to);
|
||||
ASSERT(_framecount == seek_to);
|
||||
|
||||
/*
|
||||
* Advance frame by frame (stuffing notifications back to
|
||||
* the master).
|
||||
*/
|
||||
ResetPrediction(_framecount);
|
||||
for (int i = 0; i < count; i++) {
|
||||
_callbacks.advance_frame(0);
|
||||
}
|
||||
ASSERT(_framecount == framecount);
|
||||
|
||||
_rollingback = false;
|
||||
|
||||
Log("---\n");
|
||||
}
|
||||
|
||||
void
|
||||
Sync::LoadFrame(int frame)
|
||||
{
|
||||
// find the frame in question
|
||||
if (frame == _framecount) {
|
||||
Log("Skipping NOP.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Move the head pointer back and load it up
|
||||
_savedstate.head = FindSavedFrameIndex(frame);
|
||||
SavedFrame *state = _savedstate.frames + _savedstate.head;
|
||||
|
||||
Log("=== Loading frame info %d (size: %d checksum: %08x).\n",
|
||||
state->frame, state->cbuf, state->checksum);
|
||||
|
||||
ASSERT(state->buf && state->cbuf);
|
||||
_callbacks.load_game_state(state->buf, state->cbuf);
|
||||
|
||||
// Reset framecount and the head of the state ring-buffer to point in
|
||||
// advance of the current frame (as if we had just finished executing it).
|
||||
_framecount = state->frame;
|
||||
_savedstate.head = (_savedstate.head + 1) % ARRAY_SIZE(_savedstate.frames);
|
||||
}
|
||||
|
||||
void
|
||||
Sync::SaveCurrentFrame()
|
||||
{
|
||||
/*
|
||||
* See StateCompress for the real save feature implemented by FinalBurn.
|
||||
* Write everything into the head, then advance the head pointer.
|
||||
*/
|
||||
SavedFrame *state = _savedstate.frames + _savedstate.head;
|
||||
if (state->buf) {
|
||||
_callbacks.free_buffer(state->buf);
|
||||
state->buf = NULL;
|
||||
}
|
||||
state->frame = _framecount;
|
||||
_callbacks.save_game_state(&state->buf, &state->cbuf, &state->checksum, state->frame);
|
||||
|
||||
Log("=== Saved frame info %d (size: %d checksum: %08x).\n", state->frame, state->cbuf, state->checksum);
|
||||
_savedstate.head = (_savedstate.head + 1) % ARRAY_SIZE(_savedstate.frames);
|
||||
}
|
||||
|
||||
Sync::SavedFrame&
|
||||
Sync::GetLastSavedFrame()
|
||||
{
|
||||
int i = _savedstate.head - 1;
|
||||
if (i < 0) {
|
||||
i = ARRAY_SIZE(_savedstate.frames) - 1;
|
||||
}
|
||||
return _savedstate.frames[i];
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
Sync::FindSavedFrameIndex(int frame)
|
||||
{
|
||||
int i, count = ARRAY_SIZE(_savedstate.frames);
|
||||
for (i = 0; i < count; i++) {
|
||||
if (_savedstate.frames[i].frame == frame) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == count) {
|
||||
ASSERT(false);
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Sync::CreateQueues(Config &config)
|
||||
{
|
||||
delete [] _input_queues;
|
||||
_input_queues = new InputQueue[_config.num_players];
|
||||
|
||||
for (int i = 0; i < _config.num_players; i++) {
|
||||
_input_queues[i].Init(i, _config.input_size);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Sync::CheckSimulationConsistency(int *seekTo)
|
||||
{
|
||||
int first_incorrect = GameInput::NullFrame;
|
||||
for (int i = 0; i < _config.num_players; i++) {
|
||||
int incorrect = _input_queues[i].GetFirstIncorrectFrame();
|
||||
Log("considering incorrect frame %d reported by queue %d.\n", incorrect, i);
|
||||
|
||||
if (incorrect != GameInput::NullFrame && (first_incorrect == GameInput::NullFrame || incorrect < first_incorrect)) {
|
||||
first_incorrect = incorrect;
|
||||
}
|
||||
}
|
||||
|
||||
if (first_incorrect == GameInput::NullFrame) {
|
||||
Log("prediction ok. proceeding.\n");
|
||||
return true;
|
||||
}
|
||||
*seekTo = first_incorrect;
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
Sync::SetFrameDelay(int queue, int delay)
|
||||
{
|
||||
_input_queues[queue].SetFrameDelay(delay);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Sync::ResetPrediction(int frameNumber)
|
||||
{
|
||||
for (int i = 0; i < _config.num_players; i++) {
|
||||
_input_queues[i].ResetPrediction(frameNumber);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Sync::GetEvent(Event &e)
|
||||
{
|
||||
if (_event_queue.size()) {
|
||||
e = _event_queue.front();
|
||||
_event_queue.pop();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
* GGPO.net (http://ggpo.net) - Copyright 2009 GroundStorm Studios, LLC.
|
||||
*
|
||||
* Use of this software is governed by the MIT license that can be found
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef _SYNC_H
|
||||
#define _SYNC_H
|
||||
|
||||
#include "ggponet.h"
|
||||
#include "game_input.h"
|
||||
#include "ggpo_types.h"
|
||||
#include "input_queue.h"
|
||||
#include "ring_buffer.h"
|
||||
#include "network/udp_msg.h"
|
||||
|
||||
#define MAX_PREDICTION_FRAMES 8
|
||||
|
||||
class SyncTestBackend;
|
||||
|
||||
class Sync {
|
||||
public:
|
||||
struct Config {
|
||||
GGPOSessionCallbacks callbacks;
|
||||
int num_prediction_frames;
|
||||
int num_players;
|
||||
int input_size;
|
||||
};
|
||||
struct Event {
|
||||
enum {
|
||||
ConfirmedInput,
|
||||
} type;
|
||||
union {
|
||||
struct {
|
||||
GameInput input;
|
||||
} confirmedInput;
|
||||
} u;
|
||||
};
|
||||
|
||||
public:
|
||||
Sync(UdpMsg::connect_status *connect_status);
|
||||
virtual ~Sync();
|
||||
|
||||
void Init(Config &config);
|
||||
|
||||
void SetLastConfirmedFrame(int frame);
|
||||
void SetFrameDelay(int queue, int delay);
|
||||
bool AddLocalInput(int queue, GameInput &input);
|
||||
void AddRemoteInput(int queue, GameInput &input);
|
||||
int GetConfirmedInputs(void *values, int size, int frame);
|
||||
int SynchronizeInputs(void *values, int size);
|
||||
|
||||
void CheckSimulation(int timeout);
|
||||
void AdjustSimulation(int seek_to);
|
||||
void IncrementFrame(void);
|
||||
|
||||
int GetFrameCount() { return _framecount; }
|
||||
bool InRollback() { return _rollingback; }
|
||||
int GetPredictedFrames() { return _framecount - _last_confirmed_frame; }
|
||||
|
||||
bool GetEvent(Event &e);
|
||||
|
||||
protected:
|
||||
friend SyncTestBackend;
|
||||
|
||||
struct SavedFrame {
|
||||
byte *buf;
|
||||
int cbuf;
|
||||
int frame;
|
||||
int checksum;
|
||||
SavedFrame() : buf(NULL), cbuf(0), frame(-1), checksum(0) { }
|
||||
};
|
||||
struct SavedState {
|
||||
SavedFrame frames[MAX_PREDICTION_FRAMES + 2];
|
||||
int head;
|
||||
};
|
||||
|
||||
void LoadFrame(int frame);
|
||||
void SaveCurrentFrame();
|
||||
int FindSavedFrameIndex(int frame);
|
||||
SavedFrame &GetLastSavedFrame();
|
||||
|
||||
bool CreateQueues(Config &config);
|
||||
bool CheckSimulationConsistency(int *seekTo);
|
||||
void ResetPrediction(int frameNumber);
|
||||
|
||||
protected:
|
||||
GGPOSessionCallbacks _callbacks;
|
||||
SavedState _savedstate;
|
||||
Config _config;
|
||||
|
||||
bool _rollingback;
|
||||
int _last_confirmed_frame;
|
||||
int _framecount;
|
||||
int _max_prediction_frames;
|
||||
|
||||
InputQueue *_input_queues;
|
||||
|
||||
RingBuffer<Event, 32> _event_queue;
|
||||
UdpMsg::connect_status *_local_connect_status;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
* GGPO.net (http://ggpo.net) - Copyright 2009 GroundStorm Studios, LLC.
|
||||
*
|
||||
* Use of this software is governed by the MIT license that can be found
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "timesync.h"
|
||||
|
||||
TimeSync::TimeSync()
|
||||
{
|
||||
memset(_local, 0, sizeof(_local));
|
||||
memset(_remote, 0, sizeof(_remote));
|
||||
_next_prediction = FRAME_WINDOW_SIZE * 3;
|
||||
}
|
||||
|
||||
TimeSync::~TimeSync()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
TimeSync::advance_frame(GameInput &input, int advantage, int radvantage)
|
||||
{
|
||||
// Remember the last frame and frame advantage
|
||||
_last_inputs[input.frame % ARRAY_SIZE(_last_inputs)] = input;
|
||||
_local[input.frame % ARRAY_SIZE(_local)] = advantage;
|
||||
_remote[input.frame % ARRAY_SIZE(_remote)] = radvantage;
|
||||
}
|
||||
|
||||
int
|
||||
TimeSync::recommend_frame_wait_duration(bool require_idle_input)
|
||||
{
|
||||
// Average our local and remote frame advantages
|
||||
int sum = 0;
|
||||
float advantage, radvantage;
|
||||
for (size_t i = 0; i < ARRAY_SIZE(_local); i++) {
|
||||
sum += _local[i];
|
||||
}
|
||||
advantage = sum / (float)ARRAY_SIZE(_local);
|
||||
|
||||
sum = 0;
|
||||
for (size_t i = 0; i < ARRAY_SIZE(_remote); i++) {
|
||||
sum += _remote[i];
|
||||
}
|
||||
radvantage = sum / (float)ARRAY_SIZE(_remote);
|
||||
|
||||
static int count = 0;
|
||||
count++;
|
||||
|
||||
// See if someone should take action. The person furthest ahead
|
||||
// needs to slow down so the other user can catch up.
|
||||
// Only do this if both clients agree on who's ahead!!
|
||||
if (advantage >= radvantage) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Both clients agree that we're the one ahead. Split
|
||||
// the difference between the two to figure out how long to
|
||||
// sleep for.
|
||||
int sleep_frames = (int)(((radvantage - advantage) / 2) + 0.5);
|
||||
|
||||
Log("iteration %d: sleep frames is %d\n", count, sleep_frames);
|
||||
|
||||
// Some things just aren't worth correcting for. Make sure
|
||||
// the difference is relevant before proceeding.
|
||||
if (sleep_frames < MIN_FRAME_ADVANTAGE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Make sure our input had been "idle enough" before recommending
|
||||
// a sleep. This tries to make the emulator sleep while the
|
||||
// user's input isn't sweeping in arcs (e.g. fireball motions in
|
||||
// Street Fighter), which could cause the player to miss moves.
|
||||
if (require_idle_input) {
|
||||
for (size_t i = 1; i < ARRAY_SIZE(_last_inputs); i++) {
|
||||
if (!_last_inputs[i].equal(_last_inputs[0], true)) {
|
||||
Log("iteration %d: rejecting due to input stuff at position %d...!!!\n", count, i);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Success!!! Recommend the number of frames to sleep and adjust
|
||||
return MIN(sleep_frames, MAX_FRAME_ADVANTAGE);
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
* GGPO.net (http://ggpo.net) - Copyright 2009 GroundStorm Studios, LLC.
|
||||
*
|
||||
* Use of this software is governed by the MIT license that can be found
|
||||
* in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef _TIMESYNC_H
|
||||
#define _TIMESYNC_H
|
||||
|
||||
#include "game_input.h"
|
||||
#include "ggpo_types.h"
|
||||
|
||||
#define FRAME_WINDOW_SIZE 40
|
||||
#define MIN_UNIQUE_FRAMES 10
|
||||
#define MIN_FRAME_ADVANTAGE 3
|
||||
#define MAX_FRAME_ADVANTAGE 9
|
||||
|
||||
class TimeSync {
|
||||
public:
|
||||
TimeSync();
|
||||
virtual ~TimeSync ();
|
||||
|
||||
void advance_frame(GameInput &input, int advantage, int radvantage);
|
||||
int recommend_frame_wait_duration(bool require_idle_input);
|
||||
|
||||
protected:
|
||||
int _local[FRAME_WINDOW_SIZE];
|
||||
int _remote[FRAME_WINDOW_SIZE];
|
||||
GameInput _last_inputs[MIN_UNIQUE_FRAMES];
|
||||
int _next_prediction;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -6161,11 +6161,12 @@ void ImGui::FocusWindow(ImGuiWindow* window)
|
||||
g.NavWindow = window;
|
||||
if (window && g.NavDisableMouseHover)
|
||||
g.NavMousePosDirty = true;
|
||||
g.NavInitRequest = false;
|
||||
g.NavId = window ? window->NavLastIds[0] : 0; // Restore NavId
|
||||
g.NavFocusScopeId = 0;
|
||||
g.NavIdIsAlive = false;
|
||||
g.NavLayer = ImGuiNavLayer_Main;
|
||||
g.NavInitRequest = g.NavMoveRequest = false;
|
||||
NavUpdateAnyRequestFlag();
|
||||
//IMGUI_DEBUG_LOG("FocusWindow(\"%s\")\n", window ? window->Name : NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -1706,6 +1706,8 @@ bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(voi
|
||||
SetItemDefaultFocus();
|
||||
PopID();
|
||||
}
|
||||
// no drag scrolling on combo popup
|
||||
GetCurrentWindow()->DragScrolling = false;
|
||||
|
||||
EndCombo();
|
||||
return value_changed;
|
||||
|
||||
+1
-1
Submodule core/deps/libchdr updated: d3ffd20ca7...7972daa6ca.
@@ -0,0 +1,58 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (compat_strcasestr.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#include <compat/strcasestr.h>
|
||||
|
||||
/* Pretty much strncasecmp. */
|
||||
static int casencmp(const char *a, const char *b, size_t n)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
int a_lower = tolower(a[i]);
|
||||
int b_lower = tolower(b[i]);
|
||||
if (a_lower != b_lower)
|
||||
return a_lower - b_lower;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *strcasestr_retro__(const char *haystack, const char *needle)
|
||||
{
|
||||
size_t i, search_off;
|
||||
size_t hay_len = strlen(haystack);
|
||||
size_t needle_len = strlen(needle);
|
||||
|
||||
if (needle_len > hay_len)
|
||||
return NULL;
|
||||
|
||||
search_off = hay_len - needle_len;
|
||||
for (i = 0; i <= search_off; i++)
|
||||
if (!casencmp(haystack + i, needle, needle_len))
|
||||
return (char*)haystack + i;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (compat_strl.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <compat/strl.h>
|
||||
|
||||
/* Implementation of strlcpy()/strlcat() based on OpenBSD. */
|
||||
|
||||
#ifndef __MACH__
|
||||
|
||||
size_t strlcpy(char *dest, const char *source, size_t size)
|
||||
{
|
||||
size_t src_size = 0;
|
||||
size_t n = size;
|
||||
|
||||
if (n)
|
||||
while (--n && (*dest++ = *source++)) src_size++;
|
||||
|
||||
if (!n)
|
||||
{
|
||||
if (size) *dest = '\0';
|
||||
while (*source++) src_size++;
|
||||
}
|
||||
|
||||
return src_size;
|
||||
}
|
||||
|
||||
size_t strlcat(char *dest, const char *source, size_t size)
|
||||
{
|
||||
size_t len = strlen(dest);
|
||||
|
||||
dest += len;
|
||||
|
||||
if (len > size)
|
||||
size = 0;
|
||||
else
|
||||
size -= len;
|
||||
|
||||
return len + strlcpy(dest, source, size);
|
||||
}
|
||||
#endif
|
||||
|
||||
char *strldup(const char *s, size_t n)
|
||||
{
|
||||
char *dst = (char*)malloc(sizeof(char) * (n + 1));
|
||||
strlcpy(dst, s, n);
|
||||
return dst;
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (fopen_utf8.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <compat/fopen_utf8.h>
|
||||
#include <encodings/utf.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500 || defined(_XBOX)
|
||||
#ifndef LEGACY_WIN32
|
||||
#define LEGACY_WIN32
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#undef fopen
|
||||
|
||||
void *fopen_utf8(const char * filename, const char * mode)
|
||||
{
|
||||
#if defined(_XBOX)
|
||||
return fopen(filename, mode);
|
||||
#elif defined(LEGACY_WIN32)
|
||||
FILE *ret = NULL;
|
||||
char * filename_local = utf8_to_local_string_alloc(filename);
|
||||
|
||||
if (!filename_local)
|
||||
return NULL;
|
||||
ret = fopen(filename_local, mode);
|
||||
if (filename_local)
|
||||
free(filename_local);
|
||||
return ret;
|
||||
#else
|
||||
wchar_t * filename_w = utf8_to_utf16_string_alloc(filename);
|
||||
wchar_t * mode_w = utf8_to_utf16_string_alloc(mode);
|
||||
FILE* ret = _wfopen(filename_w, mode_w);
|
||||
free(filename_w);
|
||||
free(mode_w);
|
||||
return ret;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,510 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (encoding_utf.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <boolean.h>
|
||||
#include <compat/strl.h>
|
||||
#include <retro_inline.h>
|
||||
|
||||
#include <encodings/utf.h>
|
||||
|
||||
#if defined(_WIN32) && !defined(_XBOX)
|
||||
#include <windows.h>
|
||||
#elif defined(_XBOX)
|
||||
#include <xtl.h>
|
||||
#endif
|
||||
|
||||
static unsigned leading_ones(uint8_t c)
|
||||
{
|
||||
unsigned ones = 0;
|
||||
while (c & 0x80)
|
||||
{
|
||||
ones++;
|
||||
c <<= 1;
|
||||
}
|
||||
|
||||
return ones;
|
||||
}
|
||||
|
||||
/* Simple implementation. Assumes the sequence is
|
||||
* properly synchronized and terminated. */
|
||||
|
||||
size_t utf8_conv_utf32(uint32_t *out, size_t out_chars,
|
||||
const char *in, size_t in_size)
|
||||
{
|
||||
unsigned i;
|
||||
size_t ret = 0;
|
||||
while (in_size && out_chars)
|
||||
{
|
||||
unsigned extra, shift;
|
||||
uint32_t c;
|
||||
uint8_t first = *in++;
|
||||
unsigned ones = leading_ones(first);
|
||||
|
||||
if (ones > 6 || ones == 1) /* Invalid or desync. */
|
||||
break;
|
||||
|
||||
extra = ones ? ones - 1 : ones;
|
||||
if (1 + extra > in_size) /* Overflow. */
|
||||
break;
|
||||
|
||||
shift = (extra - 1) * 6;
|
||||
c = (first & ((1 << (7 - ones)) - 1)) << (6 * extra);
|
||||
|
||||
for (i = 0; i < extra; i++, in++, shift -= 6)
|
||||
c |= (*in & 0x3f) << shift;
|
||||
|
||||
*out++ = c;
|
||||
in_size -= 1 + extra;
|
||||
out_chars--;
|
||||
ret++;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool utf16_conv_utf8(uint8_t *out, size_t *out_chars,
|
||||
const uint16_t *in, size_t in_size)
|
||||
{
|
||||
static uint8_t kUtf8Limits[5] = { 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
|
||||
size_t out_pos = 0;
|
||||
size_t in_pos = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
unsigned numAdds;
|
||||
uint32_t value;
|
||||
|
||||
if (in_pos == in_size)
|
||||
{
|
||||
*out_chars = out_pos;
|
||||
return true;
|
||||
}
|
||||
value = in[in_pos++];
|
||||
if (value < 0x80)
|
||||
{
|
||||
if (out)
|
||||
out[out_pos] = (char)value;
|
||||
out_pos++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (value >= 0xD800 && value < 0xE000)
|
||||
{
|
||||
uint32_t c2;
|
||||
|
||||
if (value >= 0xDC00 || in_pos == in_size)
|
||||
break;
|
||||
c2 = in[in_pos++];
|
||||
if (c2 < 0xDC00 || c2 >= 0xE000)
|
||||
break;
|
||||
value = (((value - 0xD800) << 10) | (c2 - 0xDC00)) + 0x10000;
|
||||
}
|
||||
|
||||
for (numAdds = 1; numAdds < 5; numAdds++)
|
||||
if (value < (((uint32_t)1) << (numAdds * 5 + 6)))
|
||||
break;
|
||||
if (out)
|
||||
out[out_pos] = (char)(kUtf8Limits[numAdds - 1]
|
||||
+ (value >> (6 * numAdds)));
|
||||
out_pos++;
|
||||
do
|
||||
{
|
||||
numAdds--;
|
||||
if (out)
|
||||
out[out_pos] = (char)(0x80
|
||||
+ ((value >> (6 * numAdds)) & 0x3F));
|
||||
out_pos++;
|
||||
}while (numAdds != 0);
|
||||
}
|
||||
|
||||
*out_chars = out_pos;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Acts mostly like strlcpy.
|
||||
*
|
||||
* Copies the given number of UTF-8 characters,
|
||||
* but at most d_len bytes.
|
||||
*
|
||||
* Always NULL terminates.
|
||||
* Does not copy half a character.
|
||||
*
|
||||
* Returns number of bytes. 's' is assumed valid UTF-8.
|
||||
* Use only if 'chars' is considerably less than 'd_len'. */
|
||||
size_t utf8cpy(char *d, size_t d_len, const char *s, size_t chars)
|
||||
{
|
||||
const uint8_t *sb = (const uint8_t*)s;
|
||||
const uint8_t *sb_org = sb;
|
||||
|
||||
if (!s)
|
||||
return 0;
|
||||
|
||||
while (*sb && chars-- > 0)
|
||||
{
|
||||
sb++;
|
||||
while ((*sb & 0xC0) == 0x80) sb++;
|
||||
}
|
||||
|
||||
if ((size_t)(sb - sb_org) > d_len-1 /* NUL */)
|
||||
{
|
||||
sb = sb_org + d_len-1;
|
||||
while ((*sb & 0xC0) == 0x80) sb--;
|
||||
}
|
||||
|
||||
memcpy(d, sb_org, sb-sb_org);
|
||||
d[sb-sb_org] = '\0';
|
||||
|
||||
return sb-sb_org;
|
||||
}
|
||||
|
||||
const char *utf8skip(const char *str, size_t chars)
|
||||
{
|
||||
const uint8_t *strb = (const uint8_t*)str;
|
||||
if (!chars)
|
||||
return str;
|
||||
do
|
||||
{
|
||||
strb++;
|
||||
while ((*strb & 0xC0)==0x80) strb++;
|
||||
chars--;
|
||||
} while(chars);
|
||||
return (const char*)strb;
|
||||
}
|
||||
|
||||
size_t utf8len(const char *string)
|
||||
{
|
||||
size_t ret = 0;
|
||||
|
||||
if (!string)
|
||||
return 0;
|
||||
|
||||
while (*string)
|
||||
{
|
||||
if ((*string & 0xC0) != 0x80)
|
||||
ret++;
|
||||
string++;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define utf8_walkbyte(string) (*((*(string))++))
|
||||
|
||||
/* Does not validate the input, returns garbage if it's not UTF-8. */
|
||||
uint32_t utf8_walk(const char **string)
|
||||
{
|
||||
uint8_t first = utf8_walkbyte(string);
|
||||
uint32_t ret = 0;
|
||||
|
||||
if (first < 128)
|
||||
return first;
|
||||
|
||||
ret = (ret << 6) | (utf8_walkbyte(string) & 0x3F);
|
||||
if (first >= 0xE0)
|
||||
{
|
||||
ret = (ret << 6) | (utf8_walkbyte(string) & 0x3F);
|
||||
if (first >= 0xF0)
|
||||
{
|
||||
ret = (ret << 6) | (utf8_walkbyte(string) & 0x3F);
|
||||
return ret | (first & 7) << 18;
|
||||
}
|
||||
return ret | (first & 15) << 12;
|
||||
}
|
||||
|
||||
return ret | (first & 31) << 6;
|
||||
}
|
||||
|
||||
static bool utf16_to_char(uint8_t **utf_data,
|
||||
size_t *dest_len, const uint16_t *in)
|
||||
{
|
||||
unsigned len = 0;
|
||||
|
||||
while (in[len] != '\0')
|
||||
len++;
|
||||
|
||||
utf16_conv_utf8(NULL, dest_len, in, len);
|
||||
*dest_len += 1;
|
||||
*utf_data = (uint8_t*)malloc(*dest_len);
|
||||
if (*utf_data == 0)
|
||||
return false;
|
||||
|
||||
return utf16_conv_utf8(*utf_data, dest_len, in, len);
|
||||
}
|
||||
|
||||
bool utf16_to_char_string(const uint16_t *in, char *s, size_t len)
|
||||
{
|
||||
size_t dest_len = 0;
|
||||
uint8_t *utf16_data = NULL;
|
||||
bool ret = utf16_to_char(&utf16_data, &dest_len, in);
|
||||
|
||||
if (ret)
|
||||
{
|
||||
utf16_data[dest_len] = 0;
|
||||
strlcpy(s, (const char*)utf16_data, len);
|
||||
}
|
||||
|
||||
free(utf16_data);
|
||||
utf16_data = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if defined(_WIN32) && !defined(_XBOX) && !defined(UNICODE)
|
||||
/* Returned pointer MUST be freed by the caller if non-NULL. */
|
||||
static char *mb_to_mb_string_alloc(const char *str,
|
||||
enum CodePage cp_in, enum CodePage cp_out)
|
||||
{
|
||||
char *path_buf = NULL;
|
||||
wchar_t *path_buf_wide = NULL;
|
||||
int path_buf_len = 0;
|
||||
int path_buf_wide_len = MultiByteToWideChar(cp_in, 0, str, -1, NULL, 0);
|
||||
|
||||
/* Windows 95 will return 0 from these functions with
|
||||
* a UTF8 codepage set without MSLU.
|
||||
*
|
||||
* From an unknown MSDN version (others omit this info):
|
||||
* - CP_UTF8 Windows 98/Me, Windows NT 4.0 and later:
|
||||
* Translate using UTF-8. When this is set, dwFlags must be zero.
|
||||
* - Windows 95: Under the Microsoft Layer for Unicode,
|
||||
* MultiByteToWideChar also supports CP_UTF7 and CP_UTF8.
|
||||
*/
|
||||
|
||||
if (path_buf_wide_len)
|
||||
{
|
||||
path_buf_wide = (wchar_t*)
|
||||
calloc(path_buf_wide_len + sizeof(wchar_t), sizeof(wchar_t));
|
||||
|
||||
if (path_buf_wide)
|
||||
{
|
||||
MultiByteToWideChar(cp_in, 0,
|
||||
str, -1, path_buf_wide, path_buf_wide_len);
|
||||
|
||||
if (*path_buf_wide)
|
||||
{
|
||||
path_buf_len = WideCharToMultiByte(cp_out, 0,
|
||||
path_buf_wide, -1, NULL, 0, NULL, NULL);
|
||||
|
||||
if (path_buf_len)
|
||||
{
|
||||
path_buf = (char*)
|
||||
calloc(path_buf_len + sizeof(char), sizeof(char));
|
||||
|
||||
if (path_buf)
|
||||
{
|
||||
WideCharToMultiByte(cp_out, 0,
|
||||
path_buf_wide, -1, path_buf,
|
||||
path_buf_len, NULL, NULL);
|
||||
|
||||
free(path_buf_wide);
|
||||
|
||||
if (*path_buf)
|
||||
return path_buf;
|
||||
|
||||
free(path_buf);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
free(path_buf_wide);
|
||||
return strdup(str);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
return strdup(str);
|
||||
|
||||
if (path_buf_wide)
|
||||
free(path_buf_wide);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Returned pointer MUST be freed by the caller if non-NULL. */
|
||||
char* utf8_to_local_string_alloc(const char *str)
|
||||
{
|
||||
if (str && *str)
|
||||
{
|
||||
#if defined(_WIN32) && !defined(_XBOX) && !defined(UNICODE)
|
||||
return mb_to_mb_string_alloc(str, CODEPAGE_UTF8, CODEPAGE_LOCAL);
|
||||
#else
|
||||
/* assume string needs no modification if not on Windows */
|
||||
return strdup(str);
|
||||
#endif
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Returned pointer MUST be freed by the caller if non-NULL. */
|
||||
char* local_to_utf8_string_alloc(const char *str)
|
||||
{
|
||||
if (str && *str)
|
||||
{
|
||||
#if defined(_WIN32) && !defined(_XBOX) && !defined(UNICODE)
|
||||
return mb_to_mb_string_alloc(str, CODEPAGE_LOCAL, CODEPAGE_UTF8);
|
||||
#else
|
||||
/* assume string needs no modification if not on Windows */
|
||||
return strdup(str);
|
||||
#endif
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Returned pointer MUST be freed by the caller if non-NULL. */
|
||||
wchar_t* utf8_to_utf16_string_alloc(const char *str)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
int len = 0;
|
||||
int out_len = 0;
|
||||
#else
|
||||
size_t len = 0;
|
||||
size_t out_len = 0;
|
||||
#endif
|
||||
wchar_t *buf = NULL;
|
||||
|
||||
if (!str || !*str)
|
||||
return NULL;
|
||||
|
||||
#ifdef _WIN32
|
||||
len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
|
||||
|
||||
if (len)
|
||||
{
|
||||
buf = (wchar_t*)calloc(len, sizeof(wchar_t));
|
||||
|
||||
if (!buf)
|
||||
return NULL;
|
||||
|
||||
out_len = MultiByteToWideChar(CP_UTF8, 0, str, -1, buf, len);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* fallback to ANSI codepage instead */
|
||||
len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
|
||||
|
||||
if (len)
|
||||
{
|
||||
buf = (wchar_t*)calloc(len, sizeof(wchar_t));
|
||||
|
||||
if (!buf)
|
||||
return NULL;
|
||||
|
||||
out_len = MultiByteToWideChar(CP_ACP, 0, str, -1, buf, len);
|
||||
}
|
||||
}
|
||||
|
||||
if (out_len < 0)
|
||||
{
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
/* NOTE: For now, assume non-Windows platforms' locale is already UTF-8. */
|
||||
len = mbstowcs(NULL, str, 0) + 1;
|
||||
|
||||
if (len)
|
||||
{
|
||||
buf = (wchar_t*)calloc(len, sizeof(wchar_t));
|
||||
|
||||
if (!buf)
|
||||
return NULL;
|
||||
|
||||
out_len = mbstowcs(buf, str, len);
|
||||
}
|
||||
|
||||
if (out_len == (size_t)-1)
|
||||
{
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* Returned pointer MUST be freed by the caller if non-NULL. */
|
||||
char* utf16_to_utf8_string_alloc(const wchar_t *str)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
int len = 0;
|
||||
#else
|
||||
size_t len = 0;
|
||||
#endif
|
||||
char *buf = NULL;
|
||||
|
||||
if (!str || !*str)
|
||||
return NULL;
|
||||
|
||||
#ifdef _WIN32
|
||||
{
|
||||
UINT code_page = CP_UTF8;
|
||||
len = WideCharToMultiByte(code_page,
|
||||
0, str, -1, NULL, 0, NULL, NULL);
|
||||
|
||||
/* fallback to ANSI codepage instead */
|
||||
if (!len)
|
||||
{
|
||||
code_page = CP_ACP;
|
||||
len = WideCharToMultiByte(code_page,
|
||||
0, str, -1, NULL, 0, NULL, NULL);
|
||||
}
|
||||
|
||||
buf = (char*)calloc(len, sizeof(char));
|
||||
|
||||
if (!buf)
|
||||
return NULL;
|
||||
|
||||
if (WideCharToMultiByte(code_page,
|
||||
0, str, -1, buf, len, NULL, NULL) < 0)
|
||||
{
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
#else
|
||||
/* NOTE: For now, assume non-Windows platforms'
|
||||
* locale is already UTF-8. */
|
||||
len = wcstombs(NULL, str, 0) + 1;
|
||||
|
||||
if (len)
|
||||
{
|
||||
buf = (char*)calloc(len, sizeof(char));
|
||||
|
||||
if (!buf)
|
||||
return NULL;
|
||||
|
||||
if (wcstombs(buf, str, len) == (size_t)-1)
|
||||
{
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return buf;
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,118 @@
|
||||
/* Copyright (C) 2010-2019 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (retro_dirent.c).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <retro_common.h>
|
||||
|
||||
#include <boolean.h>
|
||||
#include <retro_dirent.h>
|
||||
#define VFS_FRONTEND
|
||||
#include <vfs/vfs_implementation.h>
|
||||
|
||||
static retro_vfs_opendir_t dirent_opendir_cb = NULL;
|
||||
static retro_vfs_readdir_t dirent_readdir_cb = NULL;
|
||||
static retro_vfs_dirent_get_name_t dirent_dirent_get_name_cb = NULL;
|
||||
static retro_vfs_dirent_is_dir_t dirent_dirent_is_dir_cb = NULL;
|
||||
static retro_vfs_closedir_t dirent_closedir_cb = NULL;
|
||||
|
||||
void dirent_vfs_init(const struct retro_vfs_interface_info* vfs_info)
|
||||
{
|
||||
const struct retro_vfs_interface* vfs_iface;
|
||||
|
||||
dirent_opendir_cb = NULL;
|
||||
dirent_readdir_cb = NULL;
|
||||
dirent_dirent_get_name_cb = NULL;
|
||||
dirent_dirent_is_dir_cb = NULL;
|
||||
dirent_closedir_cb = NULL;
|
||||
|
||||
vfs_iface = vfs_info->iface;
|
||||
|
||||
if (vfs_info->required_interface_version < DIRENT_REQUIRED_VFS_VERSION || !vfs_iface)
|
||||
return;
|
||||
|
||||
dirent_opendir_cb = vfs_iface->opendir;
|
||||
dirent_readdir_cb = vfs_iface->readdir;
|
||||
dirent_dirent_get_name_cb = vfs_iface->dirent_get_name;
|
||||
dirent_dirent_is_dir_cb = vfs_iface->dirent_is_dir;
|
||||
dirent_closedir_cb = vfs_iface->closedir;
|
||||
}
|
||||
|
||||
struct RDIR *retro_opendir_include_hidden(const char *name, bool include_hidden)
|
||||
{
|
||||
if (dirent_opendir_cb != NULL)
|
||||
return (struct RDIR *)dirent_opendir_cb(name, include_hidden);
|
||||
return (struct RDIR *)retro_vfs_opendir_impl(name, include_hidden);
|
||||
}
|
||||
|
||||
struct RDIR *retro_opendir(const char *name)
|
||||
{
|
||||
return retro_opendir_include_hidden(name, false);
|
||||
}
|
||||
|
||||
bool retro_dirent_error(struct RDIR *rdir)
|
||||
{
|
||||
/* Left for compatibility */
|
||||
return false;
|
||||
}
|
||||
|
||||
int retro_readdir(struct RDIR *rdir)
|
||||
{
|
||||
if (dirent_readdir_cb != NULL)
|
||||
return dirent_readdir_cb((struct retro_vfs_dir_handle *)rdir);
|
||||
return retro_vfs_readdir_impl((struct retro_vfs_dir_handle *)rdir);
|
||||
}
|
||||
|
||||
const char *retro_dirent_get_name(struct RDIR *rdir)
|
||||
{
|
||||
if (dirent_dirent_get_name_cb != NULL)
|
||||
return dirent_dirent_get_name_cb((struct retro_vfs_dir_handle *)rdir);
|
||||
return retro_vfs_dirent_get_name_impl((struct retro_vfs_dir_handle *)rdir);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* retro_dirent_is_dir:
|
||||
* @rdir : pointer to the directory entry.
|
||||
* @unused : deprecated, included for compatibility reasons, pass NULL
|
||||
*
|
||||
* Is the directory listing entry a directory?
|
||||
*
|
||||
* Returns: true if directory listing entry is
|
||||
* a directory, false if not.
|
||||
*/
|
||||
bool retro_dirent_is_dir(struct RDIR *rdir, const char *unused)
|
||||
{
|
||||
if (dirent_dirent_is_dir_cb != NULL)
|
||||
return dirent_dirent_is_dir_cb((struct retro_vfs_dir_handle *)rdir);
|
||||
return retro_vfs_dirent_is_dir_impl((struct retro_vfs_dir_handle *)rdir);
|
||||
}
|
||||
|
||||
void retro_closedir(struct RDIR *rdir)
|
||||
{
|
||||
if (dirent_closedir_cb != NULL)
|
||||
dirent_closedir_cb((struct retro_vfs_dir_handle *)rdir);
|
||||
else
|
||||
retro_vfs_closedir_impl((struct retro_vfs_dir_handle *)rdir);
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,11 @@
|
||||
# Autogenerate GL extension loaders
|
||||
|
||||
## OpenGL desktop
|
||||
|
||||
Use Khronos' recent [header](www.opengl.org/registry/api/glext.h).
|
||||
|
||||
./glgen.py /usr/include/GL/glext.h glsym_gl.h glsym_gl.c
|
||||
|
||||
## OpenGL ES
|
||||
|
||||
./glgen.py /usr/include/GLES2/gl2ext.h glsym_es2.h glsym_es2.c
|
||||
Executable
+157
@@ -0,0 +1,157 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
License statement applies to this file (glgen.py) only.
|
||||
"""
|
||||
|
||||
"""
|
||||
Permission is hereby granted, free of charge,
|
||||
to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
import re
|
||||
|
||||
banned_ext = [ 'AMD', 'APPLE', 'NV', 'NVX', 'ATI', '3DLABS', 'SUN', 'SGI', 'SGIX', 'SGIS', 'INTEL', '3DFX', 'IBM', 'MESA', 'GREMEDY', 'OML', 'PGI', 'I3D', 'INGL', 'MTX', 'QCOM', 'IMG', 'ANGLE', 'SUNX', 'INGR' ]
|
||||
|
||||
def noext(sym):
|
||||
for ext in banned_ext:
|
||||
if sym.endswith(ext):
|
||||
return False
|
||||
return True
|
||||
|
||||
def fix_multiline_functions(lines):
|
||||
fixed_lines = []
|
||||
temp_lines = []
|
||||
for line in lines:
|
||||
if line.count('(') > line.count(')'):
|
||||
temp_lines.append(line)
|
||||
else:
|
||||
if len(temp_lines) > 0:
|
||||
if line.count(')') > line.count('('):
|
||||
temp_lines.append(line)
|
||||
fixed_line = re.sub(' +',' ', ''.join(temp_lines).replace('\n','').replace('\t',''))
|
||||
fixed_lines.append(fixed_line)
|
||||
temp_lines = []
|
||||
else:
|
||||
temp_lines.append(line)
|
||||
else:
|
||||
fixed_lines.append(line)
|
||||
return fixed_lines
|
||||
|
||||
def find_gl_symbols(lines):
|
||||
typedefs = []
|
||||
syms = []
|
||||
for line in lines:
|
||||
m = re.search(r'^typedef.+PFN(\S+)PROC.+$', line)
|
||||
g = re.search(r'^.+(gl\S+)\W*\(.+\).*$', line)
|
||||
if m and noext(m.group(1)):
|
||||
typedefs.append(m.group(0).replace('PFN', 'RGLSYM').replace('GLDEBUGPROC', 'RGLGENGLDEBUGPROC'))
|
||||
if g and noext(g.group(1)):
|
||||
syms.append(g.group(1))
|
||||
return (typedefs, syms)
|
||||
|
||||
def generate_defines(gl_syms):
|
||||
res = []
|
||||
for line in gl_syms:
|
||||
res.append('#define {} __rglgen_{}'.format(line, line))
|
||||
return res
|
||||
|
||||
def generate_declarations(gl_syms):
|
||||
return ['RGLSYM' + x.upper() + 'PROC ' + '__rglgen_' + x + ';' for x in gl_syms]
|
||||
|
||||
def generate_macros(gl_syms):
|
||||
return [' SYM(' + x.replace('gl', '') + '),' for x in gl_syms]
|
||||
|
||||
def dump(f, lines):
|
||||
f.write('\n'.join(lines))
|
||||
f.write('\n\n')
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
if len(sys.argv) > 4:
|
||||
for banned in sys.argv[4:]:
|
||||
banned_ext.append(banned)
|
||||
|
||||
with open(sys.argv[1], 'r') as f:
|
||||
lines = fix_multiline_functions(f.readlines())
|
||||
typedefs, syms = find_gl_symbols(lines)
|
||||
|
||||
overrides = generate_defines(syms)
|
||||
declarations = generate_declarations(syms)
|
||||
externs = ['extern ' + x for x in declarations]
|
||||
|
||||
macros = generate_macros(syms)
|
||||
|
||||
with open(sys.argv[2], 'w') as f:
|
||||
f.write('#ifndef RGLGEN_DECL_H__\n')
|
||||
f.write('#define RGLGEN_DECL_H__\n')
|
||||
|
||||
f.write('#ifdef __cplusplus\n')
|
||||
f.write('extern "C" {\n')
|
||||
f.write('#endif\n')
|
||||
|
||||
f.write('#ifdef GL_APIENTRY\n')
|
||||
f.write('typedef void (GL_APIENTRY *RGLGENGLDEBUGPROC)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\n')
|
||||
f.write('typedef void (GL_APIENTRY *RGLGENGLDEBUGPROCKHR)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\n')
|
||||
f.write('#else\n')
|
||||
f.write('#ifndef APIENTRY\n')
|
||||
f.write('#define APIENTRY\n')
|
||||
f.write('#endif\n')
|
||||
f.write('#ifndef APIENTRYP\n')
|
||||
f.write('#define APIENTRYP APIENTRY *\n')
|
||||
f.write('#endif\n')
|
||||
f.write('typedef void (APIENTRY *RGLGENGLDEBUGPROCARB)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\n')
|
||||
f.write('typedef void (APIENTRY *RGLGENGLDEBUGPROC)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\n')
|
||||
f.write('#endif\n')
|
||||
|
||||
f.write('#ifndef GL_OES_EGL_image\n')
|
||||
f.write('typedef void *GLeglImageOES;\n')
|
||||
f.write('#endif\n')
|
||||
|
||||
f.write('#if !defined(GL_OES_fixed_point) && !defined(HAVE_OPENGLES2)\n')
|
||||
f.write('typedef GLint GLfixed;\n')
|
||||
f.write('#endif\n')
|
||||
|
||||
f.write('#if defined(OSX) && !defined(MAC_OS_X_VERSION_10_7)\n')
|
||||
f.write('typedef long long int GLint64;\n')
|
||||
f.write('typedef unsigned long long int GLuint64;\n')
|
||||
f.write('typedef unsigned long long int GLuint64EXT;\n')
|
||||
f.write('typedef struct __GLsync *GLsync;\n')
|
||||
f.write('#endif\n')
|
||||
|
||||
dump(f, typedefs)
|
||||
dump(f, overrides)
|
||||
dump(f, externs)
|
||||
|
||||
f.write('struct rglgen_sym_map { const char *sym; void *ptr; };\n')
|
||||
f.write('extern const struct rglgen_sym_map rglgen_symbol_map[];\n')
|
||||
|
||||
f.write('#ifdef __cplusplus\n')
|
||||
f.write('}\n')
|
||||
f.write('#endif\n')
|
||||
|
||||
f.write('#endif\n')
|
||||
|
||||
with open(sys.argv[3], 'w') as f:
|
||||
f.write('#include "glsym/glsym.h"\n')
|
||||
f.write('#include <stddef.h>\n')
|
||||
f.write('#define SYM(x) { "gl" #x, &(gl##x) }\n')
|
||||
f.write('const struct rglgen_sym_map rglgen_symbol_map[] = {\n')
|
||||
dump(f, macros)
|
||||
f.write(' { NULL, NULL },\n')
|
||||
f.write('};\n')
|
||||
dump(f, declarations)
|
||||
@@ -0,0 +1,409 @@
|
||||
#include "glsym/glsym.h"
|
||||
#include <stddef.h>
|
||||
#define SYM(x) { "gl" #x, &(gl##x) }
|
||||
const struct rglgen_sym_map rglgen_symbol_map[] = {
|
||||
SYM(BlendBarrierKHR),
|
||||
SYM(DebugMessageControlKHR),
|
||||
SYM(DebugMessageInsertKHR),
|
||||
SYM(DebugMessageCallbackKHR),
|
||||
SYM(GetDebugMessageLogKHR),
|
||||
SYM(PushDebugGroupKHR),
|
||||
SYM(PopDebugGroupKHR),
|
||||
SYM(ObjectLabelKHR),
|
||||
SYM(GetObjectLabelKHR),
|
||||
SYM(ObjectPtrLabelKHR),
|
||||
SYM(GetObjectPtrLabelKHR),
|
||||
SYM(GetPointervKHR),
|
||||
SYM(GetGraphicsResetStatusKHR),
|
||||
SYM(ReadnPixelsKHR),
|
||||
SYM(GetnUniformfvKHR),
|
||||
SYM(GetnUniformivKHR),
|
||||
SYM(GetnUniformuivKHR),
|
||||
SYM(EGLImageTargetTexture2DOES),
|
||||
SYM(EGLImageTargetRenderbufferStorageOES),
|
||||
SYM(CopyImageSubDataOES),
|
||||
SYM(EnableiOES),
|
||||
SYM(DisableiOES),
|
||||
SYM(BlendEquationiOES),
|
||||
SYM(BlendEquationSeparateiOES),
|
||||
SYM(BlendFunciOES),
|
||||
SYM(BlendFuncSeparateiOES),
|
||||
SYM(ColorMaskiOES),
|
||||
SYM(IsEnablediOES),
|
||||
SYM(DrawElementsBaseVertexOES),
|
||||
SYM(DrawRangeElementsBaseVertexOES),
|
||||
SYM(DrawElementsInstancedBaseVertexOES),
|
||||
SYM(MultiDrawElementsBaseVertexOES),
|
||||
SYM(FramebufferTextureOES),
|
||||
SYM(GetProgramBinaryOES),
|
||||
SYM(ProgramBinaryOES),
|
||||
SYM(MapBufferOES),
|
||||
SYM(UnmapBufferOES),
|
||||
SYM(GetBufferPointervOES),
|
||||
SYM(PrimitiveBoundingBoxOES),
|
||||
SYM(MinSampleShadingOES),
|
||||
SYM(PatchParameteriOES),
|
||||
SYM(TexImage3DOES),
|
||||
SYM(TexSubImage3DOES),
|
||||
SYM(CopyTexSubImage3DOES),
|
||||
SYM(CompressedTexImage3DOES),
|
||||
SYM(CompressedTexSubImage3DOES),
|
||||
SYM(FramebufferTexture3DOES),
|
||||
SYM(TexParameterIivOES),
|
||||
SYM(TexParameterIuivOES),
|
||||
SYM(GetTexParameterIivOES),
|
||||
SYM(GetTexParameterIuivOES),
|
||||
SYM(SamplerParameterIivOES),
|
||||
SYM(SamplerParameterIuivOES),
|
||||
SYM(GetSamplerParameterIivOES),
|
||||
SYM(GetSamplerParameterIuivOES),
|
||||
SYM(TexBufferOES),
|
||||
SYM(TexBufferRangeOES),
|
||||
SYM(TexStorage3DMultisampleOES),
|
||||
SYM(TextureViewOES),
|
||||
SYM(BindVertexArrayOES),
|
||||
SYM(DeleteVertexArraysOES),
|
||||
SYM(GenVertexArraysOES),
|
||||
SYM(IsVertexArrayOES),
|
||||
SYM(ViewportArrayvOES),
|
||||
SYM(ViewportIndexedfOES),
|
||||
SYM(ViewportIndexedfvOES),
|
||||
SYM(ScissorArrayvOES),
|
||||
SYM(ScissorIndexedOES),
|
||||
SYM(ScissorIndexedvOES),
|
||||
SYM(DepthRangeArrayfvOES),
|
||||
SYM(DepthRangeIndexedfOES),
|
||||
SYM(GetFloati_vOES),
|
||||
SYM(DrawArraysInstancedBaseInstanceEXT),
|
||||
SYM(DrawElementsInstancedBaseInstanceEXT),
|
||||
SYM(DrawElementsInstancedBaseVertexBaseInstanceEXT),
|
||||
SYM(BindFragDataLocationIndexedEXT),
|
||||
SYM(BindFragDataLocationEXT),
|
||||
SYM(GetProgramResourceLocationIndexEXT),
|
||||
SYM(GetFragDataIndexEXT),
|
||||
SYM(BufferStorageEXT),
|
||||
SYM(ClearTexImageEXT),
|
||||
SYM(ClearTexSubImageEXT),
|
||||
SYM(CopyImageSubDataEXT),
|
||||
SYM(LabelObjectEXT),
|
||||
SYM(GetObjectLabelEXT),
|
||||
SYM(InsertEventMarkerEXT),
|
||||
SYM(PushGroupMarkerEXT),
|
||||
SYM(PopGroupMarkerEXT),
|
||||
SYM(DiscardFramebufferEXT),
|
||||
SYM(GenQueriesEXT),
|
||||
SYM(DeleteQueriesEXT),
|
||||
SYM(IsQueryEXT),
|
||||
SYM(BeginQueryEXT),
|
||||
SYM(EndQueryEXT),
|
||||
SYM(QueryCounterEXT),
|
||||
SYM(GetQueryivEXT),
|
||||
SYM(GetQueryObjectivEXT),
|
||||
SYM(GetQueryObjectuivEXT),
|
||||
SYM(DrawBuffersEXT),
|
||||
SYM(EnableiEXT),
|
||||
SYM(DisableiEXT),
|
||||
SYM(BlendEquationiEXT),
|
||||
SYM(BlendEquationSeparateiEXT),
|
||||
SYM(BlendFunciEXT),
|
||||
SYM(BlendFuncSeparateiEXT),
|
||||
SYM(ColorMaskiEXT),
|
||||
SYM(IsEnablediEXT),
|
||||
SYM(DrawElementsBaseVertexEXT),
|
||||
SYM(DrawRangeElementsBaseVertexEXT),
|
||||
SYM(DrawElementsInstancedBaseVertexEXT),
|
||||
SYM(MultiDrawElementsBaseVertexEXT),
|
||||
SYM(DrawArraysInstancedEXT),
|
||||
SYM(DrawElementsInstancedEXT),
|
||||
SYM(FramebufferTextureEXT),
|
||||
SYM(VertexAttribDivisorEXT),
|
||||
SYM(MapBufferRangeEXT),
|
||||
SYM(FlushMappedBufferRangeEXT),
|
||||
SYM(MultiDrawArraysEXT),
|
||||
SYM(MultiDrawElementsEXT),
|
||||
SYM(MultiDrawArraysIndirectEXT),
|
||||
SYM(MultiDrawElementsIndirectEXT),
|
||||
SYM(RenderbufferStorageMultisampleEXT),
|
||||
SYM(FramebufferTexture2DMultisampleEXT),
|
||||
SYM(ReadBufferIndexedEXT),
|
||||
SYM(DrawBuffersIndexedEXT),
|
||||
SYM(GetIntegeri_vEXT),
|
||||
SYM(PolygonOffsetClampEXT),
|
||||
SYM(PrimitiveBoundingBoxEXT),
|
||||
SYM(RasterSamplesEXT),
|
||||
SYM(GetGraphicsResetStatusEXT),
|
||||
SYM(ReadnPixelsEXT),
|
||||
SYM(GetnUniformfvEXT),
|
||||
SYM(GetnUniformivEXT),
|
||||
SYM(ActiveShaderProgramEXT),
|
||||
SYM(BindProgramPipelineEXT),
|
||||
SYM(CreateShaderProgramvEXT),
|
||||
SYM(DeleteProgramPipelinesEXT),
|
||||
SYM(GenProgramPipelinesEXT),
|
||||
SYM(GetProgramPipelineInfoLogEXT),
|
||||
SYM(GetProgramPipelineivEXT),
|
||||
SYM(IsProgramPipelineEXT),
|
||||
SYM(ProgramParameteriEXT),
|
||||
SYM(ProgramUniform1fEXT),
|
||||
SYM(ProgramUniform1fvEXT),
|
||||
SYM(ProgramUniform1iEXT),
|
||||
SYM(ProgramUniform1ivEXT),
|
||||
SYM(ProgramUniform2fEXT),
|
||||
SYM(ProgramUniform2fvEXT),
|
||||
SYM(ProgramUniform2iEXT),
|
||||
SYM(ProgramUniform2ivEXT),
|
||||
SYM(ProgramUniform3fEXT),
|
||||
SYM(ProgramUniform3fvEXT),
|
||||
SYM(ProgramUniform3iEXT),
|
||||
SYM(ProgramUniform3ivEXT),
|
||||
SYM(ProgramUniform4fEXT),
|
||||
SYM(ProgramUniform4fvEXT),
|
||||
SYM(ProgramUniform4iEXT),
|
||||
SYM(ProgramUniform4ivEXT),
|
||||
SYM(ProgramUniformMatrix2fvEXT),
|
||||
SYM(ProgramUniformMatrix3fvEXT),
|
||||
SYM(ProgramUniformMatrix4fvEXT),
|
||||
SYM(UseProgramStagesEXT),
|
||||
SYM(ValidateProgramPipelineEXT),
|
||||
SYM(ProgramUniform1uiEXT),
|
||||
SYM(ProgramUniform2uiEXT),
|
||||
SYM(ProgramUniform3uiEXT),
|
||||
SYM(ProgramUniform4uiEXT),
|
||||
SYM(ProgramUniform1uivEXT),
|
||||
SYM(ProgramUniform2uivEXT),
|
||||
SYM(ProgramUniform3uivEXT),
|
||||
SYM(ProgramUniform4uivEXT),
|
||||
SYM(ProgramUniformMatrix2x3fvEXT),
|
||||
SYM(ProgramUniformMatrix3x2fvEXT),
|
||||
SYM(ProgramUniformMatrix2x4fvEXT),
|
||||
SYM(ProgramUniformMatrix4x2fvEXT),
|
||||
SYM(ProgramUniformMatrix3x4fvEXT),
|
||||
SYM(ProgramUniformMatrix4x3fvEXT),
|
||||
SYM(FramebufferPixelLocalStorageSizeEXT),
|
||||
SYM(GetFramebufferPixelLocalStorageSizeEXT),
|
||||
SYM(ClearPixelLocalStorageuiEXT),
|
||||
SYM(TexPageCommitmentEXT),
|
||||
SYM(PatchParameteriEXT),
|
||||
SYM(TexParameterIivEXT),
|
||||
SYM(TexParameterIuivEXT),
|
||||
SYM(GetTexParameterIivEXT),
|
||||
SYM(GetTexParameterIuivEXT),
|
||||
SYM(SamplerParameterIivEXT),
|
||||
SYM(SamplerParameterIuivEXT),
|
||||
SYM(GetSamplerParameterIivEXT),
|
||||
SYM(GetSamplerParameterIuivEXT),
|
||||
SYM(TexBufferEXT),
|
||||
SYM(TexBufferRangeEXT),
|
||||
SYM(TexStorage1DEXT),
|
||||
SYM(TexStorage2DEXT),
|
||||
SYM(TexStorage3DEXT),
|
||||
SYM(TextureStorage1DEXT),
|
||||
SYM(TextureStorage2DEXT),
|
||||
SYM(TextureStorage3DEXT),
|
||||
SYM(TextureViewEXT),
|
||||
SYM(FramebufferTextureMultiviewOVR),
|
||||
SYM(FramebufferTextureMultisampleMultiviewOVR),
|
||||
|
||||
{ NULL, NULL },
|
||||
};
|
||||
RGLSYMGLBLENDBARRIERKHRPROC __rglgen_glBlendBarrierKHR;
|
||||
RGLSYMGLDEBUGMESSAGECONTROLKHRPROC __rglgen_glDebugMessageControlKHR;
|
||||
RGLSYMGLDEBUGMESSAGEINSERTKHRPROC __rglgen_glDebugMessageInsertKHR;
|
||||
RGLSYMGLDEBUGMESSAGECALLBACKKHRPROC __rglgen_glDebugMessageCallbackKHR;
|
||||
RGLSYMGLGETDEBUGMESSAGELOGKHRPROC __rglgen_glGetDebugMessageLogKHR;
|
||||
RGLSYMGLPUSHDEBUGGROUPKHRPROC __rglgen_glPushDebugGroupKHR;
|
||||
RGLSYMGLPOPDEBUGGROUPKHRPROC __rglgen_glPopDebugGroupKHR;
|
||||
RGLSYMGLOBJECTLABELKHRPROC __rglgen_glObjectLabelKHR;
|
||||
RGLSYMGLGETOBJECTLABELKHRPROC __rglgen_glGetObjectLabelKHR;
|
||||
RGLSYMGLOBJECTPTRLABELKHRPROC __rglgen_glObjectPtrLabelKHR;
|
||||
RGLSYMGLGETOBJECTPTRLABELKHRPROC __rglgen_glGetObjectPtrLabelKHR;
|
||||
RGLSYMGLGETPOINTERVKHRPROC __rglgen_glGetPointervKHR;
|
||||
RGLSYMGLGETGRAPHICSRESETSTATUSKHRPROC __rglgen_glGetGraphicsResetStatusKHR;
|
||||
RGLSYMGLREADNPIXELSKHRPROC __rglgen_glReadnPixelsKHR;
|
||||
RGLSYMGLGETNUNIFORMFVKHRPROC __rglgen_glGetnUniformfvKHR;
|
||||
RGLSYMGLGETNUNIFORMIVKHRPROC __rglgen_glGetnUniformivKHR;
|
||||
RGLSYMGLGETNUNIFORMUIVKHRPROC __rglgen_glGetnUniformuivKHR;
|
||||
RGLSYMGLEGLIMAGETARGETTEXTURE2DOESPROC __rglgen_glEGLImageTargetTexture2DOES;
|
||||
RGLSYMGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC __rglgen_glEGLImageTargetRenderbufferStorageOES;
|
||||
RGLSYMGLCOPYIMAGESUBDATAOESPROC __rglgen_glCopyImageSubDataOES;
|
||||
RGLSYMGLENABLEIOESPROC __rglgen_glEnableiOES;
|
||||
RGLSYMGLDISABLEIOESPROC __rglgen_glDisableiOES;
|
||||
RGLSYMGLBLENDEQUATIONIOESPROC __rglgen_glBlendEquationiOES;
|
||||
RGLSYMGLBLENDEQUATIONSEPARATEIOESPROC __rglgen_glBlendEquationSeparateiOES;
|
||||
RGLSYMGLBLENDFUNCIOESPROC __rglgen_glBlendFunciOES;
|
||||
RGLSYMGLBLENDFUNCSEPARATEIOESPROC __rglgen_glBlendFuncSeparateiOES;
|
||||
RGLSYMGLCOLORMASKIOESPROC __rglgen_glColorMaskiOES;
|
||||
RGLSYMGLISENABLEDIOESPROC __rglgen_glIsEnablediOES;
|
||||
RGLSYMGLDRAWELEMENTSBASEVERTEXOESPROC __rglgen_glDrawElementsBaseVertexOES;
|
||||
RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXOESPROC __rglgen_glDrawRangeElementsBaseVertexOES;
|
||||
RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXOESPROC __rglgen_glDrawElementsInstancedBaseVertexOES;
|
||||
RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXOESPROC __rglgen_glMultiDrawElementsBaseVertexOES;
|
||||
RGLSYMGLFRAMEBUFFERTEXTUREOESPROC __rglgen_glFramebufferTextureOES;
|
||||
RGLSYMGLGETPROGRAMBINARYOESPROC __rglgen_glGetProgramBinaryOES;
|
||||
RGLSYMGLPROGRAMBINARYOESPROC __rglgen_glProgramBinaryOES;
|
||||
RGLSYMGLMAPBUFFEROESPROC __rglgen_glMapBufferOES;
|
||||
RGLSYMGLUNMAPBUFFEROESPROC __rglgen_glUnmapBufferOES;
|
||||
RGLSYMGLGETBUFFERPOINTERVOESPROC __rglgen_glGetBufferPointervOES;
|
||||
RGLSYMGLPRIMITIVEBOUNDINGBOXOESPROC __rglgen_glPrimitiveBoundingBoxOES;
|
||||
RGLSYMGLMINSAMPLESHADINGOESPROC __rglgen_glMinSampleShadingOES;
|
||||
RGLSYMGLPATCHPARAMETERIOESPROC __rglgen_glPatchParameteriOES;
|
||||
RGLSYMGLTEXIMAGE3DOESPROC __rglgen_glTexImage3DOES;
|
||||
RGLSYMGLTEXSUBIMAGE3DOESPROC __rglgen_glTexSubImage3DOES;
|
||||
RGLSYMGLCOPYTEXSUBIMAGE3DOESPROC __rglgen_glCopyTexSubImage3DOES;
|
||||
RGLSYMGLCOMPRESSEDTEXIMAGE3DOESPROC __rglgen_glCompressedTexImage3DOES;
|
||||
RGLSYMGLCOMPRESSEDTEXSUBIMAGE3DOESPROC __rglgen_glCompressedTexSubImage3DOES;
|
||||
RGLSYMGLFRAMEBUFFERTEXTURE3DOESPROC __rglgen_glFramebufferTexture3DOES;
|
||||
RGLSYMGLTEXPARAMETERIIVOESPROC __rglgen_glTexParameterIivOES;
|
||||
RGLSYMGLTEXPARAMETERIUIVOESPROC __rglgen_glTexParameterIuivOES;
|
||||
RGLSYMGLGETTEXPARAMETERIIVOESPROC __rglgen_glGetTexParameterIivOES;
|
||||
RGLSYMGLGETTEXPARAMETERIUIVOESPROC __rglgen_glGetTexParameterIuivOES;
|
||||
RGLSYMGLSAMPLERPARAMETERIIVOESPROC __rglgen_glSamplerParameterIivOES;
|
||||
RGLSYMGLSAMPLERPARAMETERIUIVOESPROC __rglgen_glSamplerParameterIuivOES;
|
||||
RGLSYMGLGETSAMPLERPARAMETERIIVOESPROC __rglgen_glGetSamplerParameterIivOES;
|
||||
RGLSYMGLGETSAMPLERPARAMETERIUIVOESPROC __rglgen_glGetSamplerParameterIuivOES;
|
||||
RGLSYMGLTEXBUFFEROESPROC __rglgen_glTexBufferOES;
|
||||
RGLSYMGLTEXBUFFERRANGEOESPROC __rglgen_glTexBufferRangeOES;
|
||||
RGLSYMGLTEXSTORAGE3DMULTISAMPLEOESPROC __rglgen_glTexStorage3DMultisampleOES;
|
||||
RGLSYMGLTEXTUREVIEWOESPROC __rglgen_glTextureViewOES;
|
||||
RGLSYMGLBINDVERTEXARRAYOESPROC __rglgen_glBindVertexArrayOES;
|
||||
RGLSYMGLDELETEVERTEXARRAYSOESPROC __rglgen_glDeleteVertexArraysOES;
|
||||
RGLSYMGLGENVERTEXARRAYSOESPROC __rglgen_glGenVertexArraysOES;
|
||||
RGLSYMGLISVERTEXARRAYOESPROC __rglgen_glIsVertexArrayOES;
|
||||
RGLSYMGLVIEWPORTARRAYVOESPROC __rglgen_glViewportArrayvOES;
|
||||
RGLSYMGLVIEWPORTINDEXEDFOESPROC __rglgen_glViewportIndexedfOES;
|
||||
RGLSYMGLVIEWPORTINDEXEDFVOESPROC __rglgen_glViewportIndexedfvOES;
|
||||
RGLSYMGLSCISSORARRAYVOESPROC __rglgen_glScissorArrayvOES;
|
||||
RGLSYMGLSCISSORINDEXEDOESPROC __rglgen_glScissorIndexedOES;
|
||||
RGLSYMGLSCISSORINDEXEDVOESPROC __rglgen_glScissorIndexedvOES;
|
||||
RGLSYMGLDEPTHRANGEARRAYFVOESPROC __rglgen_glDepthRangeArrayfvOES;
|
||||
RGLSYMGLDEPTHRANGEINDEXEDFOESPROC __rglgen_glDepthRangeIndexedfOES;
|
||||
RGLSYMGLGETFLOATI_VOESPROC __rglgen_glGetFloati_vOES;
|
||||
RGLSYMGLDRAWARRAYSINSTANCEDBASEINSTANCEEXTPROC __rglgen_glDrawArraysInstancedBaseInstanceEXT;
|
||||
RGLSYMGLDRAWELEMENTSINSTANCEDBASEINSTANCEEXTPROC __rglgen_glDrawElementsInstancedBaseInstanceEXT;
|
||||
RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEEXTPROC __rglgen_glDrawElementsInstancedBaseVertexBaseInstanceEXT;
|
||||
RGLSYMGLBINDFRAGDATALOCATIONINDEXEDEXTPROC __rglgen_glBindFragDataLocationIndexedEXT;
|
||||
RGLSYMGLBINDFRAGDATALOCATIONEXTPROC __rglgen_glBindFragDataLocationEXT;
|
||||
RGLSYMGLGETPROGRAMRESOURCELOCATIONINDEXEXTPROC __rglgen_glGetProgramResourceLocationIndexEXT;
|
||||
RGLSYMGLGETFRAGDATAINDEXEXTPROC __rglgen_glGetFragDataIndexEXT;
|
||||
RGLSYMGLBUFFERSTORAGEEXTPROC __rglgen_glBufferStorageEXT;
|
||||
RGLSYMGLCLEARTEXIMAGEEXTPROC __rglgen_glClearTexImageEXT;
|
||||
RGLSYMGLCLEARTEXSUBIMAGEEXTPROC __rglgen_glClearTexSubImageEXT;
|
||||
RGLSYMGLCOPYIMAGESUBDATAEXTPROC __rglgen_glCopyImageSubDataEXT;
|
||||
RGLSYMGLLABELOBJECTEXTPROC __rglgen_glLabelObjectEXT;
|
||||
RGLSYMGLGETOBJECTLABELEXTPROC __rglgen_glGetObjectLabelEXT;
|
||||
RGLSYMGLINSERTEVENTMARKEREXTPROC __rglgen_glInsertEventMarkerEXT;
|
||||
RGLSYMGLPUSHGROUPMARKEREXTPROC __rglgen_glPushGroupMarkerEXT;
|
||||
RGLSYMGLPOPGROUPMARKEREXTPROC __rglgen_glPopGroupMarkerEXT;
|
||||
RGLSYMGLDISCARDFRAMEBUFFEREXTPROC __rglgen_glDiscardFramebufferEXT;
|
||||
RGLSYMGLGENQUERIESEXTPROC __rglgen_glGenQueriesEXT;
|
||||
RGLSYMGLDELETEQUERIESEXTPROC __rglgen_glDeleteQueriesEXT;
|
||||
RGLSYMGLISQUERYEXTPROC __rglgen_glIsQueryEXT;
|
||||
RGLSYMGLBEGINQUERYEXTPROC __rglgen_glBeginQueryEXT;
|
||||
RGLSYMGLENDQUERYEXTPROC __rglgen_glEndQueryEXT;
|
||||
RGLSYMGLQUERYCOUNTEREXTPROC __rglgen_glQueryCounterEXT;
|
||||
RGLSYMGLGETQUERYIVEXTPROC __rglgen_glGetQueryivEXT;
|
||||
RGLSYMGLGETQUERYOBJECTIVEXTPROC __rglgen_glGetQueryObjectivEXT;
|
||||
RGLSYMGLGETQUERYOBJECTUIVEXTPROC __rglgen_glGetQueryObjectuivEXT;
|
||||
RGLSYMGLDRAWBUFFERSEXTPROC __rglgen_glDrawBuffersEXT;
|
||||
RGLSYMGLENABLEIEXTPROC __rglgen_glEnableiEXT;
|
||||
RGLSYMGLDISABLEIEXTPROC __rglgen_glDisableiEXT;
|
||||
RGLSYMGLBLENDEQUATIONIEXTPROC __rglgen_glBlendEquationiEXT;
|
||||
RGLSYMGLBLENDEQUATIONSEPARATEIEXTPROC __rglgen_glBlendEquationSeparateiEXT;
|
||||
RGLSYMGLBLENDFUNCIEXTPROC __rglgen_glBlendFunciEXT;
|
||||
RGLSYMGLBLENDFUNCSEPARATEIEXTPROC __rglgen_glBlendFuncSeparateiEXT;
|
||||
RGLSYMGLCOLORMASKIEXTPROC __rglgen_glColorMaskiEXT;
|
||||
RGLSYMGLISENABLEDIEXTPROC __rglgen_glIsEnablediEXT;
|
||||
RGLSYMGLDRAWELEMENTSBASEVERTEXEXTPROC __rglgen_glDrawElementsBaseVertexEXT;
|
||||
RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXEXTPROC __rglgen_glDrawRangeElementsBaseVertexEXT;
|
||||
RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXEXTPROC __rglgen_glDrawElementsInstancedBaseVertexEXT;
|
||||
RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXEXTPROC __rglgen_glMultiDrawElementsBaseVertexEXT;
|
||||
RGLSYMGLDRAWARRAYSINSTANCEDEXTPROC __rglgen_glDrawArraysInstancedEXT;
|
||||
RGLSYMGLDRAWELEMENTSINSTANCEDEXTPROC __rglgen_glDrawElementsInstancedEXT;
|
||||
RGLSYMGLFRAMEBUFFERTEXTUREEXTPROC __rglgen_glFramebufferTextureEXT;
|
||||
RGLSYMGLVERTEXATTRIBDIVISOREXTPROC __rglgen_glVertexAttribDivisorEXT;
|
||||
RGLSYMGLMAPBUFFERRANGEEXTPROC __rglgen_glMapBufferRangeEXT;
|
||||
RGLSYMGLFLUSHMAPPEDBUFFERRANGEEXTPROC __rglgen_glFlushMappedBufferRangeEXT;
|
||||
RGLSYMGLMULTIDRAWARRAYSEXTPROC __rglgen_glMultiDrawArraysEXT;
|
||||
RGLSYMGLMULTIDRAWELEMENTSEXTPROC __rglgen_glMultiDrawElementsEXT;
|
||||
RGLSYMGLMULTIDRAWARRAYSINDIRECTEXTPROC __rglgen_glMultiDrawArraysIndirectEXT;
|
||||
RGLSYMGLMULTIDRAWELEMENTSINDIRECTEXTPROC __rglgen_glMultiDrawElementsIndirectEXT;
|
||||
RGLSYMGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC __rglgen_glRenderbufferStorageMultisampleEXT;
|
||||
RGLSYMGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC __rglgen_glFramebufferTexture2DMultisampleEXT;
|
||||
RGLSYMGLREADBUFFERINDEXEDEXTPROC __rglgen_glReadBufferIndexedEXT;
|
||||
RGLSYMGLDRAWBUFFERSINDEXEDEXTPROC __rglgen_glDrawBuffersIndexedEXT;
|
||||
RGLSYMGLGETINTEGERI_VEXTPROC __rglgen_glGetIntegeri_vEXT;
|
||||
RGLSYMGLPOLYGONOFFSETCLAMPEXTPROC __rglgen_glPolygonOffsetClampEXT;
|
||||
RGLSYMGLPRIMITIVEBOUNDINGBOXEXTPROC __rglgen_glPrimitiveBoundingBoxEXT;
|
||||
RGLSYMGLRASTERSAMPLESEXTPROC __rglgen_glRasterSamplesEXT;
|
||||
RGLSYMGLGETGRAPHICSRESETSTATUSEXTPROC __rglgen_glGetGraphicsResetStatusEXT;
|
||||
RGLSYMGLREADNPIXELSEXTPROC __rglgen_glReadnPixelsEXT;
|
||||
RGLSYMGLGETNUNIFORMFVEXTPROC __rglgen_glGetnUniformfvEXT;
|
||||
RGLSYMGLGETNUNIFORMIVEXTPROC __rglgen_glGetnUniformivEXT;
|
||||
RGLSYMGLACTIVESHADERPROGRAMEXTPROC __rglgen_glActiveShaderProgramEXT;
|
||||
RGLSYMGLBINDPROGRAMPIPELINEEXTPROC __rglgen_glBindProgramPipelineEXT;
|
||||
RGLSYMGLCREATESHADERPROGRAMVEXTPROC __rglgen_glCreateShaderProgramvEXT;
|
||||
RGLSYMGLDELETEPROGRAMPIPELINESEXTPROC __rglgen_glDeleteProgramPipelinesEXT;
|
||||
RGLSYMGLGENPROGRAMPIPELINESEXTPROC __rglgen_glGenProgramPipelinesEXT;
|
||||
RGLSYMGLGETPROGRAMPIPELINEINFOLOGEXTPROC __rglgen_glGetProgramPipelineInfoLogEXT;
|
||||
RGLSYMGLGETPROGRAMPIPELINEIVEXTPROC __rglgen_glGetProgramPipelineivEXT;
|
||||
RGLSYMGLISPROGRAMPIPELINEEXTPROC __rglgen_glIsProgramPipelineEXT;
|
||||
RGLSYMGLPROGRAMPARAMETERIEXTPROC __rglgen_glProgramParameteriEXT;
|
||||
RGLSYMGLPROGRAMUNIFORM1FEXTPROC __rglgen_glProgramUniform1fEXT;
|
||||
RGLSYMGLPROGRAMUNIFORM1FVEXTPROC __rglgen_glProgramUniform1fvEXT;
|
||||
RGLSYMGLPROGRAMUNIFORM1IEXTPROC __rglgen_glProgramUniform1iEXT;
|
||||
RGLSYMGLPROGRAMUNIFORM1IVEXTPROC __rglgen_glProgramUniform1ivEXT;
|
||||
RGLSYMGLPROGRAMUNIFORM2FEXTPROC __rglgen_glProgramUniform2fEXT;
|
||||
RGLSYMGLPROGRAMUNIFORM2FVEXTPROC __rglgen_glProgramUniform2fvEXT;
|
||||
RGLSYMGLPROGRAMUNIFORM2IEXTPROC __rglgen_glProgramUniform2iEXT;
|
||||
RGLSYMGLPROGRAMUNIFORM2IVEXTPROC __rglgen_glProgramUniform2ivEXT;
|
||||
RGLSYMGLPROGRAMUNIFORM3FEXTPROC __rglgen_glProgramUniform3fEXT;
|
||||
RGLSYMGLPROGRAMUNIFORM3FVEXTPROC __rglgen_glProgramUniform3fvEXT;
|
||||
RGLSYMGLPROGRAMUNIFORM3IEXTPROC __rglgen_glProgramUniform3iEXT;
|
||||
RGLSYMGLPROGRAMUNIFORM3IVEXTPROC __rglgen_glProgramUniform3ivEXT;
|
||||
RGLSYMGLPROGRAMUNIFORM4FEXTPROC __rglgen_glProgramUniform4fEXT;
|
||||
RGLSYMGLPROGRAMUNIFORM4FVEXTPROC __rglgen_glProgramUniform4fvEXT;
|
||||
RGLSYMGLPROGRAMUNIFORM4IEXTPROC __rglgen_glProgramUniform4iEXT;
|
||||
RGLSYMGLPROGRAMUNIFORM4IVEXTPROC __rglgen_glProgramUniform4ivEXT;
|
||||
RGLSYMGLPROGRAMUNIFORMMATRIX2FVEXTPROC __rglgen_glProgramUniformMatrix2fvEXT;
|
||||
RGLSYMGLPROGRAMUNIFORMMATRIX3FVEXTPROC __rglgen_glProgramUniformMatrix3fvEXT;
|
||||
RGLSYMGLPROGRAMUNIFORMMATRIX4FVEXTPROC __rglgen_glProgramUniformMatrix4fvEXT;
|
||||
RGLSYMGLUSEPROGRAMSTAGESEXTPROC __rglgen_glUseProgramStagesEXT;
|
||||
RGLSYMGLVALIDATEPROGRAMPIPELINEEXTPROC __rglgen_glValidateProgramPipelineEXT;
|
||||
RGLSYMGLPROGRAMUNIFORM1UIEXTPROC __rglgen_glProgramUniform1uiEXT;
|
||||
RGLSYMGLPROGRAMUNIFORM2UIEXTPROC __rglgen_glProgramUniform2uiEXT;
|
||||
RGLSYMGLPROGRAMUNIFORM3UIEXTPROC __rglgen_glProgramUniform3uiEXT;
|
||||
RGLSYMGLPROGRAMUNIFORM4UIEXTPROC __rglgen_glProgramUniform4uiEXT;
|
||||
RGLSYMGLPROGRAMUNIFORM1UIVEXTPROC __rglgen_glProgramUniform1uivEXT;
|
||||
RGLSYMGLPROGRAMUNIFORM2UIVEXTPROC __rglgen_glProgramUniform2uivEXT;
|
||||
RGLSYMGLPROGRAMUNIFORM3UIVEXTPROC __rglgen_glProgramUniform3uivEXT;
|
||||
RGLSYMGLPROGRAMUNIFORM4UIVEXTPROC __rglgen_glProgramUniform4uivEXT;
|
||||
RGLSYMGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC __rglgen_glProgramUniformMatrix2x3fvEXT;
|
||||
RGLSYMGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC __rglgen_glProgramUniformMatrix3x2fvEXT;
|
||||
RGLSYMGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC __rglgen_glProgramUniformMatrix2x4fvEXT;
|
||||
RGLSYMGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC __rglgen_glProgramUniformMatrix4x2fvEXT;
|
||||
RGLSYMGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC __rglgen_glProgramUniformMatrix3x4fvEXT;
|
||||
RGLSYMGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC __rglgen_glProgramUniformMatrix4x3fvEXT;
|
||||
RGLSYMGLFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC __rglgen_glFramebufferPixelLocalStorageSizeEXT;
|
||||
RGLSYMGLGETFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC __rglgen_glGetFramebufferPixelLocalStorageSizeEXT;
|
||||
RGLSYMGLCLEARPIXELLOCALSTORAGEUIEXTPROC __rglgen_glClearPixelLocalStorageuiEXT;
|
||||
RGLSYMGLTEXPAGECOMMITMENTEXTPROC __rglgen_glTexPageCommitmentEXT;
|
||||
RGLSYMGLPATCHPARAMETERIEXTPROC __rglgen_glPatchParameteriEXT;
|
||||
RGLSYMGLTEXPARAMETERIIVEXTPROC __rglgen_glTexParameterIivEXT;
|
||||
RGLSYMGLTEXPARAMETERIUIVEXTPROC __rglgen_glTexParameterIuivEXT;
|
||||
RGLSYMGLGETTEXPARAMETERIIVEXTPROC __rglgen_glGetTexParameterIivEXT;
|
||||
RGLSYMGLGETTEXPARAMETERIUIVEXTPROC __rglgen_glGetTexParameterIuivEXT;
|
||||
RGLSYMGLSAMPLERPARAMETERIIVEXTPROC __rglgen_glSamplerParameterIivEXT;
|
||||
RGLSYMGLSAMPLERPARAMETERIUIVEXTPROC __rglgen_glSamplerParameterIuivEXT;
|
||||
RGLSYMGLGETSAMPLERPARAMETERIIVEXTPROC __rglgen_glGetSamplerParameterIivEXT;
|
||||
RGLSYMGLGETSAMPLERPARAMETERIUIVEXTPROC __rglgen_glGetSamplerParameterIuivEXT;
|
||||
RGLSYMGLTEXBUFFEREXTPROC __rglgen_glTexBufferEXT;
|
||||
RGLSYMGLTEXBUFFERRANGEEXTPROC __rglgen_glTexBufferRangeEXT;
|
||||
RGLSYMGLTEXSTORAGE1DEXTPROC __rglgen_glTexStorage1DEXT;
|
||||
RGLSYMGLTEXSTORAGE2DEXTPROC __rglgen_glTexStorage2DEXT;
|
||||
RGLSYMGLTEXSTORAGE3DEXTPROC __rglgen_glTexStorage3DEXT;
|
||||
RGLSYMGLTEXTURESTORAGE1DEXTPROC __rglgen_glTextureStorage1DEXT;
|
||||
RGLSYMGLTEXTURESTORAGE2DEXTPROC __rglgen_glTextureStorage2DEXT;
|
||||
RGLSYMGLTEXTURESTORAGE3DEXTPROC __rglgen_glTextureStorage3DEXT;
|
||||
RGLSYMGLTEXTUREVIEWEXTPROC __rglgen_glTextureViewEXT;
|
||||
RGLSYMGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC __rglgen_glFramebufferTextureMultiviewOVR;
|
||||
RGLSYMGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC __rglgen_glFramebufferTextureMultisampleMultiviewOVR;
|
||||
@@ -0,0 +1,413 @@
|
||||
#include "glsym/glsym.h"
|
||||
#include <stddef.h>
|
||||
#define SYM(x) { "gl" #x, &(gl##x) }
|
||||
const struct rglgen_sym_map rglgen_symbol_map[] = {
|
||||
SYM(BlendBarrierKHR),
|
||||
SYM(DebugMessageControlKHR),
|
||||
SYM(DebugMessageInsertKHR),
|
||||
SYM(DebugMessageCallbackKHR),
|
||||
SYM(GetDebugMessageLogKHR),
|
||||
SYM(PushDebugGroupKHR),
|
||||
SYM(PopDebugGroupKHR),
|
||||
SYM(ObjectLabelKHR),
|
||||
SYM(GetObjectLabelKHR),
|
||||
SYM(ObjectPtrLabelKHR),
|
||||
SYM(GetObjectPtrLabelKHR),
|
||||
SYM(GetPointervKHR),
|
||||
SYM(GetGraphicsResetStatusKHR),
|
||||
SYM(ReadnPixelsKHR),
|
||||
SYM(GetnUniformfvKHR),
|
||||
SYM(GetnUniformivKHR),
|
||||
SYM(GetnUniformuivKHR),
|
||||
SYM(EGLImageTargetTexture2DOES),
|
||||
SYM(EGLImageTargetRenderbufferStorageOES),
|
||||
SYM(CopyImageSubDataOES),
|
||||
SYM(EnableiOES),
|
||||
SYM(DisableiOES),
|
||||
SYM(BlendEquationiOES),
|
||||
SYM(BlendEquationSeparateiOES),
|
||||
SYM(BlendFunciOES),
|
||||
SYM(BlendFuncSeparateiOES),
|
||||
SYM(ColorMaskiOES),
|
||||
SYM(IsEnablediOES),
|
||||
SYM(DrawElementsBaseVertexOES),
|
||||
SYM(DrawRangeElementsBaseVertexOES),
|
||||
SYM(DrawElementsInstancedBaseVertexOES),
|
||||
SYM(MultiDrawElementsBaseVertexOES),
|
||||
SYM(FramebufferTextureOES),
|
||||
SYM(GetProgramBinaryOES),
|
||||
SYM(ProgramBinaryOES),
|
||||
SYM(MapBufferOES),
|
||||
SYM(UnmapBufferOES),
|
||||
SYM(GetBufferPointervOES),
|
||||
SYM(PrimitiveBoundingBoxOES),
|
||||
SYM(MinSampleShadingOES),
|
||||
SYM(PatchParameteriOES),
|
||||
SYM(TexImage3DOES),
|
||||
SYM(TexSubImage3DOES),
|
||||
SYM(CopyTexSubImage3DOES),
|
||||
SYM(CompressedTexImage3DOES),
|
||||
SYM(CompressedTexSubImage3DOES),
|
||||
SYM(FramebufferTexture3DOES),
|
||||
SYM(TexParameterIivOES),
|
||||
SYM(TexParameterIuivOES),
|
||||
SYM(GetTexParameterIivOES),
|
||||
SYM(GetTexParameterIuivOES),
|
||||
SYM(SamplerParameterIivOES),
|
||||
SYM(SamplerParameterIuivOES),
|
||||
SYM(GetSamplerParameterIivOES),
|
||||
SYM(GetSamplerParameterIuivOES),
|
||||
SYM(TexBufferOES),
|
||||
SYM(TexBufferRangeOES),
|
||||
SYM(TexStorage3DMultisampleOES),
|
||||
SYM(TextureViewOES),
|
||||
SYM(BindVertexArrayOES),
|
||||
SYM(DeleteVertexArraysOES),
|
||||
SYM(GenVertexArraysOES),
|
||||
SYM(IsVertexArrayOES),
|
||||
SYM(ViewportArrayvOES),
|
||||
SYM(ViewportIndexedfOES),
|
||||
SYM(ViewportIndexedfvOES),
|
||||
SYM(ScissorArrayvOES),
|
||||
SYM(ScissorIndexedOES),
|
||||
SYM(ScissorIndexedvOES),
|
||||
SYM(DepthRangeArrayfvOES),
|
||||
SYM(DepthRangeIndexedfOES),
|
||||
SYM(GetFloati_vOES),
|
||||
SYM(DrawArraysInstancedBaseInstanceEXT),
|
||||
SYM(DrawElementsInstancedBaseInstanceEXT),
|
||||
SYM(DrawElementsInstancedBaseVertexBaseInstanceEXT),
|
||||
SYM(BindFragDataLocationIndexedEXT),
|
||||
SYM(BindFragDataLocationEXT),
|
||||
SYM(GetProgramResourceLocationIndexEXT),
|
||||
SYM(GetFragDataIndexEXT),
|
||||
SYM(BufferStorageEXT),
|
||||
SYM(ClearTexImageEXT),
|
||||
SYM(ClearTexSubImageEXT),
|
||||
SYM(CopyImageSubDataEXT),
|
||||
SYM(LabelObjectEXT),
|
||||
SYM(GetObjectLabelEXT),
|
||||
SYM(InsertEventMarkerEXT),
|
||||
SYM(PushGroupMarkerEXT),
|
||||
SYM(PopGroupMarkerEXT),
|
||||
SYM(DiscardFramebufferEXT),
|
||||
SYM(GenQueriesEXT),
|
||||
SYM(DeleteQueriesEXT),
|
||||
SYM(IsQueryEXT),
|
||||
SYM(BeginQueryEXT),
|
||||
SYM(EndQueryEXT),
|
||||
SYM(QueryCounterEXT),
|
||||
SYM(GetQueryivEXT),
|
||||
SYM(GetQueryObjectivEXT),
|
||||
SYM(GetQueryObjectuivEXT),
|
||||
SYM(GetQueryObjecti64vEXT),
|
||||
SYM(GetQueryObjectui64vEXT),
|
||||
SYM(DrawBuffersEXT),
|
||||
SYM(EnableiEXT),
|
||||
SYM(DisableiEXT),
|
||||
SYM(BlendEquationiEXT),
|
||||
SYM(BlendEquationSeparateiEXT),
|
||||
SYM(BlendFunciEXT),
|
||||
SYM(BlendFuncSeparateiEXT),
|
||||
SYM(ColorMaskiEXT),
|
||||
SYM(IsEnablediEXT),
|
||||
SYM(DrawElementsBaseVertexEXT),
|
||||
SYM(DrawRangeElementsBaseVertexEXT),
|
||||
SYM(DrawElementsInstancedBaseVertexEXT),
|
||||
SYM(MultiDrawElementsBaseVertexEXT),
|
||||
SYM(DrawArraysInstancedEXT),
|
||||
SYM(DrawElementsInstancedEXT),
|
||||
SYM(FramebufferTextureEXT),
|
||||
SYM(VertexAttribDivisorEXT),
|
||||
SYM(MapBufferRangeEXT),
|
||||
SYM(FlushMappedBufferRangeEXT),
|
||||
SYM(MultiDrawArraysEXT),
|
||||
SYM(MultiDrawElementsEXT),
|
||||
SYM(MultiDrawArraysIndirectEXT),
|
||||
SYM(MultiDrawElementsIndirectEXT),
|
||||
SYM(RenderbufferStorageMultisampleEXT),
|
||||
SYM(FramebufferTexture2DMultisampleEXT),
|
||||
SYM(ReadBufferIndexedEXT),
|
||||
SYM(DrawBuffersIndexedEXT),
|
||||
SYM(GetIntegeri_vEXT),
|
||||
SYM(PolygonOffsetClampEXT),
|
||||
SYM(PrimitiveBoundingBoxEXT),
|
||||
SYM(RasterSamplesEXT),
|
||||
SYM(GetGraphicsResetStatusEXT),
|
||||
SYM(ReadnPixelsEXT),
|
||||
SYM(GetnUniformfvEXT),
|
||||
SYM(GetnUniformivEXT),
|
||||
SYM(ActiveShaderProgramEXT),
|
||||
SYM(BindProgramPipelineEXT),
|
||||
SYM(CreateShaderProgramvEXT),
|
||||
SYM(DeleteProgramPipelinesEXT),
|
||||
SYM(GenProgramPipelinesEXT),
|
||||
SYM(GetProgramPipelineInfoLogEXT),
|
||||
SYM(GetProgramPipelineivEXT),
|
||||
SYM(IsProgramPipelineEXT),
|
||||
SYM(ProgramParameteriEXT),
|
||||
SYM(ProgramUniform1fEXT),
|
||||
SYM(ProgramUniform1fvEXT),
|
||||
SYM(ProgramUniform1iEXT),
|
||||
SYM(ProgramUniform1ivEXT),
|
||||
SYM(ProgramUniform2fEXT),
|
||||
SYM(ProgramUniform2fvEXT),
|
||||
SYM(ProgramUniform2iEXT),
|
||||
SYM(ProgramUniform2ivEXT),
|
||||
SYM(ProgramUniform3fEXT),
|
||||
SYM(ProgramUniform3fvEXT),
|
||||
SYM(ProgramUniform3iEXT),
|
||||
SYM(ProgramUniform3ivEXT),
|
||||
SYM(ProgramUniform4fEXT),
|
||||
SYM(ProgramUniform4fvEXT),
|
||||
SYM(ProgramUniform4iEXT),
|
||||
SYM(ProgramUniform4ivEXT),
|
||||
SYM(ProgramUniformMatrix2fvEXT),
|
||||
SYM(ProgramUniformMatrix3fvEXT),
|
||||
SYM(ProgramUniformMatrix4fvEXT),
|
||||
SYM(UseProgramStagesEXT),
|
||||
SYM(ValidateProgramPipelineEXT),
|
||||
SYM(ProgramUniform1uiEXT),
|
||||
SYM(ProgramUniform2uiEXT),
|
||||
SYM(ProgramUniform3uiEXT),
|
||||
SYM(ProgramUniform4uiEXT),
|
||||
SYM(ProgramUniform1uivEXT),
|
||||
SYM(ProgramUniform2uivEXT),
|
||||
SYM(ProgramUniform3uivEXT),
|
||||
SYM(ProgramUniform4uivEXT),
|
||||
SYM(ProgramUniformMatrix2x3fvEXT),
|
||||
SYM(ProgramUniformMatrix3x2fvEXT),
|
||||
SYM(ProgramUniformMatrix2x4fvEXT),
|
||||
SYM(ProgramUniformMatrix4x2fvEXT),
|
||||
SYM(ProgramUniformMatrix3x4fvEXT),
|
||||
SYM(ProgramUniformMatrix4x3fvEXT),
|
||||
SYM(FramebufferPixelLocalStorageSizeEXT),
|
||||
SYM(GetFramebufferPixelLocalStorageSizeEXT),
|
||||
SYM(ClearPixelLocalStorageuiEXT),
|
||||
SYM(TexPageCommitmentEXT),
|
||||
SYM(PatchParameteriEXT),
|
||||
SYM(TexParameterIivEXT),
|
||||
SYM(TexParameterIuivEXT),
|
||||
SYM(GetTexParameterIivEXT),
|
||||
SYM(GetTexParameterIuivEXT),
|
||||
SYM(SamplerParameterIivEXT),
|
||||
SYM(SamplerParameterIuivEXT),
|
||||
SYM(GetSamplerParameterIivEXT),
|
||||
SYM(GetSamplerParameterIuivEXT),
|
||||
SYM(TexBufferEXT),
|
||||
SYM(TexBufferRangeEXT),
|
||||
SYM(TexStorage1DEXT),
|
||||
SYM(TexStorage2DEXT),
|
||||
SYM(TexStorage3DEXT),
|
||||
SYM(TextureStorage1DEXT),
|
||||
SYM(TextureStorage2DEXT),
|
||||
SYM(TextureStorage3DEXT),
|
||||
SYM(TextureViewEXT),
|
||||
SYM(FramebufferTextureMultiviewOVR),
|
||||
SYM(FramebufferTextureMultisampleMultiviewOVR),
|
||||
|
||||
{ NULL, NULL },
|
||||
};
|
||||
RGLSYMGLBLENDBARRIERKHRPROC __rglgen_glBlendBarrierKHR;
|
||||
RGLSYMGLDEBUGMESSAGECONTROLKHRPROC __rglgen_glDebugMessageControlKHR;
|
||||
RGLSYMGLDEBUGMESSAGEINSERTKHRPROC __rglgen_glDebugMessageInsertKHR;
|
||||
RGLSYMGLDEBUGMESSAGECALLBACKKHRPROC __rglgen_glDebugMessageCallbackKHR;
|
||||
RGLSYMGLGETDEBUGMESSAGELOGKHRPROC __rglgen_glGetDebugMessageLogKHR;
|
||||
RGLSYMGLPUSHDEBUGGROUPKHRPROC __rglgen_glPushDebugGroupKHR;
|
||||
RGLSYMGLPOPDEBUGGROUPKHRPROC __rglgen_glPopDebugGroupKHR;
|
||||
RGLSYMGLOBJECTLABELKHRPROC __rglgen_glObjectLabelKHR;
|
||||
RGLSYMGLGETOBJECTLABELKHRPROC __rglgen_glGetObjectLabelKHR;
|
||||
RGLSYMGLOBJECTPTRLABELKHRPROC __rglgen_glObjectPtrLabelKHR;
|
||||
RGLSYMGLGETOBJECTPTRLABELKHRPROC __rglgen_glGetObjectPtrLabelKHR;
|
||||
RGLSYMGLGETPOINTERVKHRPROC __rglgen_glGetPointervKHR;
|
||||
RGLSYMGLGETGRAPHICSRESETSTATUSKHRPROC __rglgen_glGetGraphicsResetStatusKHR;
|
||||
RGLSYMGLREADNPIXELSKHRPROC __rglgen_glReadnPixelsKHR;
|
||||
RGLSYMGLGETNUNIFORMFVKHRPROC __rglgen_glGetnUniformfvKHR;
|
||||
RGLSYMGLGETNUNIFORMIVKHRPROC __rglgen_glGetnUniformivKHR;
|
||||
RGLSYMGLGETNUNIFORMUIVKHRPROC __rglgen_glGetnUniformuivKHR;
|
||||
RGLSYMGLEGLIMAGETARGETTEXTURE2DOESPROC __rglgen_glEGLImageTargetTexture2DOES;
|
||||
RGLSYMGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC __rglgen_glEGLImageTargetRenderbufferStorageOES;
|
||||
RGLSYMGLCOPYIMAGESUBDATAOESPROC __rglgen_glCopyImageSubDataOES;
|
||||
RGLSYMGLENABLEIOESPROC __rglgen_glEnableiOES;
|
||||
RGLSYMGLDISABLEIOESPROC __rglgen_glDisableiOES;
|
||||
RGLSYMGLBLENDEQUATIONIOESPROC __rglgen_glBlendEquationiOES;
|
||||
RGLSYMGLBLENDEQUATIONSEPARATEIOESPROC __rglgen_glBlendEquationSeparateiOES;
|
||||
RGLSYMGLBLENDFUNCIOESPROC __rglgen_glBlendFunciOES;
|
||||
RGLSYMGLBLENDFUNCSEPARATEIOESPROC __rglgen_glBlendFuncSeparateiOES;
|
||||
RGLSYMGLCOLORMASKIOESPROC __rglgen_glColorMaskiOES;
|
||||
RGLSYMGLISENABLEDIOESPROC __rglgen_glIsEnablediOES;
|
||||
RGLSYMGLDRAWELEMENTSBASEVERTEXOESPROC __rglgen_glDrawElementsBaseVertexOES;
|
||||
RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXOESPROC __rglgen_glDrawRangeElementsBaseVertexOES;
|
||||
RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXOESPROC __rglgen_glDrawElementsInstancedBaseVertexOES;
|
||||
RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXOESPROC __rglgen_glMultiDrawElementsBaseVertexOES;
|
||||
RGLSYMGLFRAMEBUFFERTEXTUREOESPROC __rglgen_glFramebufferTextureOES;
|
||||
RGLSYMGLGETPROGRAMBINARYOESPROC __rglgen_glGetProgramBinaryOES;
|
||||
RGLSYMGLPROGRAMBINARYOESPROC __rglgen_glProgramBinaryOES;
|
||||
RGLSYMGLMAPBUFFEROESPROC __rglgen_glMapBufferOES;
|
||||
RGLSYMGLUNMAPBUFFEROESPROC __rglgen_glUnmapBufferOES;
|
||||
RGLSYMGLGETBUFFERPOINTERVOESPROC __rglgen_glGetBufferPointervOES;
|
||||
RGLSYMGLPRIMITIVEBOUNDINGBOXOESPROC __rglgen_glPrimitiveBoundingBoxOES;
|
||||
RGLSYMGLMINSAMPLESHADINGOESPROC __rglgen_glMinSampleShadingOES;
|
||||
RGLSYMGLPATCHPARAMETERIOESPROC __rglgen_glPatchParameteriOES;
|
||||
RGLSYMGLTEXIMAGE3DOESPROC __rglgen_glTexImage3DOES;
|
||||
RGLSYMGLTEXSUBIMAGE3DOESPROC __rglgen_glTexSubImage3DOES;
|
||||
RGLSYMGLCOPYTEXSUBIMAGE3DOESPROC __rglgen_glCopyTexSubImage3DOES;
|
||||
RGLSYMGLCOMPRESSEDTEXIMAGE3DOESPROC __rglgen_glCompressedTexImage3DOES;
|
||||
RGLSYMGLCOMPRESSEDTEXSUBIMAGE3DOESPROC __rglgen_glCompressedTexSubImage3DOES;
|
||||
RGLSYMGLFRAMEBUFFERTEXTURE3DOESPROC __rglgen_glFramebufferTexture3DOES;
|
||||
RGLSYMGLTEXPARAMETERIIVOESPROC __rglgen_glTexParameterIivOES;
|
||||
RGLSYMGLTEXPARAMETERIUIVOESPROC __rglgen_glTexParameterIuivOES;
|
||||
RGLSYMGLGETTEXPARAMETERIIVOESPROC __rglgen_glGetTexParameterIivOES;
|
||||
RGLSYMGLGETTEXPARAMETERIUIVOESPROC __rglgen_glGetTexParameterIuivOES;
|
||||
RGLSYMGLSAMPLERPARAMETERIIVOESPROC __rglgen_glSamplerParameterIivOES;
|
||||
RGLSYMGLSAMPLERPARAMETERIUIVOESPROC __rglgen_glSamplerParameterIuivOES;
|
||||
RGLSYMGLGETSAMPLERPARAMETERIIVOESPROC __rglgen_glGetSamplerParameterIivOES;
|
||||
RGLSYMGLGETSAMPLERPARAMETERIUIVOESPROC __rglgen_glGetSamplerParameterIuivOES;
|
||||
RGLSYMGLTEXBUFFEROESPROC __rglgen_glTexBufferOES;
|
||||
RGLSYMGLTEXBUFFERRANGEOESPROC __rglgen_glTexBufferRangeOES;
|
||||
RGLSYMGLTEXSTORAGE3DMULTISAMPLEOESPROC __rglgen_glTexStorage3DMultisampleOES;
|
||||
RGLSYMGLTEXTUREVIEWOESPROC __rglgen_glTextureViewOES;
|
||||
RGLSYMGLBINDVERTEXARRAYOESPROC __rglgen_glBindVertexArrayOES;
|
||||
RGLSYMGLDELETEVERTEXARRAYSOESPROC __rglgen_glDeleteVertexArraysOES;
|
||||
RGLSYMGLGENVERTEXARRAYSOESPROC __rglgen_glGenVertexArraysOES;
|
||||
RGLSYMGLISVERTEXARRAYOESPROC __rglgen_glIsVertexArrayOES;
|
||||
RGLSYMGLVIEWPORTARRAYVOESPROC __rglgen_glViewportArrayvOES;
|
||||
RGLSYMGLVIEWPORTINDEXEDFOESPROC __rglgen_glViewportIndexedfOES;
|
||||
RGLSYMGLVIEWPORTINDEXEDFVOESPROC __rglgen_glViewportIndexedfvOES;
|
||||
RGLSYMGLSCISSORARRAYVOESPROC __rglgen_glScissorArrayvOES;
|
||||
RGLSYMGLSCISSORINDEXEDOESPROC __rglgen_glScissorIndexedOES;
|
||||
RGLSYMGLSCISSORINDEXEDVOESPROC __rglgen_glScissorIndexedvOES;
|
||||
RGLSYMGLDEPTHRANGEARRAYFVOESPROC __rglgen_glDepthRangeArrayfvOES;
|
||||
RGLSYMGLDEPTHRANGEINDEXEDFOESPROC __rglgen_glDepthRangeIndexedfOES;
|
||||
RGLSYMGLGETFLOATI_VOESPROC __rglgen_glGetFloati_vOES;
|
||||
RGLSYMGLDRAWARRAYSINSTANCEDBASEINSTANCEEXTPROC __rglgen_glDrawArraysInstancedBaseInstanceEXT;
|
||||
RGLSYMGLDRAWELEMENTSINSTANCEDBASEINSTANCEEXTPROC __rglgen_glDrawElementsInstancedBaseInstanceEXT;
|
||||
RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEEXTPROC __rglgen_glDrawElementsInstancedBaseVertexBaseInstanceEXT;
|
||||
RGLSYMGLBINDFRAGDATALOCATIONINDEXEDEXTPROC __rglgen_glBindFragDataLocationIndexedEXT;
|
||||
RGLSYMGLBINDFRAGDATALOCATIONEXTPROC __rglgen_glBindFragDataLocationEXT;
|
||||
RGLSYMGLGETPROGRAMRESOURCELOCATIONINDEXEXTPROC __rglgen_glGetProgramResourceLocationIndexEXT;
|
||||
RGLSYMGLGETFRAGDATAINDEXEXTPROC __rglgen_glGetFragDataIndexEXT;
|
||||
RGLSYMGLBUFFERSTORAGEEXTPROC __rglgen_glBufferStorageEXT;
|
||||
RGLSYMGLCLEARTEXIMAGEEXTPROC __rglgen_glClearTexImageEXT;
|
||||
RGLSYMGLCLEARTEXSUBIMAGEEXTPROC __rglgen_glClearTexSubImageEXT;
|
||||
RGLSYMGLCOPYIMAGESUBDATAEXTPROC __rglgen_glCopyImageSubDataEXT;
|
||||
RGLSYMGLLABELOBJECTEXTPROC __rglgen_glLabelObjectEXT;
|
||||
RGLSYMGLGETOBJECTLABELEXTPROC __rglgen_glGetObjectLabelEXT;
|
||||
RGLSYMGLINSERTEVENTMARKEREXTPROC __rglgen_glInsertEventMarkerEXT;
|
||||
RGLSYMGLPUSHGROUPMARKEREXTPROC __rglgen_glPushGroupMarkerEXT;
|
||||
RGLSYMGLPOPGROUPMARKEREXTPROC __rglgen_glPopGroupMarkerEXT;
|
||||
RGLSYMGLDISCARDFRAMEBUFFEREXTPROC __rglgen_glDiscardFramebufferEXT;
|
||||
RGLSYMGLGENQUERIESEXTPROC __rglgen_glGenQueriesEXT;
|
||||
RGLSYMGLDELETEQUERIESEXTPROC __rglgen_glDeleteQueriesEXT;
|
||||
RGLSYMGLISQUERYEXTPROC __rglgen_glIsQueryEXT;
|
||||
RGLSYMGLBEGINQUERYEXTPROC __rglgen_glBeginQueryEXT;
|
||||
RGLSYMGLENDQUERYEXTPROC __rglgen_glEndQueryEXT;
|
||||
RGLSYMGLQUERYCOUNTEREXTPROC __rglgen_glQueryCounterEXT;
|
||||
RGLSYMGLGETQUERYIVEXTPROC __rglgen_glGetQueryivEXT;
|
||||
RGLSYMGLGETQUERYOBJECTIVEXTPROC __rglgen_glGetQueryObjectivEXT;
|
||||
RGLSYMGLGETQUERYOBJECTUIVEXTPROC __rglgen_glGetQueryObjectuivEXT;
|
||||
RGLSYMGLGETQUERYOBJECTI64VEXTPROC __rglgen_glGetQueryObjecti64vEXT;
|
||||
RGLSYMGLGETQUERYOBJECTUI64VEXTPROC __rglgen_glGetQueryObjectui64vEXT;
|
||||
RGLSYMGLDRAWBUFFERSEXTPROC __rglgen_glDrawBuffersEXT;
|
||||
RGLSYMGLENABLEIEXTPROC __rglgen_glEnableiEXT;
|
||||
RGLSYMGLDISABLEIEXTPROC __rglgen_glDisableiEXT;
|
||||
RGLSYMGLBLENDEQUATIONIEXTPROC __rglgen_glBlendEquationiEXT;
|
||||
RGLSYMGLBLENDEQUATIONSEPARATEIEXTPROC __rglgen_glBlendEquationSeparateiEXT;
|
||||
RGLSYMGLBLENDFUNCIEXTPROC __rglgen_glBlendFunciEXT;
|
||||
RGLSYMGLBLENDFUNCSEPARATEIEXTPROC __rglgen_glBlendFuncSeparateiEXT;
|
||||
RGLSYMGLCOLORMASKIEXTPROC __rglgen_glColorMaskiEXT;
|
||||
RGLSYMGLISENABLEDIEXTPROC __rglgen_glIsEnablediEXT;
|
||||
RGLSYMGLDRAWELEMENTSBASEVERTEXEXTPROC __rglgen_glDrawElementsBaseVertexEXT;
|
||||
RGLSYMGLDRAWRANGEELEMENTSBASEVERTEXEXTPROC __rglgen_glDrawRangeElementsBaseVertexEXT;
|
||||
RGLSYMGLDRAWELEMENTSINSTANCEDBASEVERTEXEXTPROC __rglgen_glDrawElementsInstancedBaseVertexEXT;
|
||||
RGLSYMGLMULTIDRAWELEMENTSBASEVERTEXEXTPROC __rglgen_glMultiDrawElementsBaseVertexEXT;
|
||||
RGLSYMGLDRAWARRAYSINSTANCEDEXTPROC __rglgen_glDrawArraysInstancedEXT;
|
||||
RGLSYMGLDRAWELEMENTSINSTANCEDEXTPROC __rglgen_glDrawElementsInstancedEXT;
|
||||
RGLSYMGLFRAMEBUFFERTEXTUREEXTPROC __rglgen_glFramebufferTextureEXT;
|
||||
RGLSYMGLVERTEXATTRIBDIVISOREXTPROC __rglgen_glVertexAttribDivisorEXT;
|
||||
RGLSYMGLMAPBUFFERRANGEEXTPROC __rglgen_glMapBufferRangeEXT;
|
||||
RGLSYMGLFLUSHMAPPEDBUFFERRANGEEXTPROC __rglgen_glFlushMappedBufferRangeEXT;
|
||||
RGLSYMGLMULTIDRAWARRAYSEXTPROC __rglgen_glMultiDrawArraysEXT;
|
||||
RGLSYMGLMULTIDRAWELEMENTSEXTPROC __rglgen_glMultiDrawElementsEXT;
|
||||
RGLSYMGLMULTIDRAWARRAYSINDIRECTEXTPROC __rglgen_glMultiDrawArraysIndirectEXT;
|
||||
RGLSYMGLMULTIDRAWELEMENTSINDIRECTEXTPROC __rglgen_glMultiDrawElementsIndirectEXT;
|
||||
RGLSYMGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC __rglgen_glRenderbufferStorageMultisampleEXT;
|
||||
RGLSYMGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC __rglgen_glFramebufferTexture2DMultisampleEXT;
|
||||
RGLSYMGLREADBUFFERINDEXEDEXTPROC __rglgen_glReadBufferIndexedEXT;
|
||||
RGLSYMGLDRAWBUFFERSINDEXEDEXTPROC __rglgen_glDrawBuffersIndexedEXT;
|
||||
RGLSYMGLGETINTEGERI_VEXTPROC __rglgen_glGetIntegeri_vEXT;
|
||||
RGLSYMGLPOLYGONOFFSETCLAMPEXTPROC __rglgen_glPolygonOffsetClampEXT;
|
||||
RGLSYMGLPRIMITIVEBOUNDINGBOXEXTPROC __rglgen_glPrimitiveBoundingBoxEXT;
|
||||
RGLSYMGLRASTERSAMPLESEXTPROC __rglgen_glRasterSamplesEXT;
|
||||
RGLSYMGLGETGRAPHICSRESETSTATUSEXTPROC __rglgen_glGetGraphicsResetStatusEXT;
|
||||
RGLSYMGLREADNPIXELSEXTPROC __rglgen_glReadnPixelsEXT;
|
||||
RGLSYMGLGETNUNIFORMFVEXTPROC __rglgen_glGetnUniformfvEXT;
|
||||
RGLSYMGLGETNUNIFORMIVEXTPROC __rglgen_glGetnUniformivEXT;
|
||||
RGLSYMGLACTIVESHADERPROGRAMEXTPROC __rglgen_glActiveShaderProgramEXT;
|
||||
RGLSYMGLBINDPROGRAMPIPELINEEXTPROC __rglgen_glBindProgramPipelineEXT;
|
||||
RGLSYMGLCREATESHADERPROGRAMVEXTPROC __rglgen_glCreateShaderProgramvEXT;
|
||||
RGLSYMGLDELETEPROGRAMPIPELINESEXTPROC __rglgen_glDeleteProgramPipelinesEXT;
|
||||
RGLSYMGLGENPROGRAMPIPELINESEXTPROC __rglgen_glGenProgramPipelinesEXT;
|
||||
RGLSYMGLGETPROGRAMPIPELINEINFOLOGEXTPROC __rglgen_glGetProgramPipelineInfoLogEXT;
|
||||
RGLSYMGLGETPROGRAMPIPELINEIVEXTPROC __rglgen_glGetProgramPipelineivEXT;
|
||||
RGLSYMGLISPROGRAMPIPELINEEXTPROC __rglgen_glIsProgramPipelineEXT;
|
||||
RGLSYMGLPROGRAMPARAMETERIEXTPROC __rglgen_glProgramParameteriEXT;
|
||||
RGLSYMGLPROGRAMUNIFORM1FEXTPROC __rglgen_glProgramUniform1fEXT;
|
||||
RGLSYMGLPROGRAMUNIFORM1FVEXTPROC __rglgen_glProgramUniform1fvEXT;
|
||||
RGLSYMGLPROGRAMUNIFORM1IEXTPROC __rglgen_glProgramUniform1iEXT;
|
||||
RGLSYMGLPROGRAMUNIFORM1IVEXTPROC __rglgen_glProgramUniform1ivEXT;
|
||||
RGLSYMGLPROGRAMUNIFORM2FEXTPROC __rglgen_glProgramUniform2fEXT;
|
||||
RGLSYMGLPROGRAMUNIFORM2FVEXTPROC __rglgen_glProgramUniform2fvEXT;
|
||||
RGLSYMGLPROGRAMUNIFORM2IEXTPROC __rglgen_glProgramUniform2iEXT;
|
||||
RGLSYMGLPROGRAMUNIFORM2IVEXTPROC __rglgen_glProgramUniform2ivEXT;
|
||||
RGLSYMGLPROGRAMUNIFORM3FEXTPROC __rglgen_glProgramUniform3fEXT;
|
||||
RGLSYMGLPROGRAMUNIFORM3FVEXTPROC __rglgen_glProgramUniform3fvEXT;
|
||||
RGLSYMGLPROGRAMUNIFORM3IEXTPROC __rglgen_glProgramUniform3iEXT;
|
||||
RGLSYMGLPROGRAMUNIFORM3IVEXTPROC __rglgen_glProgramUniform3ivEXT;
|
||||
RGLSYMGLPROGRAMUNIFORM4FEXTPROC __rglgen_glProgramUniform4fEXT;
|
||||
RGLSYMGLPROGRAMUNIFORM4FVEXTPROC __rglgen_glProgramUniform4fvEXT;
|
||||
RGLSYMGLPROGRAMUNIFORM4IEXTPROC __rglgen_glProgramUniform4iEXT;
|
||||
RGLSYMGLPROGRAMUNIFORM4IVEXTPROC __rglgen_glProgramUniform4ivEXT;
|
||||
RGLSYMGLPROGRAMUNIFORMMATRIX2FVEXTPROC __rglgen_glProgramUniformMatrix2fvEXT;
|
||||
RGLSYMGLPROGRAMUNIFORMMATRIX3FVEXTPROC __rglgen_glProgramUniformMatrix3fvEXT;
|
||||
RGLSYMGLPROGRAMUNIFORMMATRIX4FVEXTPROC __rglgen_glProgramUniformMatrix4fvEXT;
|
||||
RGLSYMGLUSEPROGRAMSTAGESEXTPROC __rglgen_glUseProgramStagesEXT;
|
||||
RGLSYMGLVALIDATEPROGRAMPIPELINEEXTPROC __rglgen_glValidateProgramPipelineEXT;
|
||||
RGLSYMGLPROGRAMUNIFORM1UIEXTPROC __rglgen_glProgramUniform1uiEXT;
|
||||
RGLSYMGLPROGRAMUNIFORM2UIEXTPROC __rglgen_glProgramUniform2uiEXT;
|
||||
RGLSYMGLPROGRAMUNIFORM3UIEXTPROC __rglgen_glProgramUniform3uiEXT;
|
||||
RGLSYMGLPROGRAMUNIFORM4UIEXTPROC __rglgen_glProgramUniform4uiEXT;
|
||||
RGLSYMGLPROGRAMUNIFORM1UIVEXTPROC __rglgen_glProgramUniform1uivEXT;
|
||||
RGLSYMGLPROGRAMUNIFORM2UIVEXTPROC __rglgen_glProgramUniform2uivEXT;
|
||||
RGLSYMGLPROGRAMUNIFORM3UIVEXTPROC __rglgen_glProgramUniform3uivEXT;
|
||||
RGLSYMGLPROGRAMUNIFORM4UIVEXTPROC __rglgen_glProgramUniform4uivEXT;
|
||||
RGLSYMGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC __rglgen_glProgramUniformMatrix2x3fvEXT;
|
||||
RGLSYMGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC __rglgen_glProgramUniformMatrix3x2fvEXT;
|
||||
RGLSYMGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC __rglgen_glProgramUniformMatrix2x4fvEXT;
|
||||
RGLSYMGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC __rglgen_glProgramUniformMatrix4x2fvEXT;
|
||||
RGLSYMGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC __rglgen_glProgramUniformMatrix3x4fvEXT;
|
||||
RGLSYMGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC __rglgen_glProgramUniformMatrix4x3fvEXT;
|
||||
RGLSYMGLFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC __rglgen_glFramebufferPixelLocalStorageSizeEXT;
|
||||
RGLSYMGLGETFRAMEBUFFERPIXELLOCALSTORAGESIZEEXTPROC __rglgen_glGetFramebufferPixelLocalStorageSizeEXT;
|
||||
RGLSYMGLCLEARPIXELLOCALSTORAGEUIEXTPROC __rglgen_glClearPixelLocalStorageuiEXT;
|
||||
RGLSYMGLTEXPAGECOMMITMENTEXTPROC __rglgen_glTexPageCommitmentEXT;
|
||||
RGLSYMGLPATCHPARAMETERIEXTPROC __rglgen_glPatchParameteriEXT;
|
||||
RGLSYMGLTEXPARAMETERIIVEXTPROC __rglgen_glTexParameterIivEXT;
|
||||
RGLSYMGLTEXPARAMETERIUIVEXTPROC __rglgen_glTexParameterIuivEXT;
|
||||
RGLSYMGLGETTEXPARAMETERIIVEXTPROC __rglgen_glGetTexParameterIivEXT;
|
||||
RGLSYMGLGETTEXPARAMETERIUIVEXTPROC __rglgen_glGetTexParameterIuivEXT;
|
||||
RGLSYMGLSAMPLERPARAMETERIIVEXTPROC __rglgen_glSamplerParameterIivEXT;
|
||||
RGLSYMGLSAMPLERPARAMETERIUIVEXTPROC __rglgen_glSamplerParameterIuivEXT;
|
||||
RGLSYMGLGETSAMPLERPARAMETERIIVEXTPROC __rglgen_glGetSamplerParameterIivEXT;
|
||||
RGLSYMGLGETSAMPLERPARAMETERIUIVEXTPROC __rglgen_glGetSamplerParameterIuivEXT;
|
||||
RGLSYMGLTEXBUFFEREXTPROC __rglgen_glTexBufferEXT;
|
||||
RGLSYMGLTEXBUFFERRANGEEXTPROC __rglgen_glTexBufferRangeEXT;
|
||||
RGLSYMGLTEXSTORAGE1DEXTPROC __rglgen_glTexStorage1DEXT;
|
||||
RGLSYMGLTEXSTORAGE2DEXTPROC __rglgen_glTexStorage2DEXT;
|
||||
RGLSYMGLTEXSTORAGE3DEXTPROC __rglgen_glTexStorage3DEXT;
|
||||
RGLSYMGLTEXTURESTORAGE1DEXTPROC __rglgen_glTextureStorage1DEXT;
|
||||
RGLSYMGLTEXTURESTORAGE2DEXTPROC __rglgen_glTextureStorage2DEXT;
|
||||
RGLSYMGLTEXTURESTORAGE3DEXTPROC __rglgen_glTextureStorage3DEXT;
|
||||
RGLSYMGLTEXTUREVIEWEXTPROC __rglgen_glTextureViewEXT;
|
||||
RGLSYMGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC __rglgen_glFramebufferTextureMultiviewOVR;
|
||||
RGLSYMGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC __rglgen_glFramebufferTextureMultisampleMultiviewOVR;
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,45 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this libretro SDK code part (glsym).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <glsym/rglgen.h>
|
||||
#include <glsym/glsym.h>
|
||||
|
||||
void rglgen_resolve_symbols_custom(rglgen_proc_address_t proc,
|
||||
const struct rglgen_sym_map *map)
|
||||
{
|
||||
for (; map->sym; map++)
|
||||
{
|
||||
rglgen_func_t func = proc(map->sym);
|
||||
memcpy(map->ptr, &func, sizeof(func));
|
||||
}
|
||||
}
|
||||
|
||||
void rglgen_resolve_symbols(rglgen_proc_address_t proc)
|
||||
{
|
||||
if (!proc)
|
||||
return;
|
||||
|
||||
rglgen_resolve_symbols_custom(proc, rglgen_symbol_map);
|
||||
}
|
||||
Executable
+149
@@ -0,0 +1,149 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
License statement applies to this file (glgen.py) only.
|
||||
"""
|
||||
|
||||
"""
|
||||
Permission is hereby granted, free of charge,
|
||||
to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
import re
|
||||
|
||||
banned_ext = [ 'AMD', 'APPLE', 'NV', 'NVX', 'ATI', '3DLABS', 'SUN', 'SGI', 'SGIX', 'SGIS', 'INTEL', '3DFX', 'IBM', 'MESA', 'GREMEDY', 'OML', 'PGI', 'I3D', 'INGL', 'MTX', 'QCOM', 'IMG', 'ANGLE', 'SUNX', 'INGR' ]
|
||||
|
||||
def noext(sym):
|
||||
for ext in banned_ext:
|
||||
if sym.endswith(ext):
|
||||
return False
|
||||
return True
|
||||
|
||||
def fix_multiline_functions(lines):
|
||||
fixed_lines = []
|
||||
temp_lines = []
|
||||
for line in lines:
|
||||
if line.count('(') > line.count(')'):
|
||||
temp_lines.append(line)
|
||||
else:
|
||||
if len(temp_lines) > 0:
|
||||
if line.count(')') > line.count('('):
|
||||
temp_lines.append(line)
|
||||
fixed_line = re.sub(' +',' ', ''.join(temp_lines).replace('\n','').replace('\t',''))
|
||||
fixed_lines.append(fixed_line)
|
||||
temp_lines = []
|
||||
else:
|
||||
temp_lines.append(line)
|
||||
else:
|
||||
fixed_lines.append(line)
|
||||
return fixed_lines
|
||||
|
||||
def find_gl_symbols(lines):
|
||||
typedefs = []
|
||||
syms = []
|
||||
for line in lines:
|
||||
m = re.search(r'^typedef.+PFN(\S+)PROC.+$', line)
|
||||
g = re.search(r'^.+(gl\S+)\W*\(.+\).*$', line)
|
||||
if m and noext(m.group(1)):
|
||||
typedefs.append(m.group(0).replace('PFN', 'RGLSYM').replace('GLDEBUGPROC', 'RGLGENGLDEBUGPROC'))
|
||||
if g and noext(g.group(1)):
|
||||
syms.append(g.group(1))
|
||||
return (typedefs, syms)
|
||||
|
||||
def generate_defines(gl_syms):
|
||||
res = []
|
||||
for line in gl_syms:
|
||||
res.append('#define {} __rglgen_{}'.format(line, line))
|
||||
return res
|
||||
|
||||
def generate_declarations(gl_syms):
|
||||
return ['RGLSYM' + x.upper() + 'PROC ' + '__rglgen_' + x + ';' for x in gl_syms]
|
||||
|
||||
def generate_macros(gl_syms):
|
||||
return [' SYM(' + x.replace('gl', '') + '),' for x in gl_syms]
|
||||
|
||||
def dump(f, lines):
|
||||
f.write('\n'.join(lines))
|
||||
f.write('\n\n')
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
if len(sys.argv) > 4:
|
||||
for banned in sys.argv[4:]:
|
||||
banned_ext.append(banned)
|
||||
|
||||
with open(sys.argv[1], 'r') as f:
|
||||
lines = fix_multiline_functions(f.readlines())
|
||||
typedefs, syms = find_gl_symbols(lines)
|
||||
|
||||
overrides = generate_defines(syms)
|
||||
declarations = generate_declarations(syms)
|
||||
externs = ['extern ' + x for x in declarations]
|
||||
|
||||
macros = generate_macros(syms)
|
||||
|
||||
with open(sys.argv[2], 'w') as f:
|
||||
f.write('#ifndef RGLGEN_DECL_H__\n')
|
||||
f.write('#define RGLGEN_DECL_H__\n')
|
||||
|
||||
f.write('#ifdef __cplusplus\n')
|
||||
f.write('extern "C" {\n')
|
||||
f.write('#endif\n')
|
||||
|
||||
f.write('#ifdef GL_APIENTRY\n')
|
||||
f.write('typedef void (GL_APIENTRY *RGLGENGLDEBUGPROC)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\n')
|
||||
f.write('#else\n')
|
||||
f.write('#ifndef APIENTRY\n')
|
||||
f.write('#define APIENTRY\n')
|
||||
f.write('#endif\n')
|
||||
f.write('#ifndef APIENTRYP\n')
|
||||
f.write('#define APIENTRYP APIENTRY *\n')
|
||||
f.write('#endif\n')
|
||||
f.write('typedef void (APIENTRY *RGLGENGLDEBUGPROCARB)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\n')
|
||||
f.write('typedef void (APIENTRY *RGLGENGLDEBUGPROC)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\n')
|
||||
f.write('#endif\n')
|
||||
|
||||
f.write('#ifndef GL_OES_EGL_image\n')
|
||||
f.write('typedef void *GLeglImageOES;\n')
|
||||
f.write('#endif\n')
|
||||
|
||||
f.write('#if !defined(GL_OES_fixed_point) && !defined(HAVE_OPENGLES2)\n')
|
||||
f.write('typedef GLint GLfixed;\n')
|
||||
f.write('#endif\n')
|
||||
|
||||
dump(f, typedefs)
|
||||
dump(f, overrides)
|
||||
dump(f, externs)
|
||||
|
||||
f.write('struct rglgen_sym_map { const char *sym; void *ptr; };\n')
|
||||
f.write('extern const struct rglgen_sym_map rglgen_symbol_map[];\n')
|
||||
|
||||
f.write('#ifdef __cplusplus\n')
|
||||
f.write('}\n')
|
||||
f.write('#endif\n')
|
||||
|
||||
f.write('#endif\n')
|
||||
|
||||
with open(sys.argv[3], 'w') as f:
|
||||
f.write('#include "glsym/glsym.h"\n')
|
||||
f.write('#include <stddef.h>\n')
|
||||
f.write('#define SYM(x) { "gl" #x, &(gl##x) }\n')
|
||||
f.write('const struct rglgen_sym_map rglgen_symbol_map[] = {\n')
|
||||
dump(f, macros)
|
||||
f.write(' { NULL, NULL },\n')
|
||||
f.write('};\n')
|
||||
dump(f, declarations)
|
||||
@@ -0,0 +1,158 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
License statement applies to this file (xglgen.py) only.
|
||||
"""
|
||||
|
||||
"""
|
||||
Permission is hereby granted, free of charge,
|
||||
to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
import re
|
||||
|
||||
banned_ext = [ 'AMD', 'APPLE', 'NV', 'NVX', 'ATI', '3DLABS', 'SUN', 'SGI', 'SGIX', 'SGIS', 'INTEL', '3DFX', 'IBM', 'MESA', 'GREMEDY', 'OML', 'PGI', 'I3D', 'INGL', 'MTX', 'QCOM', 'IMG', 'ANGLE', 'SUNX', 'INGR' ]
|
||||
|
||||
def noext(sym):
|
||||
for ext in banned_ext:
|
||||
if sym.endswith(ext):
|
||||
return False
|
||||
return True
|
||||
|
||||
def fix_multiline_functions(lines):
|
||||
fixed_lines = []
|
||||
temp_lines = []
|
||||
for line in lines:
|
||||
if line.count('(') > line.count(')'):
|
||||
temp_lines.append(line)
|
||||
else:
|
||||
if len(temp_lines) > 0:
|
||||
if line.count(')') > line.count('('):
|
||||
temp_lines.append(line)
|
||||
fixed_line = re.sub(' +',' ', ''.join(temp_lines).replace('\n','').replace('\t',''))
|
||||
fixed_lines.append(fixed_line)
|
||||
temp_lines = []
|
||||
else:
|
||||
temp_lines.append(line)
|
||||
else:
|
||||
fixed_lines.append(line)
|
||||
return fixed_lines
|
||||
|
||||
def find_gl_symbols(lines):
|
||||
typedefs = []
|
||||
syms = []
|
||||
for line in lines:
|
||||
# Note this doesn't work automated; this script is designed as a helper
|
||||
m = re.search(r'^typedef.+PFN(\S+)PROC.+$', line)
|
||||
g = re.search(r'^GLAPI\s(.+)\s(.+)\s(gl\S+)\W*\((.+)\).*', line)
|
||||
if g and noext(g.group(3)):
|
||||
typedefs.append('typedef ' + g.group(1) + ' (APIENTRYP RGLSYM' + g.group(3).upper() + 'PROC) (' + g.group(4) + ');')
|
||||
syms.append(g.group(3))
|
||||
|
||||
return (typedefs, syms)
|
||||
|
||||
def generate_defines(gl_syms):
|
||||
res = []
|
||||
for line in gl_syms:
|
||||
res.append('#define {} __rglgen_{}'.format(line, line))
|
||||
return res
|
||||
|
||||
def generate_declarations(gl_syms):
|
||||
return ['RGLSYM' + x.upper() + 'PROC ' + x + ';' for x in gl_syms]
|
||||
|
||||
def generate_macros(gl_syms):
|
||||
return [' SYM(' + x.replace('gl', '') + '),' for x in gl_syms]
|
||||
|
||||
def dump(f, lines):
|
||||
f.write('\n'.join(lines))
|
||||
f.write('\n\n')
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
if len(sys.argv) > 4:
|
||||
for banned in sys.argv[4:]:
|
||||
banned_ext.append(banned)
|
||||
|
||||
with open(sys.argv[1], 'r') as f:
|
||||
lines = fix_multiline_functions(f.readlines())
|
||||
typedefs, syms = find_gl_symbols(lines)
|
||||
|
||||
overrides = generate_defines(syms)
|
||||
declarations = generate_declarations(syms)
|
||||
externs = ['extern ' + x for x in declarations]
|
||||
|
||||
macros = generate_macros(syms)
|
||||
|
||||
with open(sys.argv[2], 'w') as f:
|
||||
f.write('#ifndef RGLGEN_DECL_H__\n')
|
||||
f.write('#define RGLGEN_DECL_H__\n')
|
||||
|
||||
f.write('#ifdef __cplusplus\n')
|
||||
f.write('extern "C" {\n')
|
||||
f.write('#endif\n')
|
||||
|
||||
f.write('#ifdef GL_APIENTRY\n')
|
||||
f.write('typedef void (GL_APIENTRY *RGLGENGLDEBUGPROC)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\n')
|
||||
f.write('typedef void (GL_APIENTRY *RGLGENGLDEBUGPROCKHR)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\n')
|
||||
f.write('#else\n')
|
||||
f.write('#ifndef APIENTRY\n')
|
||||
f.write('#define APIENTRY\n')
|
||||
f.write('#endif\n')
|
||||
f.write('#ifndef APIENTRYP\n')
|
||||
f.write('#define APIENTRYP APIENTRY *\n')
|
||||
f.write('#endif\n')
|
||||
f.write('typedef void (APIENTRY *RGLGENGLDEBUGPROCARB)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\n')
|
||||
f.write('typedef void (APIENTRY *RGLGENGLDEBUGPROC)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, GLvoid*);\n')
|
||||
f.write('#endif\n')
|
||||
|
||||
f.write('#ifndef GL_OES_EGL_image\n')
|
||||
f.write('typedef void *GLeglImageOES;\n')
|
||||
f.write('#endif\n')
|
||||
|
||||
f.write('#if !defined(GL_OES_fixed_point) && !defined(HAVE_OPENGLES2)\n')
|
||||
f.write('typedef GLint GLfixed;\n')
|
||||
f.write('#endif\n')
|
||||
|
||||
f.write('#if defined(OSX) && !defined(MAC_OS_X_VERSION_10_7)\n')
|
||||
f.write('typedef long long int GLint64;\n')
|
||||
f.write('typedef unsigned long long int GLuint64;\n')
|
||||
f.write('typedef unsigned long long int GLuint64EXT;\n')
|
||||
f.write('typedef struct __GLsync *GLsync;\n')
|
||||
f.write('#endif\n')
|
||||
|
||||
dump(f, typedefs)
|
||||
dump(f, overrides)
|
||||
dump(f, externs)
|
||||
|
||||
f.write('struct rglgen_sym_map { const char *sym; void *ptr; };\n')
|
||||
f.write('extern const struct rglgen_sym_map rglgen_symbol_map[];\n')
|
||||
|
||||
f.write('#ifdef __cplusplus\n')
|
||||
f.write('}\n')
|
||||
f.write('#endif\n')
|
||||
|
||||
f.write('#endif\n')
|
||||
|
||||
with open(sys.argv[3], 'w') as f:
|
||||
f.write('#include "glsym/glsym.h"\n')
|
||||
f.write('#include <stddef.h>\n')
|
||||
f.write('#define SYM(x) { "gl" #x, &(gl##x) }\n')
|
||||
f.write('const struct rglgen_sym_map rglgen_symbol_map[] = {\n')
|
||||
dump(f, macros)
|
||||
f.write(' { NULL, NULL },\n')
|
||||
f.write('};\n')
|
||||
dump(f, declarations)
|
||||
@@ -0,0 +1,39 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (boolean.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __LIBRETRO_SDK_BOOLEAN_H
|
||||
#define __LIBRETRO_SDK_BOOLEAN_H
|
||||
|
||||
#ifndef __cplusplus
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1800 && !defined(SN_TARGET_PS3)
|
||||
/* Hack applied for MSVC when compiling in C89 mode as it isn't C99 compliant. */
|
||||
#define bool unsigned char
|
||||
#define true 1
|
||||
#define false 0
|
||||
#else
|
||||
#include <stdbool.h>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,127 @@
|
||||
/* Copyright (C) 2010-2019 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (cdrom.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __LIBRETRO_SDK_CDROM_H
|
||||
#define __LIBRETRO_SDK_CDROM_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <vfs/vfs.h>
|
||||
#include <libretro.h>
|
||||
#include <retro_common_api.h>
|
||||
#include <retro_inline.h>
|
||||
|
||||
#include <boolean.h>
|
||||
|
||||
struct string_list;
|
||||
|
||||
RETRO_BEGIN_DECLS
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned short g1_timeout;
|
||||
unsigned short g2_timeout;
|
||||
unsigned short g3_timeout;
|
||||
} cdrom_group_timeouts_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned lba_start; /* start of pregap */
|
||||
unsigned lba; /* start of data */
|
||||
unsigned track_size; /* in LBAs */
|
||||
unsigned track_bytes;
|
||||
unsigned char track_num;
|
||||
unsigned char min; /* start of data */
|
||||
unsigned char sec;
|
||||
unsigned char frame;
|
||||
unsigned char mode;
|
||||
bool audio;
|
||||
} cdrom_track_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char drive;
|
||||
unsigned char num_tracks;
|
||||
cdrom_group_timeouts_t timeouts;
|
||||
cdrom_track_t track[99];
|
||||
} cdrom_toc_t;
|
||||
|
||||
void cdrom_lba_to_msf(unsigned lba, unsigned char *min, unsigned char *sec, unsigned char *frame);
|
||||
|
||||
unsigned cdrom_msf_to_lba(unsigned char min, unsigned char sec, unsigned char frame);
|
||||
|
||||
void increment_msf(unsigned char *min, unsigned char *sec, unsigned char *frame);
|
||||
|
||||
int cdrom_read_subq(libretro_vfs_implementation_file *stream, unsigned char *buf, size_t len);
|
||||
|
||||
int cdrom_write_cue(libretro_vfs_implementation_file *stream, char **out_buf, size_t *out_len, char cdrom_drive, unsigned char *num_tracks, cdrom_toc_t *toc);
|
||||
|
||||
/* needs 32 bytes for full vendor, product and version */
|
||||
int cdrom_get_inquiry(const libretro_vfs_implementation_file *stream, char *model, int len, bool *is_cdrom);
|
||||
|
||||
int cdrom_read(libretro_vfs_implementation_file *stream, cdrom_group_timeouts_t *timeouts, unsigned char min, unsigned char sec, unsigned char frame, void *s, size_t len, size_t skip);
|
||||
|
||||
int cdrom_read_lba(libretro_vfs_implementation_file *stream, unsigned lba, void *s, size_t len, size_t skip);
|
||||
|
||||
int cdrom_set_read_speed(libretro_vfs_implementation_file *stream, unsigned speed);
|
||||
|
||||
int cdrom_stop(const libretro_vfs_implementation_file *stream);
|
||||
|
||||
int cdrom_unlock(const libretro_vfs_implementation_file *stream);
|
||||
|
||||
int cdrom_open_tray(const libretro_vfs_implementation_file *stream);
|
||||
|
||||
int cdrom_close_tray(const libretro_vfs_implementation_file *stream);
|
||||
|
||||
/* must be freed by the caller */
|
||||
struct string_list* cdrom_get_available_drives(void);
|
||||
|
||||
bool cdrom_is_media_inserted(const libretro_vfs_implementation_file *stream);
|
||||
|
||||
bool cdrom_drive_has_media(const char drive);
|
||||
|
||||
void cdrom_get_current_config_core(const libretro_vfs_implementation_file *stream);
|
||||
|
||||
void cdrom_get_current_config_profiles(const libretro_vfs_implementation_file *stream);
|
||||
|
||||
void cdrom_get_current_config_cdread(const libretro_vfs_implementation_file *stream);
|
||||
|
||||
void cdrom_get_current_config_multiread(const libretro_vfs_implementation_file *stream);
|
||||
|
||||
void cdrom_get_current_config_random_readable(const libretro_vfs_implementation_file *stream);
|
||||
|
||||
int cdrom_get_sense(const libretro_vfs_implementation_file *stream, unsigned char *sense, size_t len);
|
||||
|
||||
bool cdrom_set_read_cache(const libretro_vfs_implementation_file *stream, bool enabled);
|
||||
|
||||
bool cdrom_get_timeouts(libretro_vfs_implementation_file *stream, cdrom_group_timeouts_t *timeouts);
|
||||
|
||||
bool cdrom_has_atip(const libretro_vfs_implementation_file *stream);
|
||||
|
||||
void cdrom_device_fillpath(char *path, size_t len, char drive, unsigned char track, bool is_cue);
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,65 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (clamping.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _LIBRETRO_SDK_CLAMPING_H
|
||||
#define _LIBRETRO_SDK_CLAMPING_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <retro_inline.h>
|
||||
|
||||
/**
|
||||
* clamp_float:
|
||||
* @val : initial value
|
||||
* @lower : lower limit that value should be clamped against
|
||||
* @upper : upper limit that value should be clamped against
|
||||
*
|
||||
* Clamps a floating point value.
|
||||
*
|
||||
* Returns: a clamped value of initial float value @val.
|
||||
*/
|
||||
static INLINE float clamp_float(float val, float lower, float upper)
|
||||
{
|
||||
if (val < lower)
|
||||
return lower;
|
||||
if (val > upper)
|
||||
return upper;
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* clamp_8bit:
|
||||
* @val : initial value
|
||||
*
|
||||
* Clamps an unsigned 8-bit value.
|
||||
*
|
||||
* Returns: a clamped value of initial unsigned 8-bit value @val.
|
||||
*/
|
||||
static INLINE uint8_t clamp_8bit(int val)
|
||||
{
|
||||
if (val > 255)
|
||||
return 255;
|
||||
if (val < 0)
|
||||
return 0;
|
||||
return (uint8_t)val;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,84 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (apple_compat.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __APPLE_COMPAT_H
|
||||
#define __APPLE_COMPAT_H
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <AvailabilityMacros.h>
|
||||
#endif
|
||||
|
||||
#ifdef __OBJC__
|
||||
|
||||
#if (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4)
|
||||
typedef int NSInteger;
|
||||
typedef unsigned NSUInteger;
|
||||
typedef float CGFloat;
|
||||
#endif
|
||||
|
||||
#ifndef __has_feature
|
||||
/* Compatibility with non-Clang compilers. */
|
||||
#define __has_feature(x) 0
|
||||
#endif
|
||||
|
||||
#ifndef CF_RETURNS_RETAINED
|
||||
#if __has_feature(attribute_cf_returns_retained)
|
||||
#define CF_RETURNS_RETAINED __attribute__((cf_returns_retained))
|
||||
#else
|
||||
#define CF_RETURNS_RETAINED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef NS_INLINE
|
||||
#define NS_INLINE inline
|
||||
#endif
|
||||
|
||||
NS_INLINE CF_RETURNS_RETAINED CFTypeRef CFBridgingRetainCompat(id X)
|
||||
{
|
||||
#if __has_feature(objc_arc)
|
||||
return (__bridge_retained CFTypeRef)X;
|
||||
#else
|
||||
return X;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef IOS
|
||||
#ifndef __IPHONE_5_0
|
||||
#warning "This project uses features only available in iOS SDK 5.0 and later."
|
||||
#endif
|
||||
|
||||
#ifdef __OBJC__
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <GLKit/GLKit.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#ifdef __OBJC__
|
||||
#include <objc/objc-runtime.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,30 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (fnmatch.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __LIBRETRO_SDK_COMPAT_FNMATCH_H__
|
||||
#define __LIBRETRO_SDK_COMPAT_FNMATCH_H__
|
||||
|
||||
#define FNM_NOMATCH 1
|
||||
|
||||
int rl_fnmatch(const char *pattern, const char *string, int flags);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,34 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (fopen_utf8.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __LIBRETRO_SDK_COMPAT_FOPEN_UTF8_H
|
||||
#define __LIBRETRO_SDK_COMPAT_FOPEN_UTF8_H
|
||||
|
||||
#ifdef _WIN32
|
||||
/* Defined to error rather than fopen_utf8, to make it clear to everyone reading the code that not worrying about utf16 is fine */
|
||||
/* TODO: enable */
|
||||
/* #define fopen (use fopen_utf8 instead) */
|
||||
void *fopen_utf8(const char * filename, const char * mode);
|
||||
#else
|
||||
#define fopen_utf8 fopen
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,74 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (getopt.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __LIBRETRO_SDK_COMPAT_GETOPT_H
|
||||
#define __LIBRETRO_SDK_COMPAT_GETOPT_H
|
||||
|
||||
#if defined(RARCH_INTERNAL) && defined(HAVE_CONFIG_H)
|
||||
#include "../../../config.h"
|
||||
#endif
|
||||
|
||||
/* Custom implementation of the GNU getopt_long for portability.
|
||||
* Not designed to be fully compatible, but compatible with
|
||||
* the features RetroArch uses. */
|
||||
|
||||
#ifdef HAVE_GETOPT_LONG
|
||||
#include <getopt.h>
|
||||
#else
|
||||
/* Avoid possible naming collisions during link since we
|
||||
* prefer to use the actual name. */
|
||||
#define getopt_long(argc, argv, optstring, longopts, longindex) __getopt_long_retro(argc, argv, optstring, longopts, longindex)
|
||||
|
||||
#include <retro_common_api.h>
|
||||
|
||||
RETRO_BEGIN_DECLS
|
||||
|
||||
struct option
|
||||
{
|
||||
const char *name;
|
||||
int has_arg;
|
||||
int *flag;
|
||||
int val;
|
||||
};
|
||||
|
||||
/* argv[] is declared with char * const argv[] in GNU,
|
||||
* but this makes no sense, as non-POSIX getopt_long
|
||||
* mutates argv (non-opts are moved to the end). */
|
||||
int getopt_long(int argc, char *argv[],
|
||||
const char *optstring, const struct option *longopts, int *longindex);
|
||||
extern char *optarg;
|
||||
extern int optind, opterr, optopt;
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
/* If these are variously #defined, then we have bigger problems */
|
||||
#ifndef no_argument
|
||||
#define no_argument 0
|
||||
#define required_argument 1
|
||||
#define optional_argument 2
|
||||
#endif
|
||||
|
||||
/* HAVE_GETOPT_LONG */
|
||||
#endif
|
||||
|
||||
/* pragma once */
|
||||
#endif
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) 1995, 1999
|
||||
* Berkeley Software Design, Inc. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* BSDI ifaddrs.h,v 2.5 2000/02/23 14:51:59 dab Exp
|
||||
*/
|
||||
|
||||
#ifndef _IFADDRS_H_
|
||||
#define _IFADDRS_H_
|
||||
|
||||
struct ifaddrs
|
||||
{
|
||||
struct ifaddrs *ifa_next;
|
||||
char *ifa_name;
|
||||
unsigned int ifa_flags;
|
||||
struct sockaddr *ifa_addr;
|
||||
struct sockaddr *ifa_netmask;
|
||||
struct sockaddr *ifa_dstaddr;
|
||||
void *ifa_data;
|
||||
};
|
||||
|
||||
/*
|
||||
* This may have been defined in <net/if.h>. Note that if <net/if.h> is
|
||||
* to be included it must be included before this header file.
|
||||
*/
|
||||
#ifndef ifa_broadaddr
|
||||
#define ifa_broadaddr ifa_dstaddr /* broadcast address interface */
|
||||
#endif
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
extern int getifaddrs(struct ifaddrs **ifap);
|
||||
extern void freeifaddrs(struct ifaddrs *ifa);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,85 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (intrinsics.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __LIBRETRO_SDK_COMPAT_INTRINSICS_H
|
||||
#define __LIBRETRO_SDK_COMPAT_INTRINSICS_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <retro_common_api.h>
|
||||
#include <retro_inline.h>
|
||||
|
||||
#if defined(_MSC_VER) && !defined(_XBOX)
|
||||
#if (_MSC_VER > 1310)
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
RETRO_BEGIN_DECLS
|
||||
|
||||
/* Count Leading Zero, unsigned 16bit input value */
|
||||
static INLINE unsigned compat_clz_u16(uint16_t val)
|
||||
{
|
||||
#if defined(__GNUC__) && !defined(PS2)
|
||||
return __builtin_clz(val << 16 | 0x8000);
|
||||
#else
|
||||
unsigned ret = 0;
|
||||
|
||||
while(!(val & 0x8000) && ret < 16)
|
||||
{
|
||||
val <<= 1;
|
||||
ret++;
|
||||
}
|
||||
|
||||
return ret;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Count Trailing Zero */
|
||||
static INLINE int compat_ctz(unsigned x)
|
||||
{
|
||||
#if defined(__GNUC__) && !defined(RARCH_CONSOLE)
|
||||
return __builtin_ctz(x);
|
||||
#elif _MSC_VER >= 1400 && !defined(_XBOX) && !defined(__WINRT__)
|
||||
unsigned long r = 0;
|
||||
_BitScanReverse((unsigned long*)&r, x);
|
||||
return (int)r;
|
||||
#else
|
||||
/* Only checks at nibble granularity,
|
||||
* because that's what we need. */
|
||||
if (x & 0x000f)
|
||||
return 0;
|
||||
if (x & 0x00f0)
|
||||
return 4;
|
||||
if (x & 0x0f00)
|
||||
return 8;
|
||||
if (x & 0xf000)
|
||||
return 12;
|
||||
return 16;
|
||||
#endif
|
||||
}
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,129 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (msvc.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __LIBRETRO_SDK_COMPAT_MSVC_H
|
||||
#define __LIBRETRO_SDK_COMPAT_MSVC_H
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Pre-MSVC 2015 compilers don't implement snprintf in a cross-platform manner. */
|
||||
#if _MSC_VER < 1900
|
||||
#include <stdlib.h>
|
||||
#ifndef snprintf
|
||||
#define snprintf c99_snprintf_retro__
|
||||
#endif
|
||||
|
||||
int c99_snprintf_retro__(char *outBuf, size_t size, const char *format, ...);
|
||||
#endif
|
||||
|
||||
/* Pre-MSVC 2008 compilers don't implement vsnprintf in a cross-platform manner? Not sure about this one. */
|
||||
#if _MSC_VER < 1500
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#ifndef vsnprintf
|
||||
#define vsnprintf c99_vsnprintf_retro__
|
||||
#endif
|
||||
int c99_vsnprintf_retro__(char *outBuf, size_t size, const char *format, va_list ap);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#undef UNICODE /* Do not bother with UNICODE at this time. */
|
||||
#include <direct.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <math.h>
|
||||
|
||||
/* Python headers defines ssize_t and sets HAVE_SSIZE_T.
|
||||
* Cannot duplicate these efforts.
|
||||
*/
|
||||
#ifndef HAVE_SSIZE_T
|
||||
#if defined(_WIN64)
|
||||
typedef __int64 ssize_t;
|
||||
#elif defined(_WIN32)
|
||||
typedef int ssize_t;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define mkdir(dirname, unused) _mkdir(dirname)
|
||||
#define strtoull _strtoui64
|
||||
#undef strcasecmp
|
||||
#define strcasecmp _stricmp
|
||||
#undef strncasecmp
|
||||
#define strncasecmp _strnicmp
|
||||
|
||||
/* Disable some of the annoying warnings. */
|
||||
#pragma warning(disable : 4800)
|
||||
#pragma warning(disable : 4805)
|
||||
#pragma warning(disable : 4244)
|
||||
#pragma warning(disable : 4305)
|
||||
#pragma warning(disable : 4146)
|
||||
#pragma warning(disable : 4267)
|
||||
#pragma warning(disable : 4723)
|
||||
#pragma warning(disable : 4996)
|
||||
|
||||
/* roundf and va_copy is available since MSVC 2013 */
|
||||
#if _MSC_VER < 1800
|
||||
#define roundf(in) (in >= 0.0f ? floorf(in + 0.5f) : ceilf(in - 0.5f))
|
||||
#define va_copy(x, y) ((x) = (y))
|
||||
#endif
|
||||
|
||||
#if _MSC_VER <= 1310
|
||||
#ifndef __cplusplus
|
||||
/* VC6 math.h doesn't define some functions when in C mode.
|
||||
* Trying to define a prototype gives "undefined reference".
|
||||
* But providing an implementation then gives "function already has body".
|
||||
* So the equivalent of the implementations from math.h are used as
|
||||
* defines here instead, and it seems to work.
|
||||
*/
|
||||
#define cosf(x) ((float)cos((double)x))
|
||||
#define powf(x, y) ((float)pow((double)x, (double)y))
|
||||
#define sinf(x) ((float)sin((double)x))
|
||||
#define ceilf(x) ((float)ceil((double)x))
|
||||
#define floorf(x) ((float)floor((double)x))
|
||||
#define sqrtf(x) ((float)sqrt((double)x))
|
||||
#define fabsf(x) ((float)fabs((double)(x)))
|
||||
#endif
|
||||
|
||||
#ifndef _strtoui64
|
||||
#define _strtoui64(x, y, z) (_atoi64(x))
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef PATH_MAX
|
||||
#define PATH_MAX _MAX_PATH
|
||||
#endif
|
||||
|
||||
#ifndef SIZE_MAX
|
||||
#define SIZE_MAX _UI32_MAX
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,255 @@
|
||||
/* ISO C9x compliant stdint.h for Microsoft Visual Studio
|
||||
* Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
|
||||
*
|
||||
* Copyright (c) 2006-2008 Alexander Chemeris
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. The name of the author may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef __RARCH_STDINT_H
|
||||
#define __RARCH_STDINT_H
|
||||
|
||||
#if _MSC_VER && (_MSC_VER < 1600)
|
||||
/* Pre-MSVC 2010 needs an implementation of stdint.h. */
|
||||
|
||||
#if _MSC_VER > 1000
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
/* For Visual Studio 6 in C++ mode and for many Visual Studio versions when
|
||||
* compiling for ARM we should wrap <wchar.h> include with 'extern "C++" {}'
|
||||
* or compiler give many errors like this:
|
||||
*
|
||||
* error C2733: second C linkage of overloaded function 'wmemchr' not allowed
|
||||
*/
|
||||
#ifdef __cplusplus
|
||||
#if _MSC_VER <= 1200
|
||||
extern "C++" {
|
||||
#else
|
||||
extern "C" {
|
||||
#endif
|
||||
#endif
|
||||
# include <wchar.h>
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Define _W64 macros to mark types changing their size, like intptr_t. */
|
||||
#ifndef _W64
|
||||
# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
|
||||
# define _W64 __w64
|
||||
# else
|
||||
# define _W64
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* 7.18.1 Integer types. */
|
||||
|
||||
/* 7.18.1.1 Exact-width integer types. */
|
||||
|
||||
/* Visual Studio 6 and Embedded Visual C++ 4 doesn't
|
||||
* realize that, e.g. char has the same size as __int8
|
||||
* so we give up on __intX for them.
|
||||
*/
|
||||
#if (_MSC_VER < 1300)
|
||||
typedef signed char int8_t;
|
||||
typedef signed short int16_t;
|
||||
typedef signed int int32_t;
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
#else
|
||||
typedef signed __int8 int8_t;
|
||||
typedef signed __int16 int16_t;
|
||||
typedef signed __int32 int32_t;
|
||||
typedef unsigned __int8 uint8_t;
|
||||
typedef unsigned __int16 uint16_t;
|
||||
typedef unsigned __int32 uint32_t;
|
||||
#endif
|
||||
typedef signed __int64 int64_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
|
||||
/* 7.18.1.2 Minimum-width integer types. */
|
||||
typedef int8_t int_least8_t;
|
||||
typedef int16_t int_least16_t;
|
||||
typedef int32_t int_least32_t;
|
||||
typedef int64_t int_least64_t;
|
||||
typedef uint8_t uint_least8_t;
|
||||
typedef uint16_t uint_least16_t;
|
||||
typedef uint32_t uint_least32_t;
|
||||
typedef uint64_t uint_least64_t;
|
||||
|
||||
/* 7.18.1.3 Fastest minimum-width integer types. */
|
||||
typedef int8_t int_fast8_t;
|
||||
typedef int16_t int_fast16_t;
|
||||
typedef int32_t int_fast32_t;
|
||||
typedef int64_t int_fast64_t;
|
||||
typedef uint8_t uint_fast8_t;
|
||||
typedef uint16_t uint_fast16_t;
|
||||
typedef uint32_t uint_fast32_t;
|
||||
typedef uint64_t uint_fast64_t;
|
||||
|
||||
/* 7.18.1.4 Integer types capable of holding object pointers. */
|
||||
#ifdef _WIN64 /* [ */
|
||||
typedef signed __int64 intptr_t;
|
||||
typedef unsigned __int64 uintptr_t;
|
||||
#else /* _WIN64 ][ */
|
||||
typedef _W64 signed int intptr_t;
|
||||
typedef _W64 unsigned int uintptr_t;
|
||||
#endif /* _WIN64 ] */
|
||||
|
||||
/* 7.18.1.5 Greatest-width integer types. */
|
||||
typedef int64_t intmax_t;
|
||||
typedef uint64_t uintmax_t;
|
||||
|
||||
/* 7.18.2 Limits of specified-width integer types. */
|
||||
|
||||
#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS)
|
||||
/* [ See footnote 220 at page 257 and footnote 221 at page 259. */
|
||||
|
||||
/* 7.18.2.1 Limits of exact-width integer types. */
|
||||
#define INT8_MIN ((int8_t)_I8_MIN)
|
||||
#define INT8_MAX _I8_MAX
|
||||
#define INT16_MIN ((int16_t)_I16_MIN)
|
||||
#define INT16_MAX _I16_MAX
|
||||
#define INT32_MIN ((int32_t)_I32_MIN)
|
||||
#define INT32_MAX _I32_MAX
|
||||
#define INT64_MIN ((int64_t)_I64_MIN)
|
||||
#define INT64_MAX _I64_MAX
|
||||
#define UINT8_MAX _UI8_MAX
|
||||
#define UINT16_MAX _UI16_MAX
|
||||
#define UINT32_MAX _UI32_MAX
|
||||
#define UINT64_MAX _UI64_MAX
|
||||
|
||||
/* 7.18.2.2 Limits of minimum-width integer types. */
|
||||
#define INT_LEAST8_MIN INT8_MIN
|
||||
#define INT_LEAST8_MAX INT8_MAX
|
||||
#define INT_LEAST16_MIN INT16_MIN
|
||||
#define INT_LEAST16_MAX INT16_MAX
|
||||
#define INT_LEAST32_MIN INT32_MIN
|
||||
#define INT_LEAST32_MAX INT32_MAX
|
||||
#define INT_LEAST64_MIN INT64_MIN
|
||||
#define INT_LEAST64_MAX INT64_MAX
|
||||
#define UINT_LEAST8_MAX UINT8_MAX
|
||||
#define UINT_LEAST16_MAX UINT16_MAX
|
||||
#define UINT_LEAST32_MAX UINT32_MAX
|
||||
#define UINT_LEAST64_MAX UINT64_MAX
|
||||
|
||||
/* 7.18.2.3 Limits of fastest minimum-width integer types. */
|
||||
#define INT_FAST8_MIN INT8_MIN
|
||||
#define INT_FAST8_MAX INT8_MAX
|
||||
#define INT_FAST16_MIN INT16_MIN
|
||||
#define INT_FAST16_MAX INT16_MAX
|
||||
#define INT_FAST32_MIN INT32_MIN
|
||||
#define INT_FAST32_MAX INT32_MAX
|
||||
#define INT_FAST64_MIN INT64_MIN
|
||||
#define INT_FAST64_MAX INT64_MAX
|
||||
#define UINT_FAST8_MAX UINT8_MAX
|
||||
#define UINT_FAST16_MAX UINT16_MAX
|
||||
#define UINT_FAST32_MAX UINT32_MAX
|
||||
#define UINT_FAST64_MAX UINT64_MAX
|
||||
|
||||
/* 7.18.2.4 Limits of integer types capable of holding object pointers. */
|
||||
#ifdef _WIN64 /* [ */
|
||||
# define INTPTR_MIN INT64_MIN
|
||||
# define INTPTR_MAX INT64_MAX
|
||||
# define UINTPTR_MAX UINT64_MAX
|
||||
#else /* _WIN64 ][ */
|
||||
# define INTPTR_MIN INT32_MIN
|
||||
# define INTPTR_MAX INT32_MAX
|
||||
# define UINTPTR_MAX UINT32_MAX
|
||||
#endif /* _WIN64 ] */
|
||||
|
||||
/* 7.18.2.5 Limits of greatest-width integer types */
|
||||
#define INTMAX_MIN INT64_MIN
|
||||
#define INTMAX_MAX INT64_MAX
|
||||
#define UINTMAX_MAX UINT64_MAX
|
||||
|
||||
/* 7.18.3 Limits of other integer types */
|
||||
|
||||
#ifdef _WIN64 /* [ */
|
||||
# define PTRDIFF_MIN _I64_MIN
|
||||
# define PTRDIFF_MAX _I64_MAX
|
||||
#else /* _WIN64 ][ */
|
||||
# define PTRDIFF_MIN _I32_MIN
|
||||
# define PTRDIFF_MAX _I32_MAX
|
||||
#endif /* _WIN64 ] */
|
||||
|
||||
#define SIG_ATOMIC_MIN INT_MIN
|
||||
#define SIG_ATOMIC_MAX INT_MAX
|
||||
|
||||
#ifndef SIZE_MAX /* [ */
|
||||
# ifdef _WIN64 /* [ */
|
||||
# define SIZE_MAX _UI64_MAX
|
||||
# else /* _WIN64 ][ */
|
||||
# define SIZE_MAX _UI32_MAX
|
||||
# endif /* _WIN64 ] */
|
||||
#endif /* SIZE_MAX ] */
|
||||
|
||||
/* WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h> */
|
||||
#ifndef WCHAR_MIN /* [ */
|
||||
# define WCHAR_MIN 0
|
||||
#endif /* WCHAR_MIN ] */
|
||||
#ifndef WCHAR_MAX // [
|
||||
# define WCHAR_MAX _UI16_MAX
|
||||
#endif /* WCHAR_MAX ] */
|
||||
|
||||
#define WINT_MIN 0
|
||||
#define WINT_MAX _UI16_MAX
|
||||
|
||||
#endif /* __STDC_LIMIT_MACROS ] */
|
||||
|
||||
/* 7.18.4 Limits of other integer types */
|
||||
|
||||
#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS)
|
||||
/* [ See footnote 224 at page 260 */
|
||||
|
||||
/* 7.18.4.1 Macros for minimum-width integer constants */
|
||||
|
||||
#define INT8_C(val) val##i8
|
||||
#define INT16_C(val) val##i16
|
||||
#define INT32_C(val) val##i32
|
||||
#define INT64_C(val) val##i64
|
||||
|
||||
#define UINT8_C(val) val##ui8
|
||||
#define UINT16_C(val) val##ui16
|
||||
#define UINT32_C(val) val##ui32
|
||||
#define UINT64_C(val) val##ui64
|
||||
|
||||
/* 7.18.4.2 Macros for greatest-width integer constants */
|
||||
#define INTMAX_C INT64_C
|
||||
#define UINTMAX_C UINT64_C
|
||||
|
||||
#endif
|
||||
/* __STDC_CONSTANT_MACROS ] */
|
||||
|
||||
#else
|
||||
/* Sanity for everything else. */
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,64 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (posix_string.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __LIBRETRO_SDK_COMPAT_POSIX_STRING_H
|
||||
#define __LIBRETRO_SDK_COMPAT_POSIX_STRING_H
|
||||
|
||||
#include <retro_common_api.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <compat/msvc.h>
|
||||
#endif
|
||||
|
||||
#if defined(PS2)
|
||||
#include <compat_ctype.h>
|
||||
#endif
|
||||
|
||||
RETRO_BEGIN_DECLS
|
||||
|
||||
#ifdef _WIN32
|
||||
#undef strtok_r
|
||||
#define strtok_r(str, delim, saveptr) retro_strtok_r__(str, delim, saveptr)
|
||||
|
||||
char *strtok_r(char *str, const char *delim, char **saveptr);
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#undef strcasecmp
|
||||
#undef strdup
|
||||
#define strcasecmp(a, b) retro_strcasecmp__(a, b)
|
||||
#define strdup(orig) retro_strdup__(orig)
|
||||
int strcasecmp(const char *a, const char *b);
|
||||
char *strdup(const char *orig);
|
||||
|
||||
/* isblank is available since MSVC 2013 */
|
||||
#if _MSC_VER < 1800
|
||||
#undef isblank
|
||||
#define isblank(c) retro_isblank__(c)
|
||||
int isblank(int c);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,52 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (strcasestr.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __LIBRETRO_SDK_COMPAT_STRCASESTR_H
|
||||
#define __LIBRETRO_SDK_COMPAT_STRCASESTR_H
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#if defined(PS2)
|
||||
#include <compat_ctype.h>
|
||||
#endif
|
||||
|
||||
#if defined(RARCH_INTERNAL) && defined(HAVE_CONFIG_H)
|
||||
#include "../../../config.h"
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRCASESTR
|
||||
|
||||
#include <retro_common_api.h>
|
||||
|
||||
RETRO_BEGIN_DECLS
|
||||
|
||||
/* Avoid possible naming collisions during link
|
||||
* since we prefer to use the actual name. */
|
||||
#define strcasestr(haystack, needle) strcasestr_retro__(haystack, needle)
|
||||
|
||||
char *strcasestr(const char *haystack, const char *needle);
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,59 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (strl.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __LIBRETRO_SDK_COMPAT_STRL_H
|
||||
#define __LIBRETRO_SDK_COMPAT_STRL_H
|
||||
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#if defined(RARCH_INTERNAL) && defined(HAVE_CONFIG_H)
|
||||
#include "../../../config.h"
|
||||
#endif
|
||||
|
||||
#include <retro_common_api.h>
|
||||
|
||||
RETRO_BEGIN_DECLS
|
||||
|
||||
#ifdef __MACH__
|
||||
#ifndef HAVE_STRL
|
||||
#define HAVE_STRL
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRL
|
||||
/* Avoid possible naming collisions during link since
|
||||
* we prefer to use the actual name. */
|
||||
#define strlcpy(dst, src, size) strlcpy_retro__(dst, src, size)
|
||||
|
||||
#define strlcat(dst, src, size) strlcat_retro__(dst, src, size)
|
||||
|
||||
size_t strlcpy(char *dest, const char *source, size_t size);
|
||||
size_t strlcat(char *dest, const char *source, size_t size);
|
||||
|
||||
#endif
|
||||
|
||||
char *strldup(const char *s, size_t n);
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,483 @@
|
||||
/* zconf.h -- configuration of the zlib compression library
|
||||
* Copyright (C) 1995-2013 Jean-loup Gailly.
|
||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||
*/
|
||||
|
||||
/* @(#) $Id$ */
|
||||
|
||||
#ifndef ZCONF_H
|
||||
#define ZCONF_H
|
||||
|
||||
/*
|
||||
* If you *really* need a unique prefix for all types and library functions,
|
||||
* compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
|
||||
* Even better than compiling with -DZ_PREFIX would be to use configure to set
|
||||
* this permanently in zconf.h using "./configure --zprefix".
|
||||
*/
|
||||
#ifdef Z_PREFIX /* may be set to #if 1 by ./configure */
|
||||
# define Z_PREFIX_SET
|
||||
|
||||
/* all linked symbols */
|
||||
# define _dist_code z__dist_code
|
||||
# define _length_code z__length_code
|
||||
# define _tr_align z__tr_align
|
||||
# define _tr_flush_bits z__tr_flush_bits
|
||||
# define _tr_flush_block z__tr_flush_block
|
||||
# define _tr_init z__tr_init
|
||||
# define _tr_stored_block z__tr_stored_block
|
||||
# define _tr_tally z__tr_tally
|
||||
# define adler32 z_adler32
|
||||
# define adler32_combine z_adler32_combine
|
||||
# define adler32_combine64 z_adler32_combine64
|
||||
# ifndef Z_SOLO
|
||||
# define compress z_compress
|
||||
# define compress2 z_compress2
|
||||
# define compressBound z_compressBound
|
||||
# endif
|
||||
# define crc32 z_crc32
|
||||
# define crc32_combine z_crc32_combine
|
||||
# define crc32_combine64 z_crc32_combine64
|
||||
# define deflate z_deflate
|
||||
# define deflateBound z_deflateBound
|
||||
# define deflateCopy z_deflateCopy
|
||||
# define deflateEnd z_deflateEnd
|
||||
# define deflateInit2_ z_deflateInit2_
|
||||
# define deflateInit_ z_deflateInit_
|
||||
# define deflateParams z_deflateParams
|
||||
# define deflatePending z_deflatePending
|
||||
# define deflatePrime z_deflatePrime
|
||||
# define deflateReset z_deflateReset
|
||||
# define deflateResetKeep z_deflateResetKeep
|
||||
# define deflateSetDictionary z_deflateSetDictionary
|
||||
# define deflateSetHeader z_deflateSetHeader
|
||||
# define deflateTune z_deflateTune
|
||||
# define deflate_copyright z_deflate_copyright
|
||||
# define get_crc_table z_get_crc_table
|
||||
# ifndef Z_SOLO
|
||||
# define gz_error z_gz_error
|
||||
# define gz_intmax z_gz_intmax
|
||||
# define gz_strwinerror z_gz_strwinerror
|
||||
# define gzbuffer z_gzbuffer
|
||||
# define gzclearerr z_gzclearerr
|
||||
# define gzclose z_gzclose
|
||||
# define gzclose_r z_gzclose_r
|
||||
# define gzclose_w z_gzclose_w
|
||||
# define gzdirect z_gzdirect
|
||||
# define gzdopen z_gzdopen
|
||||
# define gzeof z_gzeof
|
||||
# define gzerror z_gzerror
|
||||
# define gzflush z_gzflush
|
||||
# define gzgetc z_gzgetc
|
||||
# define gzgetc_ z_gzgetc_
|
||||
# define gzgets z_gzgets
|
||||
# define gzoffset z_gzoffset
|
||||
# define gzoffset64 z_gzoffset64
|
||||
# define gzopen z_gzopen
|
||||
# define gzopen64 z_gzopen64
|
||||
# ifdef _WIN32
|
||||
# define gzopen_w z_gzopen_w
|
||||
# endif
|
||||
# define gzprintf z_gzprintf
|
||||
# define gzvprintf z_gzvprintf
|
||||
# define gzputc z_gzputc
|
||||
# define gzputs z_gzputs
|
||||
# define gzread z_gzread
|
||||
# define gzrewind z_gzrewind
|
||||
# define gzseek z_gzseek
|
||||
# define gzseek64 z_gzseek64
|
||||
# define gzsetparams z_gzsetparams
|
||||
# define gztell z_gztell
|
||||
# define gztell64 z_gztell64
|
||||
# define gzungetc z_gzungetc
|
||||
# define gzwrite z_gzwrite
|
||||
# endif
|
||||
# define inflate z_inflate
|
||||
# define inflateBack z_inflateBack
|
||||
# define inflateBackEnd z_inflateBackEnd
|
||||
# define inflateBackInit_ z_inflateBackInit_
|
||||
# define inflateCopy z_inflateCopy
|
||||
# define inflateEnd z_inflateEnd
|
||||
# define inflateGetHeader z_inflateGetHeader
|
||||
# define inflateInit2_ z_inflateInit2_
|
||||
# define inflateInit_ z_inflateInit_
|
||||
# define inflateMark z_inflateMark
|
||||
# define inflatePrime z_inflatePrime
|
||||
# define inflateReset z_inflateReset
|
||||
# define inflateReset2 z_inflateReset2
|
||||
# define inflateSetDictionary z_inflateSetDictionary
|
||||
# define inflateGetDictionary z_inflateGetDictionary
|
||||
# define inflateSync z_inflateSync
|
||||
# define inflateSyncPoint z_inflateSyncPoint
|
||||
# define inflateUndermine z_inflateUndermine
|
||||
# define inflateResetKeep z_inflateResetKeep
|
||||
# define inflate_copyright z_inflate_copyright
|
||||
# define inflate_fast z_inflate_fast
|
||||
# define inflate_table z_inflate_table
|
||||
# ifndef Z_SOLO
|
||||
# define uncompress z_uncompress
|
||||
# endif
|
||||
# define zError z_zError
|
||||
# ifndef Z_SOLO
|
||||
# define zcalloc z_zcalloc
|
||||
# define zcfree z_zcfree
|
||||
# endif
|
||||
# define zlibCompileFlags z_zlibCompileFlags
|
||||
# define zlibVersion z_zlibVersion
|
||||
|
||||
/* all zlib typedefs in zlib.h and zconf.h */
|
||||
# define Byte z_Byte
|
||||
# define Bytef z_Bytef
|
||||
# define alloc_func z_alloc_func
|
||||
# define charf z_charf
|
||||
# define free_func z_free_func
|
||||
# ifndef Z_SOLO
|
||||
# define gzFile z_gzFile
|
||||
# endif
|
||||
# define gz_header z_gz_header
|
||||
# define gz_headerp z_gz_headerp
|
||||
# define in_func z_in_func
|
||||
# define intf z_intf
|
||||
# define out_func z_out_func
|
||||
# define uInt z_uInt
|
||||
# define uIntf z_uIntf
|
||||
# define uLong z_uLong
|
||||
# define uLongf z_uLongf
|
||||
# define voidp z_voidp
|
||||
# define voidpc z_voidpc
|
||||
# define voidpf z_voidpf
|
||||
|
||||
/* all zlib structs in zlib.h and zconf.h */
|
||||
# define gz_header_s z_gz_header_s
|
||||
# define internal_state z_internal_state
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__MSDOS__) && !defined(MSDOS)
|
||||
# define MSDOS
|
||||
#endif
|
||||
#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2)
|
||||
# define OS2
|
||||
#endif
|
||||
#if defined(_WINDOWS) && !defined(WINDOWS)
|
||||
# define WINDOWS
|
||||
#endif
|
||||
#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__)
|
||||
# ifndef WIN32
|
||||
# define WIN32
|
||||
# endif
|
||||
#endif
|
||||
#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32)
|
||||
# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__)
|
||||
# ifndef SYS16BIT
|
||||
# define SYS16BIT
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Compile with -DMAXSEG_64K if the alloc function cannot allocate more
|
||||
* than 64k bytes at a time (needed on systems with 16-bit int).
|
||||
*/
|
||||
#ifdef SYS16BIT
|
||||
# define MAXSEG_64K
|
||||
#endif
|
||||
#ifdef MSDOS
|
||||
# define UNALIGNED_OK
|
||||
#endif
|
||||
|
||||
#ifdef __STDC_VERSION__
|
||||
# ifndef STDC
|
||||
# define STDC
|
||||
# endif
|
||||
# if __STDC_VERSION__ >= 199901L
|
||||
# ifndef STDC99
|
||||
# define STDC99
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus))
|
||||
# define STDC
|
||||
#endif
|
||||
#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__))
|
||||
# define STDC
|
||||
#endif
|
||||
#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32))
|
||||
# define STDC
|
||||
#endif
|
||||
#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__))
|
||||
# define STDC
|
||||
#endif
|
||||
|
||||
#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */
|
||||
# define STDC
|
||||
#endif
|
||||
|
||||
#ifndef STDC
|
||||
# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
|
||||
# define const /* note: need a more gentle solution here */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(ZLIB_CONST) && !defined(z_const)
|
||||
# define z_const const
|
||||
#else
|
||||
# define z_const
|
||||
#endif
|
||||
|
||||
/* Some Mac compilers merge all .h files incorrectly: */
|
||||
#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__)
|
||||
# define NO_DUMMY_DECL
|
||||
#endif
|
||||
|
||||
/* Maximum value for memLevel in deflateInit2 */
|
||||
#ifndef MAX_MEM_LEVEL
|
||||
# ifdef MAXSEG_64K
|
||||
# define MAX_MEM_LEVEL 8
|
||||
# else
|
||||
# define MAX_MEM_LEVEL 9
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Maximum value for windowBits in deflateInit2 and inflateInit2.
|
||||
* WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
|
||||
* created by gzip. (Files created by minigzip can still be extracted by
|
||||
* gzip.)
|
||||
*/
|
||||
#ifndef MAX_WBITS
|
||||
# define MAX_WBITS 15 /* 32K LZ77 window */
|
||||
#endif
|
||||
|
||||
/* The memory requirements for deflate are (in bytes):
|
||||
(1 << (windowBits+2)) + (1 << (memLevel+9))
|
||||
that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values)
|
||||
plus a few kilobytes for small objects. For example, if you want to reduce
|
||||
the default memory requirements from 256K to 128K, compile with
|
||||
make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
|
||||
Of course this will generally degrade compression (there's no free lunch).
|
||||
|
||||
The memory requirements for inflate are (in bytes) 1 << windowBits
|
||||
that is, 32K for windowBits=15 (default value) plus a few kilobytes
|
||||
for small objects.
|
||||
*/
|
||||
|
||||
/* Type declarations */
|
||||
|
||||
#ifndef OF /* function prototypes */
|
||||
# ifdef STDC
|
||||
# define OF(args) args
|
||||
# else
|
||||
# define OF(args) ()
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef Z_ARG /* function prototypes for stdarg */
|
||||
# if defined(STDC) || defined(Z_HAVE_STDARG_H)
|
||||
# define Z_ARG(args) args
|
||||
# else
|
||||
# define Z_ARG(args) ()
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* The following definitions for FAR are needed only for MSDOS mixed
|
||||
* model programming (small or medium model with some far allocations).
|
||||
* This was tested only with MSC; for other MSDOS compilers you may have
|
||||
* to define NO_MEMCPY in zutil.h. If you don't need the mixed model,
|
||||
* just define FAR to be empty.
|
||||
*/
|
||||
#ifdef SYS16BIT
|
||||
# if defined(M_I86SM) || defined(M_I86MM)
|
||||
/* MSC small or medium model */
|
||||
# define SMALL_MEDIUM
|
||||
# ifdef _MSC_VER
|
||||
# define FAR _far
|
||||
# else
|
||||
# define FAR far
|
||||
# endif
|
||||
# endif
|
||||
# if (defined(__SMALL__) || defined(__MEDIUM__))
|
||||
/* Turbo C small or medium model */
|
||||
# define SMALL_MEDIUM
|
||||
# ifdef __BORLANDC__
|
||||
# define FAR _far
|
||||
# else
|
||||
# define FAR far
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(WINDOWS) || defined(WIN32)
|
||||
/* If building or using zlib as a DLL, define ZLIB_DLL.
|
||||
* This is not mandatory, but it offers a little performance increase.
|
||||
*/
|
||||
# ifdef ZLIB_DLL
|
||||
# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500))
|
||||
# ifdef ZLIB_INTERNAL
|
||||
# define ZEXTERN extern __declspec(dllexport)
|
||||
# else
|
||||
# define ZEXTERN extern __declspec(dllimport)
|
||||
# endif
|
||||
# endif
|
||||
# endif /* ZLIB_DLL */
|
||||
/* If building or using zlib with the WINAPI/WINAPIV calling convention,
|
||||
* define ZLIB_WINAPI.
|
||||
* Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
|
||||
*/
|
||||
# ifdef ZLIB_WINAPI
|
||||
# ifdef FAR
|
||||
# undef FAR
|
||||
# endif
|
||||
# include <windows.h>
|
||||
/* No need for _export, use ZLIB.DEF instead. */
|
||||
/* For complete Windows compatibility, use WINAPI, not __stdcall. */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef FAR
|
||||
# define FAR
|
||||
#endif
|
||||
|
||||
#if !defined(__MACTYPES__)
|
||||
typedef unsigned char Byte; /* 8 bits */
|
||||
#endif
|
||||
typedef unsigned int uInt; /* 16 bits or more */
|
||||
typedef unsigned long uLong; /* 32 bits or more */
|
||||
|
||||
#ifdef SMALL_MEDIUM
|
||||
/* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
|
||||
# define Bytef Byte FAR
|
||||
#else
|
||||
typedef Byte FAR Bytef;
|
||||
#endif
|
||||
typedef char FAR charf;
|
||||
typedef int FAR intf;
|
||||
typedef uInt FAR uIntf;
|
||||
typedef uLong FAR uLongf;
|
||||
|
||||
#ifdef STDC
|
||||
typedef void const *voidpc;
|
||||
typedef void FAR *voidpf;
|
||||
typedef void *voidp;
|
||||
#else
|
||||
typedef Byte const *voidpc;
|
||||
typedef Byte FAR *voidpf;
|
||||
typedef Byte *voidp;
|
||||
#endif
|
||||
|
||||
#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC)
|
||||
# include <limits.h>
|
||||
# if (UINT_MAX == 0xffffffffUL)
|
||||
# define Z_U4 unsigned
|
||||
# elif (ULONG_MAX == 0xffffffffUL)
|
||||
# define Z_U4 unsigned long
|
||||
# elif (USHRT_MAX == 0xffffffffUL)
|
||||
# define Z_U4 unsigned short
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef Z_U4
|
||||
typedef Z_U4 z_crc_t;
|
||||
#else
|
||||
typedef unsigned long z_crc_t;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */
|
||||
# define Z_HAVE_UNISTD_H
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STDARG_H /* may be set to #if 1 by ./configure */
|
||||
# define Z_HAVE_STDARG_H
|
||||
#endif
|
||||
|
||||
#ifdef STDC
|
||||
# ifndef Z_SOLO
|
||||
# include <sys/types.h> /* for off_t */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(STDC) || defined(Z_HAVE_STDARG_H)
|
||||
# ifndef Z_SOLO
|
||||
# include <stdarg.h> /* for va_list */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
# ifndef Z_SOLO
|
||||
# include <stddef.h> /* for wchar_t */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and
|
||||
* "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even
|
||||
* though the former does not conform to the LFS document), but considering
|
||||
* both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as
|
||||
* equivalently requesting no 64-bit operations
|
||||
*/
|
||||
#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1
|
||||
# undef _LARGEFILE64_SOURCE
|
||||
#endif
|
||||
|
||||
#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H)
|
||||
# define Z_HAVE_UNISTD_H
|
||||
#endif
|
||||
#ifndef Z_SOLO
|
||||
# if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE)
|
||||
# include <unistd.h> /* for SEEK_*, off_t, and _LFS64_LARGEFILE */
|
||||
# ifdef VMS
|
||||
# include <unixio.h> /* for off_t */
|
||||
# endif
|
||||
# ifndef z_off_t
|
||||
# define z_off_t off_t
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0
|
||||
# define Z_LFS64
|
||||
#endif
|
||||
|
||||
#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64)
|
||||
# define Z_LARGE64
|
||||
#endif
|
||||
|
||||
#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64)
|
||||
# define Z_WANT64
|
||||
#endif
|
||||
|
||||
#if !defined(SEEK_SET) && !defined(Z_SOLO)
|
||||
# define SEEK_SET 0 /* Seek from beginning of file. */
|
||||
# define SEEK_CUR 1 /* Seek from current position. */
|
||||
# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */
|
||||
#endif
|
||||
|
||||
#ifndef z_off_t
|
||||
# define z_off_t long
|
||||
#endif
|
||||
|
||||
#if !defined(_WIN32) && defined(Z_LARGE64)
|
||||
# define z_off64_t off64_t
|
||||
#else
|
||||
# if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO)
|
||||
# define z_off64_t __int64
|
||||
# else
|
||||
# define z_off64_t z_off_t
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* MVS linker does not support external names larger than 8 bytes */
|
||||
#if defined(__MVS__)
|
||||
#pragma map(deflateInit_,"DEIN")
|
||||
#pragma map(deflateInit2_,"DEIN2")
|
||||
#pragma map(deflateEnd,"DEEND")
|
||||
#pragma map(deflateBound,"DEBND")
|
||||
#pragma map(inflateInit_,"ININ")
|
||||
#pragma map(inflateInit2_,"ININ2")
|
||||
#pragma map(inflateEnd,"INEND")
|
||||
#pragma map(inflateSync,"INSY")
|
||||
#pragma map(inflateSetDictionary,"INSEDI")
|
||||
#pragma map(compressBound,"CMBND")
|
||||
#pragma map(inflate_table,"INTABL")
|
||||
#pragma map(inflate_fast,"INFA")
|
||||
#pragma map(inflate_copyright,"INCOPY")
|
||||
#endif
|
||||
|
||||
#endif /* ZCONF_H */
|
||||
@@ -0,0 +1,483 @@
|
||||
/* zconf.h -- configuration of the zlib compression library
|
||||
* Copyright (C) 1995-2013 Jean-loup Gailly.
|
||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||
*/
|
||||
|
||||
/* @(#) $Id$ */
|
||||
|
||||
#ifndef ZCONF_H
|
||||
#define ZCONF_H
|
||||
|
||||
/*
|
||||
* If you *really* need a unique prefix for all types and library functions,
|
||||
* compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
|
||||
* Even better than compiling with -DZ_PREFIX would be to use configure to set
|
||||
* this permanently in zconf.h using "./configure --zprefix".
|
||||
*/
|
||||
#ifdef Z_PREFIX /* may be set to #if 1 by ./configure */
|
||||
# define Z_PREFIX_SET
|
||||
|
||||
/* all linked symbols */
|
||||
# define _dist_code z__dist_code
|
||||
# define _length_code z__length_code
|
||||
# define _tr_align z__tr_align
|
||||
# define _tr_flush_bits z__tr_flush_bits
|
||||
# define _tr_flush_block z__tr_flush_block
|
||||
# define _tr_init z__tr_init
|
||||
# define _tr_stored_block z__tr_stored_block
|
||||
# define _tr_tally z__tr_tally
|
||||
# define adler32 z_adler32
|
||||
# define adler32_combine z_adler32_combine
|
||||
# define adler32_combine64 z_adler32_combine64
|
||||
# ifndef Z_SOLO
|
||||
# define compress z_compress
|
||||
# define compress2 z_compress2
|
||||
# define compressBound z_compressBound
|
||||
# endif
|
||||
# define crc32 z_crc32
|
||||
# define crc32_combine z_crc32_combine
|
||||
# define crc32_combine64 z_crc32_combine64
|
||||
# define deflate z_deflate
|
||||
# define deflateBound z_deflateBound
|
||||
# define deflateCopy z_deflateCopy
|
||||
# define deflateEnd z_deflateEnd
|
||||
# define deflateInit2_ z_deflateInit2_
|
||||
# define deflateInit_ z_deflateInit_
|
||||
# define deflateParams z_deflateParams
|
||||
# define deflatePending z_deflatePending
|
||||
# define deflatePrime z_deflatePrime
|
||||
# define deflateReset z_deflateReset
|
||||
# define deflateResetKeep z_deflateResetKeep
|
||||
# define deflateSetDictionary z_deflateSetDictionary
|
||||
# define deflateSetHeader z_deflateSetHeader
|
||||
# define deflateTune z_deflateTune
|
||||
# define deflate_copyright z_deflate_copyright
|
||||
# define get_crc_table z_get_crc_table
|
||||
# ifndef Z_SOLO
|
||||
# define gz_error z_gz_error
|
||||
# define gz_intmax z_gz_intmax
|
||||
# define gz_strwinerror z_gz_strwinerror
|
||||
# define gzbuffer z_gzbuffer
|
||||
# define gzclearerr z_gzclearerr
|
||||
# define gzclose z_gzclose
|
||||
# define gzclose_r z_gzclose_r
|
||||
# define gzclose_w z_gzclose_w
|
||||
# define gzdirect z_gzdirect
|
||||
# define gzdopen z_gzdopen
|
||||
# define gzeof z_gzeof
|
||||
# define gzerror z_gzerror
|
||||
# define gzflush z_gzflush
|
||||
# define gzgetc z_gzgetc
|
||||
# define gzgetc_ z_gzgetc_
|
||||
# define gzgets z_gzgets
|
||||
# define gzoffset z_gzoffset
|
||||
# define gzoffset64 z_gzoffset64
|
||||
# define gzopen z_gzopen
|
||||
# define gzopen64 z_gzopen64
|
||||
# ifdef _WIN32
|
||||
# define gzopen_w z_gzopen_w
|
||||
# endif
|
||||
# define gzprintf z_gzprintf
|
||||
# define gzvprintf z_gzvprintf
|
||||
# define gzputc z_gzputc
|
||||
# define gzputs z_gzputs
|
||||
# define gzread z_gzread
|
||||
# define gzrewind z_gzrewind
|
||||
# define gzseek z_gzseek
|
||||
# define gzseek64 z_gzseek64
|
||||
# define gzsetparams z_gzsetparams
|
||||
# define gztell z_gztell
|
||||
# define gztell64 z_gztell64
|
||||
# define gzungetc z_gzungetc
|
||||
# define gzwrite z_gzwrite
|
||||
# endif
|
||||
# define inflate z_inflate
|
||||
# define inflateBack z_inflateBack
|
||||
# define inflateBackEnd z_inflateBackEnd
|
||||
# define inflateBackInit_ z_inflateBackInit_
|
||||
# define inflateCopy z_inflateCopy
|
||||
# define inflateEnd z_inflateEnd
|
||||
# define inflateGetHeader z_inflateGetHeader
|
||||
# define inflateInit2_ z_inflateInit2_
|
||||
# define inflateInit_ z_inflateInit_
|
||||
# define inflateMark z_inflateMark
|
||||
# define inflatePrime z_inflatePrime
|
||||
# define inflateReset z_inflateReset
|
||||
# define inflateReset2 z_inflateReset2
|
||||
# define inflateSetDictionary z_inflateSetDictionary
|
||||
# define inflateGetDictionary z_inflateGetDictionary
|
||||
# define inflateSync z_inflateSync
|
||||
# define inflateSyncPoint z_inflateSyncPoint
|
||||
# define inflateUndermine z_inflateUndermine
|
||||
# define inflateResetKeep z_inflateResetKeep
|
||||
# define inflate_copyright z_inflate_copyright
|
||||
# define inflate_fast z_inflate_fast
|
||||
# define inflate_table z_inflate_table
|
||||
# ifndef Z_SOLO
|
||||
# define uncompress z_uncompress
|
||||
# endif
|
||||
# define zError z_zError
|
||||
# ifndef Z_SOLO
|
||||
# define zcalloc z_zcalloc
|
||||
# define zcfree z_zcfree
|
||||
# endif
|
||||
# define zlibCompileFlags z_zlibCompileFlags
|
||||
# define zlibVersion z_zlibVersion
|
||||
|
||||
/* all zlib typedefs in zlib.h and zconf.h */
|
||||
# define Byte z_Byte
|
||||
# define Bytef z_Bytef
|
||||
# define alloc_func z_alloc_func
|
||||
# define charf z_charf
|
||||
# define free_func z_free_func
|
||||
# ifndef Z_SOLO
|
||||
# define gzFile z_gzFile
|
||||
# endif
|
||||
# define gz_header z_gz_header
|
||||
# define gz_headerp z_gz_headerp
|
||||
# define in_func z_in_func
|
||||
# define intf z_intf
|
||||
# define out_func z_out_func
|
||||
# define uInt z_uInt
|
||||
# define uIntf z_uIntf
|
||||
# define uLong z_uLong
|
||||
# define uLongf z_uLongf
|
||||
# define voidp z_voidp
|
||||
# define voidpc z_voidpc
|
||||
# define voidpf z_voidpf
|
||||
|
||||
/* all zlib structs in zlib.h and zconf.h */
|
||||
# define gz_header_s z_gz_header_s
|
||||
# define internal_state z_internal_state
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__MSDOS__) && !defined(MSDOS)
|
||||
# define MSDOS
|
||||
#endif
|
||||
#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2)
|
||||
# define OS2
|
||||
#endif
|
||||
#if defined(_WINDOWS) && !defined(WINDOWS)
|
||||
# define WINDOWS
|
||||
#endif
|
||||
#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__)
|
||||
# ifndef WIN32
|
||||
# define WIN32
|
||||
# endif
|
||||
#endif
|
||||
#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32)
|
||||
# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__)
|
||||
# ifndef SYS16BIT
|
||||
# define SYS16BIT
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Compile with -DMAXSEG_64K if the alloc function cannot allocate more
|
||||
* than 64k bytes at a time (needed on systems with 16-bit int).
|
||||
*/
|
||||
#ifdef SYS16BIT
|
||||
# define MAXSEG_64K
|
||||
#endif
|
||||
#ifdef MSDOS
|
||||
# define UNALIGNED_OK
|
||||
#endif
|
||||
|
||||
#ifdef __STDC_VERSION__
|
||||
# ifndef STDC
|
||||
# define STDC
|
||||
# endif
|
||||
# if __STDC_VERSION__ >= 199901L
|
||||
# ifndef STDC99
|
||||
# define STDC99
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus))
|
||||
# define STDC
|
||||
#endif
|
||||
#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__))
|
||||
# define STDC
|
||||
#endif
|
||||
#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32))
|
||||
# define STDC
|
||||
#endif
|
||||
#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__))
|
||||
# define STDC
|
||||
#endif
|
||||
|
||||
#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */
|
||||
# define STDC
|
||||
#endif
|
||||
|
||||
#ifndef STDC
|
||||
# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
|
||||
# define const /* note: need a more gentle solution here */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(ZLIB_CONST) && !defined(z_const)
|
||||
# define z_const const
|
||||
#else
|
||||
# define z_const
|
||||
#endif
|
||||
|
||||
/* Some Mac compilers merge all .h files incorrectly: */
|
||||
#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__)
|
||||
# define NO_DUMMY_DECL
|
||||
#endif
|
||||
|
||||
/* Maximum value for memLevel in deflateInit2 */
|
||||
#ifndef MAX_MEM_LEVEL
|
||||
# ifdef MAXSEG_64K
|
||||
# define MAX_MEM_LEVEL 8
|
||||
# else
|
||||
# define MAX_MEM_LEVEL 9
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Maximum value for windowBits in deflateInit2 and inflateInit2.
|
||||
* WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
|
||||
* created by gzip. (Files created by minigzip can still be extracted by
|
||||
* gzip.)
|
||||
*/
|
||||
#ifndef MAX_WBITS
|
||||
# define MAX_WBITS 15 /* 32K LZ77 window */
|
||||
#endif
|
||||
|
||||
/* The memory requirements for deflate are (in bytes):
|
||||
(1 << (windowBits+2)) + (1 << (memLevel+9))
|
||||
that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values)
|
||||
plus a few kilobytes for small objects. For example, if you want to reduce
|
||||
the default memory requirements from 256K to 128K, compile with
|
||||
make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
|
||||
Of course this will generally degrade compression (there's no free lunch).
|
||||
|
||||
The memory requirements for inflate are (in bytes) 1 << windowBits
|
||||
that is, 32K for windowBits=15 (default value) plus a few kilobytes
|
||||
for small objects.
|
||||
*/
|
||||
|
||||
/* Type declarations */
|
||||
|
||||
#ifndef OF /* function prototypes */
|
||||
# ifdef STDC
|
||||
# define OF(args) args
|
||||
# else
|
||||
# define OF(args) ()
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef Z_ARG /* function prototypes for stdarg */
|
||||
# if defined(STDC) || defined(Z_HAVE_STDARG_H)
|
||||
# define Z_ARG(args) args
|
||||
# else
|
||||
# define Z_ARG(args) ()
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* The following definitions for FAR are needed only for MSDOS mixed
|
||||
* model programming (small or medium model with some far allocations).
|
||||
* This was tested only with MSC; for other MSDOS compilers you may have
|
||||
* to define NO_MEMCPY in zutil.h. If you don't need the mixed model,
|
||||
* just define FAR to be empty.
|
||||
*/
|
||||
#ifdef SYS16BIT
|
||||
# if defined(M_I86SM) || defined(M_I86MM)
|
||||
/* MSC small or medium model */
|
||||
# define SMALL_MEDIUM
|
||||
# ifdef _MSC_VER
|
||||
# define FAR _far
|
||||
# else
|
||||
# define FAR far
|
||||
# endif
|
||||
# endif
|
||||
# if (defined(__SMALL__) || defined(__MEDIUM__))
|
||||
/* Turbo C small or medium model */
|
||||
# define SMALL_MEDIUM
|
||||
# ifdef __BORLANDC__
|
||||
# define FAR _far
|
||||
# else
|
||||
# define FAR far
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(WINDOWS) || defined(WIN32)
|
||||
/* If building or using zlib as a DLL, define ZLIB_DLL.
|
||||
* This is not mandatory, but it offers a little performance increase.
|
||||
*/
|
||||
# ifdef ZLIB_DLL
|
||||
# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500))
|
||||
# ifdef ZLIB_INTERNAL
|
||||
# define ZEXTERN extern __declspec(dllexport)
|
||||
# else
|
||||
# define ZEXTERN extern __declspec(dllimport)
|
||||
# endif
|
||||
# endif
|
||||
# endif /* ZLIB_DLL */
|
||||
/* If building or using zlib with the WINAPI/WINAPIV calling convention,
|
||||
* define ZLIB_WINAPI.
|
||||
* Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
|
||||
*/
|
||||
# ifdef ZLIB_WINAPI
|
||||
# ifdef FAR
|
||||
# undef FAR
|
||||
# endif
|
||||
# include <windows.h>
|
||||
/* No need for _export, use ZLIB.DEF instead. */
|
||||
/* For complete Windows compatibility, use WINAPI, not __stdcall. */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef FAR
|
||||
# define FAR
|
||||
#endif
|
||||
|
||||
#if !defined(__MACTYPES__)
|
||||
typedef unsigned char Byte; /* 8 bits */
|
||||
#endif
|
||||
typedef unsigned int uInt; /* 16 bits or more */
|
||||
typedef unsigned long uLong; /* 32 bits or more */
|
||||
|
||||
#ifdef SMALL_MEDIUM
|
||||
/* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
|
||||
# define Bytef Byte FAR
|
||||
#else
|
||||
typedef Byte FAR Bytef;
|
||||
#endif
|
||||
typedef char FAR charf;
|
||||
typedef int FAR intf;
|
||||
typedef uInt FAR uIntf;
|
||||
typedef uLong FAR uLongf;
|
||||
|
||||
#ifdef STDC
|
||||
typedef void const *voidpc;
|
||||
typedef void FAR *voidpf;
|
||||
typedef void *voidp;
|
||||
#else
|
||||
typedef Byte const *voidpc;
|
||||
typedef Byte FAR *voidpf;
|
||||
typedef Byte *voidp;
|
||||
#endif
|
||||
|
||||
#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC)
|
||||
# include <limits.h>
|
||||
# if (UINT_MAX == 0xffffffffUL)
|
||||
# define Z_U4 unsigned
|
||||
# elif (ULONG_MAX == 0xffffffffUL)
|
||||
# define Z_U4 unsigned long
|
||||
# elif (USHRT_MAX == 0xffffffffUL)
|
||||
# define Z_U4 unsigned short
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef Z_U4
|
||||
typedef Z_U4 z_crc_t;
|
||||
#else
|
||||
typedef unsigned long z_crc_t;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */
|
||||
# define Z_HAVE_UNISTD_H
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STDARG_H /* may be set to #if 1 by ./configure */
|
||||
# define Z_HAVE_STDARG_H
|
||||
#endif
|
||||
|
||||
#ifdef STDC
|
||||
# ifndef Z_SOLO
|
||||
# include <sys/types.h> /* for off_t */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(STDC) || defined(Z_HAVE_STDARG_H)
|
||||
# ifndef Z_SOLO
|
||||
# include <stdarg.h> /* for va_list */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
# ifndef Z_SOLO
|
||||
# include <stddef.h> /* for wchar_t */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and
|
||||
* "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even
|
||||
* though the former does not conform to the LFS document), but considering
|
||||
* both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as
|
||||
* equivalently requesting no 64-bit operations
|
||||
*/
|
||||
#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1
|
||||
# undef _LARGEFILE64_SOURCE
|
||||
#endif
|
||||
|
||||
#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H)
|
||||
# define Z_HAVE_UNISTD_H
|
||||
#endif
|
||||
#ifndef Z_SOLO
|
||||
# if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE)
|
||||
# include <unistd.h> /* for SEEK_*, off_t, and _LFS64_LARGEFILE */
|
||||
# ifdef VMS
|
||||
# include <unixio.h> /* for off_t */
|
||||
# endif
|
||||
# ifndef z_off_t
|
||||
# define z_off_t off_t
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0
|
||||
# define Z_LFS64
|
||||
#endif
|
||||
|
||||
#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64)
|
||||
# define Z_LARGE64
|
||||
#endif
|
||||
|
||||
#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64)
|
||||
# define Z_WANT64
|
||||
#endif
|
||||
|
||||
#if !defined(SEEK_SET) && !defined(Z_SOLO)
|
||||
# define SEEK_SET 0 /* Seek from beginning of file. */
|
||||
# define SEEK_CUR 1 /* Seek from current position. */
|
||||
# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */
|
||||
#endif
|
||||
|
||||
#ifndef z_off_t
|
||||
# define z_off_t long
|
||||
#endif
|
||||
|
||||
#if !defined(_WIN32) && defined(Z_LARGE64)
|
||||
# define z_off64_t off64_t
|
||||
#else
|
||||
# if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO)
|
||||
# define z_off64_t __int64
|
||||
# else
|
||||
# define z_off64_t z_off_t
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* MVS linker does not support external names larger than 8 bytes */
|
||||
#if defined(__MVS__)
|
||||
#pragma map(deflateInit_,"DEIN")
|
||||
#pragma map(deflateInit2_,"DEIN2")
|
||||
#pragma map(deflateEnd,"DEEND")
|
||||
#pragma map(deflateBound,"DEBND")
|
||||
#pragma map(inflateInit_,"ININ")
|
||||
#pragma map(inflateInit2_,"ININ2")
|
||||
#pragma map(inflateEnd,"INEND")
|
||||
#pragma map(inflateSync,"INSY")
|
||||
#pragma map(inflateSetDictionary,"INSEDI")
|
||||
#pragma map(compressBound,"CMBND")
|
||||
#pragma map(inflate_table,"INTABL")
|
||||
#pragma map(inflate_fast,"INFA")
|
||||
#pragma map(inflate_copyright,"INCOPY")
|
||||
#endif
|
||||
|
||||
#endif /* ZCONF_H */
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,483 @@
|
||||
/* zconf.h -- configuration of the zlib compression library
|
||||
* Copyright (C) 1995-2013 Jean-loup Gailly.
|
||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||
*/
|
||||
|
||||
/* @(#) $Id$ */
|
||||
|
||||
#ifndef ZCONF_H
|
||||
#define ZCONF_H
|
||||
|
||||
/*
|
||||
* If you *really* need a unique prefix for all types and library functions,
|
||||
* compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
|
||||
* Even better than compiling with -DZ_PREFIX would be to use configure to set
|
||||
* this permanently in zconf.h using "./configure --zprefix".
|
||||
*/
|
||||
#ifdef Z_PREFIX /* may be set to #if 1 by ./configure */
|
||||
# define Z_PREFIX_SET
|
||||
|
||||
/* all linked symbols */
|
||||
# define _dist_code z__dist_code
|
||||
# define _length_code z__length_code
|
||||
# define _tr_align z__tr_align
|
||||
# define _tr_flush_bits z__tr_flush_bits
|
||||
# define _tr_flush_block z__tr_flush_block
|
||||
# define _tr_init z__tr_init
|
||||
# define _tr_stored_block z__tr_stored_block
|
||||
# define _tr_tally z__tr_tally
|
||||
# define adler32 z_adler32
|
||||
# define adler32_combine z_adler32_combine
|
||||
# define adler32_combine64 z_adler32_combine64
|
||||
# ifndef Z_SOLO
|
||||
# define compress z_compress
|
||||
# define compress2 z_compress2
|
||||
# define compressBound z_compressBound
|
||||
# endif
|
||||
# define crc32 z_crc32
|
||||
# define crc32_combine z_crc32_combine
|
||||
# define crc32_combine64 z_crc32_combine64
|
||||
# define deflate z_deflate
|
||||
# define deflateBound z_deflateBound
|
||||
# define deflateCopy z_deflateCopy
|
||||
# define deflateEnd z_deflateEnd
|
||||
# define deflateInit2_ z_deflateInit2_
|
||||
# define deflateInit_ z_deflateInit_
|
||||
# define deflateParams z_deflateParams
|
||||
# define deflatePending z_deflatePending
|
||||
# define deflatePrime z_deflatePrime
|
||||
# define deflateReset z_deflateReset
|
||||
# define deflateResetKeep z_deflateResetKeep
|
||||
# define deflateSetDictionary z_deflateSetDictionary
|
||||
# define deflateSetHeader z_deflateSetHeader
|
||||
# define deflateTune z_deflateTune
|
||||
# define deflate_copyright z_deflate_copyright
|
||||
# define get_crc_table z_get_crc_table
|
||||
# ifndef Z_SOLO
|
||||
# define gz_error z_gz_error
|
||||
# define gz_intmax z_gz_intmax
|
||||
# define gz_strwinerror z_gz_strwinerror
|
||||
# define gzbuffer z_gzbuffer
|
||||
# define gzclearerr z_gzclearerr
|
||||
# define gzclose z_gzclose
|
||||
# define gzclose_r z_gzclose_r
|
||||
# define gzclose_w z_gzclose_w
|
||||
# define gzdirect z_gzdirect
|
||||
# define gzdopen z_gzdopen
|
||||
# define gzeof z_gzeof
|
||||
# define gzerror z_gzerror
|
||||
# define gzflush z_gzflush
|
||||
# define gzgetc z_gzgetc
|
||||
# define gzgetc_ z_gzgetc_
|
||||
# define gzgets z_gzgets
|
||||
# define gzoffset z_gzoffset
|
||||
# define gzoffset64 z_gzoffset64
|
||||
# define gzopen z_gzopen
|
||||
# define gzopen64 z_gzopen64
|
||||
# ifdef _WIN32
|
||||
# define gzopen_w z_gzopen_w
|
||||
# endif
|
||||
# define gzprintf z_gzprintf
|
||||
# define gzvprintf z_gzvprintf
|
||||
# define gzputc z_gzputc
|
||||
# define gzputs z_gzputs
|
||||
# define gzread z_gzread
|
||||
# define gzrewind z_gzrewind
|
||||
# define gzseek z_gzseek
|
||||
# define gzseek64 z_gzseek64
|
||||
# define gzsetparams z_gzsetparams
|
||||
# define gztell z_gztell
|
||||
# define gztell64 z_gztell64
|
||||
# define gzungetc z_gzungetc
|
||||
# define gzwrite z_gzwrite
|
||||
# endif
|
||||
# define inflate z_inflate
|
||||
# define inflateBack z_inflateBack
|
||||
# define inflateBackEnd z_inflateBackEnd
|
||||
# define inflateBackInit_ z_inflateBackInit_
|
||||
# define inflateCopy z_inflateCopy
|
||||
# define inflateEnd z_inflateEnd
|
||||
# define inflateGetHeader z_inflateGetHeader
|
||||
# define inflateInit2_ z_inflateInit2_
|
||||
# define inflateInit_ z_inflateInit_
|
||||
# define inflateMark z_inflateMark
|
||||
# define inflatePrime z_inflatePrime
|
||||
# define inflateReset z_inflateReset
|
||||
# define inflateReset2 z_inflateReset2
|
||||
# define inflateSetDictionary z_inflateSetDictionary
|
||||
# define inflateGetDictionary z_inflateGetDictionary
|
||||
# define inflateSync z_inflateSync
|
||||
# define inflateSyncPoint z_inflateSyncPoint
|
||||
# define inflateUndermine z_inflateUndermine
|
||||
# define inflateResetKeep z_inflateResetKeep
|
||||
# define inflate_copyright z_inflate_copyright
|
||||
# define inflate_fast z_inflate_fast
|
||||
# define inflate_table z_inflate_table
|
||||
# ifndef Z_SOLO
|
||||
# define uncompress z_uncompress
|
||||
# endif
|
||||
# define zError z_zError
|
||||
# ifndef Z_SOLO
|
||||
# define zcalloc z_zcalloc
|
||||
# define zcfree z_zcfree
|
||||
# endif
|
||||
# define zlibCompileFlags z_zlibCompileFlags
|
||||
# define zlibVersion z_zlibVersion
|
||||
|
||||
/* all zlib typedefs in zlib.h and zconf.h */
|
||||
# define Byte z_Byte
|
||||
# define Bytef z_Bytef
|
||||
# define alloc_func z_alloc_func
|
||||
# define charf z_charf
|
||||
# define free_func z_free_func
|
||||
# ifndef Z_SOLO
|
||||
# define gzFile z_gzFile
|
||||
# endif
|
||||
# define gz_header z_gz_header
|
||||
# define gz_headerp z_gz_headerp
|
||||
# define in_func z_in_func
|
||||
# define intf z_intf
|
||||
# define out_func z_out_func
|
||||
# define uInt z_uInt
|
||||
# define uIntf z_uIntf
|
||||
# define uLong z_uLong
|
||||
# define uLongf z_uLongf
|
||||
# define voidp z_voidp
|
||||
# define voidpc z_voidpc
|
||||
# define voidpf z_voidpf
|
||||
|
||||
/* all zlib structs in zlib.h and zconf.h */
|
||||
# define gz_header_s z_gz_header_s
|
||||
# define internal_state z_internal_state
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__MSDOS__) && !defined(MSDOS)
|
||||
# define MSDOS
|
||||
#endif
|
||||
#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2)
|
||||
# define OS2
|
||||
#endif
|
||||
#if defined(_WINDOWS) && !defined(WINDOWS)
|
||||
# define WINDOWS
|
||||
#endif
|
||||
#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__)
|
||||
# ifndef WIN32
|
||||
# define WIN32
|
||||
# endif
|
||||
#endif
|
||||
#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32)
|
||||
# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__)
|
||||
# ifndef SYS16BIT
|
||||
# define SYS16BIT
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Compile with -DMAXSEG_64K if the alloc function cannot allocate more
|
||||
* than 64k bytes at a time (needed on systems with 16-bit int).
|
||||
*/
|
||||
#ifdef SYS16BIT
|
||||
# define MAXSEG_64K
|
||||
#endif
|
||||
#ifdef MSDOS
|
||||
# define UNALIGNED_OK
|
||||
#endif
|
||||
|
||||
#ifdef __STDC_VERSION__
|
||||
# ifndef STDC
|
||||
# define STDC
|
||||
# endif
|
||||
# if __STDC_VERSION__ >= 199901L
|
||||
# ifndef STDC99
|
||||
# define STDC99
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus))
|
||||
# define STDC
|
||||
#endif
|
||||
#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__))
|
||||
# define STDC
|
||||
#endif
|
||||
#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32))
|
||||
# define STDC
|
||||
#endif
|
||||
#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__))
|
||||
# define STDC
|
||||
#endif
|
||||
|
||||
#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */
|
||||
# define STDC
|
||||
#endif
|
||||
|
||||
#ifndef STDC
|
||||
# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
|
||||
# define const /* note: need a more gentle solution here */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(ZLIB_CONST) && !defined(z_const)
|
||||
# define z_const const
|
||||
#else
|
||||
# define z_const
|
||||
#endif
|
||||
|
||||
/* Some Mac compilers merge all .h files incorrectly: */
|
||||
#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__)
|
||||
# define NO_DUMMY_DECL
|
||||
#endif
|
||||
|
||||
/* Maximum value for memLevel in deflateInit2 */
|
||||
#ifndef MAX_MEM_LEVEL
|
||||
# ifdef MAXSEG_64K
|
||||
# define MAX_MEM_LEVEL 8
|
||||
# else
|
||||
# define MAX_MEM_LEVEL 9
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Maximum value for windowBits in deflateInit2 and inflateInit2.
|
||||
* WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
|
||||
* created by gzip. (Files created by minigzip can still be extracted by
|
||||
* gzip.)
|
||||
*/
|
||||
#ifndef MAX_WBITS
|
||||
# define MAX_WBITS 15 /* 32K LZ77 window */
|
||||
#endif
|
||||
|
||||
/* The memory requirements for deflate are (in bytes):
|
||||
(1 << (windowBits+2)) + (1 << (memLevel+9))
|
||||
that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values)
|
||||
plus a few kilobytes for small objects. For example, if you want to reduce
|
||||
the default memory requirements from 256K to 128K, compile with
|
||||
make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
|
||||
Of course this will generally degrade compression (there's no free lunch).
|
||||
|
||||
The memory requirements for inflate are (in bytes) 1 << windowBits
|
||||
that is, 32K for windowBits=15 (default value) plus a few kilobytes
|
||||
for small objects.
|
||||
*/
|
||||
|
||||
/* Type declarations */
|
||||
|
||||
#ifndef OF /* function prototypes */
|
||||
# ifdef STDC
|
||||
# define OF(args) args
|
||||
# else
|
||||
# define OF(args) ()
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef Z_ARG /* function prototypes for stdarg */
|
||||
# if defined(STDC) || defined(Z_HAVE_STDARG_H)
|
||||
# define Z_ARG(args) args
|
||||
# else
|
||||
# define Z_ARG(args) ()
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* The following definitions for FAR are needed only for MSDOS mixed
|
||||
* model programming (small or medium model with some far allocations).
|
||||
* This was tested only with MSC; for other MSDOS compilers you may have
|
||||
* to define NO_MEMCPY in zutil.h. If you don't need the mixed model,
|
||||
* just define FAR to be empty.
|
||||
*/
|
||||
#ifdef SYS16BIT
|
||||
# if defined(M_I86SM) || defined(M_I86MM)
|
||||
/* MSC small or medium model */
|
||||
# define SMALL_MEDIUM
|
||||
# ifdef _MSC_VER
|
||||
# define FAR _far
|
||||
# else
|
||||
# define FAR far
|
||||
# endif
|
||||
# endif
|
||||
# if (defined(__SMALL__) || defined(__MEDIUM__))
|
||||
/* Turbo C small or medium model */
|
||||
# define SMALL_MEDIUM
|
||||
# ifdef __BORLANDC__
|
||||
# define FAR _far
|
||||
# else
|
||||
# define FAR far
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(WINDOWS) || defined(WIN32)
|
||||
/* If building or using zlib as a DLL, define ZLIB_DLL.
|
||||
* This is not mandatory, but it offers a little performance increase.
|
||||
*/
|
||||
# ifdef ZLIB_DLL
|
||||
# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500))
|
||||
# ifdef ZLIB_INTERNAL
|
||||
# define ZEXTERN extern __declspec(dllexport)
|
||||
# else
|
||||
# define ZEXTERN extern __declspec(dllimport)
|
||||
# endif
|
||||
# endif
|
||||
# endif /* ZLIB_DLL */
|
||||
/* If building or using zlib with the WINAPI/WINAPIV calling convention,
|
||||
* define ZLIB_WINAPI.
|
||||
* Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
|
||||
*/
|
||||
# ifdef ZLIB_WINAPI
|
||||
# ifdef FAR
|
||||
# undef FAR
|
||||
# endif
|
||||
# include <windows.h>
|
||||
/* No need for _export, use ZLIB.DEF instead. */
|
||||
/* For complete Windows compatibility, use WINAPI, not __stdcall. */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef FAR
|
||||
# define FAR
|
||||
#endif
|
||||
|
||||
#if !defined(__MACTYPES__)
|
||||
typedef unsigned char Byte; /* 8 bits */
|
||||
#endif
|
||||
typedef unsigned int uInt; /* 16 bits or more */
|
||||
typedef unsigned long uLong; /* 32 bits or more */
|
||||
|
||||
#ifdef SMALL_MEDIUM
|
||||
/* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
|
||||
# define Bytef Byte FAR
|
||||
#else
|
||||
typedef Byte FAR Bytef;
|
||||
#endif
|
||||
typedef char FAR charf;
|
||||
typedef int FAR intf;
|
||||
typedef uInt FAR uIntf;
|
||||
typedef uLong FAR uLongf;
|
||||
|
||||
#ifdef STDC
|
||||
typedef void const *voidpc;
|
||||
typedef void FAR *voidpf;
|
||||
typedef void *voidp;
|
||||
#else
|
||||
typedef Byte const *voidpc;
|
||||
typedef Byte FAR *voidpf;
|
||||
typedef Byte *voidp;
|
||||
#endif
|
||||
|
||||
#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC)
|
||||
# include <limits.h>
|
||||
# if (UINT_MAX == 0xffffffffUL)
|
||||
# define Z_U4 unsigned
|
||||
# elif (ULONG_MAX == 0xffffffffUL)
|
||||
# define Z_U4 unsigned long
|
||||
# elif (USHRT_MAX == 0xffffffffUL)
|
||||
# define Z_U4 unsigned short
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef Z_U4
|
||||
typedef Z_U4 z_crc_t;
|
||||
#else
|
||||
typedef unsigned long z_crc_t;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */
|
||||
# define Z_HAVE_UNISTD_H
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STDARG_H /* may be set to #if 1 by ./configure */
|
||||
# define Z_HAVE_STDARG_H
|
||||
#endif
|
||||
|
||||
#ifdef STDC
|
||||
# ifndef Z_SOLO
|
||||
# include <sys/types.h> /* for off_t */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(STDC) || defined(Z_HAVE_STDARG_H)
|
||||
# ifndef Z_SOLO
|
||||
# include <stdarg.h> /* for va_list */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
# ifndef Z_SOLO
|
||||
# include <stddef.h> /* for wchar_t */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and
|
||||
* "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even
|
||||
* though the former does not conform to the LFS document), but considering
|
||||
* both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as
|
||||
* equivalently requesting no 64-bit operations
|
||||
*/
|
||||
#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1
|
||||
# undef _LARGEFILE64_SOURCE
|
||||
#endif
|
||||
|
||||
#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H)
|
||||
# define Z_HAVE_UNISTD_H
|
||||
#endif
|
||||
#ifndef Z_SOLO
|
||||
# if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE)
|
||||
# include <unistd.h> /* for SEEK_*, off_t, and _LFS64_LARGEFILE */
|
||||
# ifdef VMS
|
||||
# include <unixio.h> /* for off_t */
|
||||
# endif
|
||||
# ifndef z_off_t
|
||||
# define z_off_t off_t
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0
|
||||
# define Z_LFS64
|
||||
#endif
|
||||
|
||||
#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64)
|
||||
# define Z_LARGE64
|
||||
#endif
|
||||
|
||||
#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64)
|
||||
# define Z_WANT64
|
||||
#endif
|
||||
|
||||
#if !defined(SEEK_SET) && !defined(Z_SOLO)
|
||||
# define SEEK_SET 0 /* Seek from beginning of file. */
|
||||
# define SEEK_CUR 1 /* Seek from current position. */
|
||||
# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */
|
||||
#endif
|
||||
|
||||
#ifndef z_off_t
|
||||
# define z_off_t long
|
||||
#endif
|
||||
|
||||
#if !defined(_WIN32) && defined(Z_LARGE64)
|
||||
# define z_off64_t off64_t
|
||||
#else
|
||||
# if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO)
|
||||
# define z_off64_t __int64
|
||||
# else
|
||||
# define z_off64_t z_off_t
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* MVS linker does not support external names larger than 8 bytes */
|
||||
#if defined(__MVS__)
|
||||
#pragma map(deflateInit_,"DEIN")
|
||||
#pragma map(deflateInit2_,"DEIN2")
|
||||
#pragma map(deflateEnd,"DEEND")
|
||||
#pragma map(deflateBound,"DEBND")
|
||||
#pragma map(inflateInit_,"ININ")
|
||||
#pragma map(inflateInit2_,"ININ2")
|
||||
#pragma map(inflateEnd,"INEND")
|
||||
#pragma map(inflateSync,"INSY")
|
||||
#pragma map(inflateSetDictionary,"INSEDI")
|
||||
#pragma map(compressBound,"CMBND")
|
||||
#pragma map(inflate_table,"INTABL")
|
||||
#pragma map(inflate_fast,"INFA")
|
||||
#pragma map(inflate_copyright,"INCOPY")
|
||||
#endif
|
||||
|
||||
#endif /* ZCONF_H */
|
||||
Loaded 100 of 811 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user