Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dc61d682c0 | ||
|
|
d113fc40cb | ||
|
|
45a2f28cf6 | ||
|
|
45d47677ac | ||
|
|
a485080c27 | ||
|
|
cb4ecc521f | ||
|
|
0e269ddfc7 | ||
|
|
80ca43b46e | ||
|
|
8f0583958d | ||
|
|
bf3c45dbb7 | ||
|
|
2591230927 | ||
|
|
d605eaea85 | ||
|
|
4ad7b33bb2 | ||
|
|
f82c8d7fb7 | ||
|
|
91c84cd9d0 | ||
|
|
2a413071cd | ||
|
|
3fa3fbda14 | ||
|
|
cd7c9f1afc | ||
|
|
e458e868a4 | ||
|
|
6f8f43d3dc | ||
|
|
621413682e | ||
|
|
a8a5ae7a89 | ||
|
|
6502b8027f | ||
|
|
b80c492afb | ||
|
|
ca0853615b | ||
|
|
0530bd0732 | ||
|
|
294b9f302a | ||
|
|
d7c9f2595a | ||
|
|
e0b5369eb5 | ||
|
|
d874ea0348 | ||
|
|
2ec0500cd5 | ||
|
|
959aed576c | ||
|
|
6272c3e98f | ||
|
|
d80b7b95cf | ||
|
|
5ec57c5c39 | ||
|
|
a342783de4 | ||
|
|
eac0dac9b2 | ||
|
|
d6488d37ad | ||
|
|
995a28e88a | ||
|
|
6dd4058ac6 | ||
|
|
b447031e2d | ||
|
|
270ed6b9b5 | ||
|
|
17bea45cd6 | ||
|
|
8fc068e718 | ||
|
|
39968efb19 | ||
|
|
64ea9db1c1 | ||
|
|
5957a55b96 | ||
|
|
cf2c3689c5 | ||
|
|
3266e22562 | ||
|
|
491e5df430 | ||
|
|
a7b040152d | ||
|
|
0d9bf82b06 | ||
|
|
54eea79dec | ||
|
|
4aaa3ba06b | ||
|
|
606e98c192 | ||
|
|
d8964db5d9 | ||
|
|
13e6b9a56f | ||
|
|
a951e38dbb | ||
|
|
4fe3ba76e3 | ||
|
|
2e7a8dcd21 | ||
|
|
df386d7e68 | ||
|
|
f44d0192af | ||
|
|
5671b87e05 | ||
|
|
d922e6112f | ||
|
|
6fb716be07 | ||
|
|
b6d3333dfb | ||
|
|
f8a06bf94c | ||
|
|
ec2a39995b | ||
|
|
c3b1900154 | ||
|
|
c20c29250d | ||
|
|
143cc447c8 | ||
|
|
5a176e0ccc | ||
|
|
3c15805c80 | ||
|
|
221d9dba1d | ||
|
|
d87ac417f7 | ||
|
|
3e084397a8 | ||
|
|
370d5ede81 | ||
|
|
d7dbe5038d | ||
|
|
6c25431c75 | ||
|
|
37eb193e53 | ||
|
|
0eeef88ac7 | ||
|
|
47a3526178 | ||
|
|
bbb16f4c5c | ||
|
|
5115067b49 | ||
|
|
4d84e65cb5 | ||
|
|
f8f9d6eb4a | ||
|
|
6d3243b256 | ||
|
|
0cfb3e52c5 | ||
|
|
9d9640071c | ||
|
|
8fc1493759 | ||
|
|
69d82f560d | ||
|
|
ccc509ac9f | ||
|
|
ce8e91b361 | ||
|
|
5ac7408af6 | ||
|
|
421ed4ca09 | ||
|
|
bfe152dd8f | ||
|
|
d318ccaca8 | ||
|
|
a87dff7240 | ||
|
|
8873d63067 | ||
|
|
2913d7eea7 | ||
|
|
a89f3509e3 | ||
|
|
cde7d46572 | ||
|
|
d504aa3c35 | ||
|
|
8b449e590f | ||
|
|
e6f1fed96e | ||
|
|
e585de7db5 | ||
|
|
219e95117b | ||
|
|
06e8ba8c18 | ||
|
|
34639d729d | ||
|
|
abf77f72f2 | ||
|
|
4a99e7eda7 | ||
|
|
8bab844e0c | ||
|
|
fb90e2dd96 | ||
|
|
7dcbbc3c64 | ||
|
|
9bd9490c49 | ||
|
|
1b403b2ab2 | ||
|
|
162f1add75 | ||
|
|
6951ac82cd | ||
|
|
56f53c73a9 | ||
|
|
87b825b046 | ||
|
|
cd631c6eda | ||
|
|
eccaa77f0e | ||
|
|
a24de64707 | ||
|
|
7d186d2203 | ||
|
|
86b3fb3ad9 | ||
|
|
82fb0bcf88 | ||
|
|
e6bcb144d9 | ||
|
|
44d134eed0 | ||
|
|
846f2deedb | ||
|
|
deef60b231 | ||
|
|
1d2a391a90 | ||
|
|
e9bd5a52ac | ||
|
|
74343852cf | ||
|
|
fa094580cd | ||
|
|
8cadcd78f6 | ||
|
|
d0bffe825a | ||
|
|
be27447de9 | ||
|
|
a8808be29e | ||
|
|
53aa9cc2e7 | ||
|
|
b7dfce0f70 | ||
|
|
b1de3b1896 | ||
|
|
cdb751e6e1 | ||
|
|
5eddbc59d3 | ||
|
|
15496de225 | ||
|
|
7fc047615f | ||
|
|
535e702bc2 | ||
|
|
31a01bea97 | ||
|
|
5b2a86aace | ||
|
|
43d599acfd | ||
|
|
38c9836dc3 | ||
|
|
a73a51eef3 | ||
|
|
36640c1a43 | ||
|
|
3720bc149c | ||
|
|
8f09809e69 | ||
|
|
5d8a9c71a2 | ||
|
|
bbe3464085 | ||
|
|
3a88e78cec | ||
|
|
4d73ec3477 | ||
|
|
4d8e99f630 | ||
|
|
323c51e42c | ||
|
|
c13a0a2afd | ||
|
|
eecfb619b7 | ||
|
|
c14207236f | ||
|
|
8938665acb | ||
|
|
8369e8fcab | ||
|
|
a465a97c32 |
@@ -37,4 +37,7 @@ f8b20774e3f035eeddb9211a28a391b20db74456
|
||||
|
||||
# Revert a revert (scripted cutscene path)
|
||||
d73f86d26ec2dbf031c01f588ba4be11842db09c
|
||||
fe0ab0aa454f4ae12ced9502db8a01e7bca3e04c
|
||||
fe0ab0aa454f4ae12ced9502db8a01e7bca3e04c
|
||||
|
||||
# Forgot the # in the commit message
|
||||
484bbcb22aa8f28b62912abb6d8c89fb58e63889
|
||||
@@ -1,31 +1,33 @@
|
||||
name: Linux Builds
|
||||
|
||||
name: Linux Build
|
||||
on:
|
||||
push:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Linux Build
|
||||
permissions: write-all
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Pulling the source
|
||||
uses: actions/checkout@v2
|
||||
- name: Pulling the new commit
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setting up Haxe
|
||||
uses: krdlab/setup-haxe@v2
|
||||
with:
|
||||
haxe-version: 4.3.7
|
||||
- name: Restore existing build cache for faster compilation
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
# not caching the bin folder to prevent asset duplication and stuff like that
|
||||
key: cache-build-linux
|
||||
path: |
|
||||
.haxelib/
|
||||
export/release/linux/haxe/
|
||||
export/release/linux/obj/
|
||||
restore-keys: |
|
||||
cache-build-linux
|
||||
# - name: Restore existing build cache for faster compilation
|
||||
# uses: actions/cache@v4.2.3
|
||||
# with:
|
||||
# # not caching the bin folder to prevent asset duplication and stuff like that
|
||||
# key: cache-build-linux
|
||||
# path: |
|
||||
# .haxelib/
|
||||
# export/release/linux/obj/
|
||||
- run: |
|
||||
echo "HXCPP_COMPILE_CACHE=~/.hxcpp" >> $GITHUB_ENV
|
||||
- name: Installing LibVLC
|
||||
run: |
|
||||
sudo apt-get install libvlc-dev libvlccore-dev
|
||||
@@ -34,46 +36,112 @@ jobs:
|
||||
haxe -cp commandline -D analyzer-optimize --run Main setup -s
|
||||
- name: Building the game
|
||||
run: |
|
||||
haxelib run lime build linux
|
||||
haxelib run lime rebuild linux -nocolor -nocffi -release
|
||||
haxelib run lime build linux -DCOMPILE_EXPERIMENTAL
|
||||
# - name: Tar files
|
||||
# run: tar -zcvf CodenameEngine.tar.gz -C export/release/linux/bin .
|
||||
- name: Uploading artifact (executable)
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: Codename Engine (Executable Only)
|
||||
path: export/release/linux/bin/CodenameEngine
|
||||
- name: Uploading artifact (entire build)
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: Codename Engine
|
||||
path: export/release/linux/bin/
|
||||
- name: Clearing already existing cache
|
||||
uses: actions/github-script@v6
|
||||
# - name: Clearing already existing cache
|
||||
# uses: actions/github-script@v6
|
||||
# with:
|
||||
# script: |
|
||||
# const caches = await github.rest.actions.getActionsCacheList({
|
||||
# owner: context.repo.owner,
|
||||
# repo: context.repo.repo,
|
||||
# })
|
||||
# for (const cache of caches.data.actions_caches) {
|
||||
# if (cache.key == "cache-build-linux") {
|
||||
# console.log('Clearing ' + cache.key + '...')
|
||||
# await github.rest.actions.deleteActionsCacheById({
|
||||
# owner: context.repo.owner,
|
||||
# repo: context.repo.repo,
|
||||
# cache_id: cache.id,
|
||||
# })
|
||||
# console.log("Cache cleared.")
|
||||
# }
|
||||
# }
|
||||
# - name: Uploading new cache
|
||||
# uses: actions/cache@v4.2.3
|
||||
# with:
|
||||
# # caching again since for some reason it doesnt work with the first post cache shit
|
||||
# key: cache-build-linux
|
||||
# path: |
|
||||
# .haxelib/
|
||||
# export/release/linux/obj/
|
||||
|
||||
# didnt compile debug in the same job or github would have said that job wasn't completed until debug was done too (debug uploads are not essential)
|
||||
debug_build:
|
||||
name: Linux Debug Build
|
||||
permissions: write-all
|
||||
runs-on: ubuntu-24.04
|
||||
needs: build # since its low priority, it'll run after, so actions will concentrate first on normal builds
|
||||
steps:
|
||||
- name: Pulling the new commit
|
||||
uses: actions/checkout@v6
|
||||
- name: Setting up Haxe
|
||||
uses: krdlab/setup-haxe@v2
|
||||
with:
|
||||
script: |
|
||||
const caches = await github.rest.actions.getActionsCacheList({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
})
|
||||
for (const cache of caches.data.actions_caches) {
|
||||
if (cache.key == "cache-build-linux") {
|
||||
console.log('Clearing ' + cache.key + '...')
|
||||
await github.rest.actions.deleteActionsCacheById({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
cache_id: cache.id,
|
||||
})
|
||||
console.log("Cache cleared.")
|
||||
}
|
||||
}
|
||||
- name: Uploading new cache
|
||||
uses: actions/cache@v3
|
||||
haxe-version: 4.3.7
|
||||
# - name: Restore existing build cache for faster compilation
|
||||
# uses: actions/cache@v4.2.3
|
||||
# with:
|
||||
# # not caching the bin folder to prevent asset duplication and stuff like that
|
||||
# key: cache-build-linux-debug
|
||||
# path: |
|
||||
# .haxelib/
|
||||
# export/debug/linux/obj/
|
||||
- run: |
|
||||
echo "HXCPP_COMPILE_CACHE=~/.hxcpp" >> $GITHUB_ENV
|
||||
- name: Installing LibVLC
|
||||
run: |
|
||||
sudo apt-get install libvlc-dev libvlccore-dev
|
||||
- name: Installing/Updating libraries
|
||||
run: |
|
||||
haxe -cp commandline -D analyzer-optimize --run Main setup -s
|
||||
- name: Building the game
|
||||
run: |
|
||||
haxelib run lime rebuild linux -nocolor -nocffi -debug
|
||||
haxelib run lime build linux -debug -DCOMPILE_EXPERIMENTAL
|
||||
# - name: Tar files
|
||||
# run: tar -zcvf CodenameEngine.tar.gz -C export/debug/linux/bin .
|
||||
- name: Uploading artifact (entire build)
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
# caching again since for some reason it doesnt work with the first post cache shit
|
||||
key: cache-build-linux
|
||||
path: |
|
||||
.haxelib/
|
||||
export/release/linux/haxe/
|
||||
export/release/linux/obj/
|
||||
restore-keys: |
|
||||
cache-build-linux
|
||||
name: Codename Engine Debug
|
||||
path: export/debug/linux/bin/
|
||||
# - name: Clearing already existing cache
|
||||
# uses: actions/github-script@v6
|
||||
# with:
|
||||
# script: |
|
||||
# const caches = await github.rest.actions.getActionsCacheList({
|
||||
# owner: context.repo.owner,
|
||||
# repo: context.repo.repo,
|
||||
# })
|
||||
# for (const cache of caches.data.actions_caches) {
|
||||
# if (cache.key == "cache-build-linux-debug") {
|
||||
# console.log('Clearing ' + cache.key + '...')
|
||||
# await github.rest.actions.deleteActionsCacheById({
|
||||
# owner: context.repo.owner,
|
||||
# repo: context.repo.repo,
|
||||
# cache_id: cache.id,
|
||||
# })
|
||||
# console.log("Cache cleared.")
|
||||
# }
|
||||
# }
|
||||
# - name: Uploading new cache
|
||||
# uses: actions/cache@v4.2.3
|
||||
# with:
|
||||
# # caching again since for some reason it doesnt work with the first post cache shit
|
||||
# key: cache-build-linux-debug
|
||||
# path: |
|
||||
# .haxelib/
|
||||
# export/debug/linux/obj/
|
||||
|
||||
@@ -1,76 +1,141 @@
|
||||
name: Mac OS Builds
|
||||
|
||||
name: Mac OS Build
|
||||
on:
|
||||
push:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Mac OS Build
|
||||
permissions: write-all
|
||||
runs-on: macos-13
|
||||
runs-on: macos-26
|
||||
steps:
|
||||
- name: Pulling the new commit
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setting up Haxe
|
||||
uses: krdlab/setup-haxe@v2
|
||||
with:
|
||||
haxe-version: 4.3.7
|
||||
- name: Restore existing build cache for faster compilation
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
# not caching the bin folder to prevent asset duplication and stuff like that
|
||||
key: cache-build-mac
|
||||
path: |
|
||||
.haxelib/
|
||||
export/release/macos/haxe/
|
||||
export/release/macos/obj/
|
||||
restore-keys: |
|
||||
cache-build-mac
|
||||
# - name: Restore existing build cache for faster compilation
|
||||
# uses: actions/cache@v4.2.3
|
||||
# with:
|
||||
# # not caching the bin folder to prevent asset duplication and stuff like that
|
||||
# key: cache-build-mac
|
||||
# path: |
|
||||
# .haxelib/
|
||||
# export/release/macos/obj/
|
||||
- run: |
|
||||
echo "HXCPP_COMPILE_CACHE=~/.hxcpp" >> $GITHUB_ENV
|
||||
- name: Installing/Updating libraries
|
||||
run: |
|
||||
haxe -cp commandline -D analyzer-optimize --run Main setup -s
|
||||
- name: Building the game
|
||||
run: |
|
||||
haxelib run lime build mac
|
||||
haxelib run lime rebuild mac -nocolor -nocffi -release
|
||||
haxelib run lime build mac -DCOMPILE_EXPERIMENTAL
|
||||
- name: Tar files
|
||||
run: tar -zcvf CodenameEngine.tar.gz -C export/release/macos/bin .
|
||||
- name: Uploading artifact (executable)
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: Codename Engine (Executable Only)
|
||||
path: export/release/macos/bin/CodenameEngine.app/Contents/MacOS/CodenameEngine
|
||||
- name: Uploading artifact (entire build)
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: Codename Engine
|
||||
path: CodenameEngine.tar.gz
|
||||
- name: Clearing already existing cache
|
||||
uses: actions/github-script@v6
|
||||
# - name: Clearing already existing cache
|
||||
# uses: actions/github-script@v6
|
||||
# with:
|
||||
# script: |
|
||||
# const caches = await github.rest.actions.getActionsCacheList({
|
||||
# owner: context.repo.owner,
|
||||
# repo: context.repo.repo,
|
||||
# })
|
||||
# for (const cache of caches.data.actions_caches) {
|
||||
# if (cache.key == "cache-build-mac") {
|
||||
# console.log('Clearing ' + cache.key + '...')
|
||||
# await github.rest.actions.deleteActionsCacheById({
|
||||
# owner: context.repo.owner,
|
||||
# repo: context.repo.repo,
|
||||
# cache_id: cache.id,
|
||||
# })
|
||||
# console.log("Cache cleared.")
|
||||
# }
|
||||
# }
|
||||
# - name: Uploading new cache
|
||||
# uses: actions/cache@v4.2.3
|
||||
# with:
|
||||
# # caching again since for some reason it doesnt work with the first post cache shit
|
||||
# key: cache-build-mac
|
||||
# path: |
|
||||
# .haxelib/
|
||||
# export/release/macos/obj/
|
||||
|
||||
# didnt compile debug in the same job or github would have said that job wasn't completed until debug was done too (debug uploads are not essential)
|
||||
debug_build:
|
||||
name: Mac OS Debug Build
|
||||
permissions: write-all
|
||||
runs-on: macos-26
|
||||
needs: build # since its low priority, it'll run after, so actions will concentrate first on normal builds
|
||||
steps:
|
||||
- name: Pulling the new commit
|
||||
uses: actions/checkout@v6
|
||||
- name: Setting up Haxe
|
||||
uses: krdlab/setup-haxe@v2
|
||||
with:
|
||||
script: |
|
||||
const caches = await github.rest.actions.getActionsCacheList({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
})
|
||||
for (const cache of caches.data.actions_caches) {
|
||||
if (cache.key == "cache-build-mac") {
|
||||
console.log('Clearing ' + cache.key + '...')
|
||||
await github.rest.actions.deleteActionsCacheById({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
cache_id: cache.id,
|
||||
})
|
||||
console.log("Cache cleared.")
|
||||
}
|
||||
}
|
||||
- name: Uploading new cache
|
||||
uses: actions/cache@v3
|
||||
haxe-version: 4.3.7
|
||||
# - name: Restore existing build cache for faster compilation
|
||||
# uses: actions/cache@v4.2.3
|
||||
# with:
|
||||
# # not caching the bin folder to prevent asset duplication and stuff like that
|
||||
# key: cache-build-mac-debug
|
||||
# path: |
|
||||
# .haxelib/
|
||||
# export/debug/macos/obj/
|
||||
- run: |
|
||||
echo "HXCPP_COMPILE_CACHE=~/.hxcpp" >> $GITHUB_ENV
|
||||
- name: Installing/Updating libraries
|
||||
run: |
|
||||
haxe -cp commandline -D analyzer-optimize --run Main setup -s
|
||||
- name: Building the game
|
||||
run: |
|
||||
haxelib run lime rebuild mac -nocolor -nocffi -debug
|
||||
haxelib run lime build mac -debug -DCOMPILE_EXPERIMENTAL
|
||||
- name: Tar files
|
||||
run: tar -zcvf CodenameEngine.tar.gz -C export/debug/macos/bin .
|
||||
- name: Uploading artifact (entire build)
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
# caching again since for some reason it doesnt work with the first post cache shit
|
||||
key: cache-build-mac
|
||||
path: |
|
||||
.haxelib/
|
||||
export/release/macos/haxe/
|
||||
export/release/macos/obj/
|
||||
restore-keys: |
|
||||
cache-build-mac
|
||||
name: Codename Engine Debug
|
||||
path: CodenameEngine.tar.gz
|
||||
# - name: Clearing already existing cache
|
||||
# uses: actions/github-script@v6
|
||||
# with:
|
||||
# script: |
|
||||
# const caches = await github.rest.actions.getActionsCacheList({
|
||||
# owner: context.repo.owner,
|
||||
# repo: context.repo.repo,
|
||||
# })
|
||||
# for (const cache of caches.data.actions_caches) {
|
||||
# if (cache.key == "cache-build-mac-debug") {
|
||||
# console.log('Clearing ' + cache.key + '...')
|
||||
# await github.rest.actions.deleteActionsCacheById({
|
||||
# owner: context.repo.owner,
|
||||
# repo: context.repo.repo,
|
||||
# cache_id: cache.id,
|
||||
# })
|
||||
# console.log("Cache cleared.")
|
||||
# }
|
||||
# }
|
||||
# - name: Uploading new cache
|
||||
# uses: actions/cache@v4.2.3
|
||||
# with:
|
||||
# # caching again since for some reason it doesnt work with the first post cache shit
|
||||
# key: cache-build-mac-debug
|
||||
# path: |
|
||||
# .haxelib/
|
||||
# export/debug/macos/obj/
|
||||
|
||||
@@ -21,10 +21,12 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Download Windows Full Build
|
||||
uses: dawidd6/action-download-artifact@v6
|
||||
uses: dawidd6/action-download-artifact@v8
|
||||
with:
|
||||
workflow: windows.yml
|
||||
name: Codename Engine
|
||||
@@ -32,7 +34,7 @@ jobs:
|
||||
allow_forks: false
|
||||
|
||||
- name: Download Windows Executable
|
||||
uses: dawidd6/action-download-artifact@v6
|
||||
uses: dawidd6/action-download-artifact@v8
|
||||
with:
|
||||
workflow: windows.yml
|
||||
name: Codename Engine (Executable Only)
|
||||
@@ -40,7 +42,7 @@ jobs:
|
||||
allow_forks: false
|
||||
|
||||
- name: Download Mac OS Full Build
|
||||
uses: dawidd6/action-download-artifact@v6
|
||||
uses: dawidd6/action-download-artifact@v8
|
||||
with:
|
||||
workflow: macos.yml
|
||||
name: Codename Engine
|
||||
@@ -48,7 +50,7 @@ jobs:
|
||||
allow_forks: false
|
||||
|
||||
- name: Download Mac OS Executable
|
||||
uses: dawidd6/action-download-artifact@v6
|
||||
uses: dawidd6/action-download-artifact@v8
|
||||
with:
|
||||
workflow: macos.yml
|
||||
name: Codename Engine (Executable Only)
|
||||
@@ -56,7 +58,7 @@ jobs:
|
||||
allow_forks: false
|
||||
|
||||
- name: Download Linux Full Build
|
||||
uses: dawidd6/action-download-artifact@v6
|
||||
uses: dawidd6/action-download-artifact@v8
|
||||
with:
|
||||
workflow: linux.yml
|
||||
name: Codename Engine
|
||||
@@ -64,7 +66,7 @@ jobs:
|
||||
allow_forks: false
|
||||
|
||||
- name: Download Linux Executable
|
||||
uses: dawidd6/action-download-artifact@v6
|
||||
uses: dawidd6/action-download-artifact@v8
|
||||
with:
|
||||
workflow: linux.yml
|
||||
name: Codename Engine (Executable Only)
|
||||
@@ -184,7 +186,7 @@ jobs:
|
||||
name: Release ${{ github.event.inputs.tag_name }}
|
||||
draft: true
|
||||
prerelease: ${{ github.event.inputs.prerelease }}
|
||||
body: ${{ steps.build_body.outputs.body }}
|
||||
body: ${{ steps.build_body.outputs.body }}
|
||||
generate_release_notes: true
|
||||
files: |
|
||||
renamed/Codename Engine-Windows.zip
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
name: Windows Builds
|
||||
|
||||
name: Windows Build
|
||||
on:
|
||||
push:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Windows Build
|
||||
@@ -10,65 +11,130 @@ jobs:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: Pulling the new commit
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Setting up Haxe
|
||||
uses: krdlab/setup-haxe@v2
|
||||
with:
|
||||
haxe-version: 4.3.7
|
||||
- name: Restore existing build cache for faster compilation
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
# not caching the bin folder to prevent asset duplication and stuff like that
|
||||
key: cache-build-windows
|
||||
path: |
|
||||
.haxelib/
|
||||
export/release/windows/haxe/
|
||||
export/release/windows/obj/
|
||||
restore-keys: |
|
||||
cache-build-windows
|
||||
# - name: Restore existing build cache for faster compilation
|
||||
# uses: actions/cache@v4.2.3
|
||||
# with:
|
||||
# # not caching the bin folder to prevent asset duplication and stuff like that
|
||||
# key: cache-build-windows
|
||||
# path: |
|
||||
# .haxelib/
|
||||
# export/release/windows/obj/
|
||||
- run: |
|
||||
echo "HXCPP_COMPILE_CACHE=~/.hxcpp" >> $GITHUB_ENV
|
||||
- name: Installing/Updating libraries
|
||||
run: |
|
||||
haxe -cp commandline -D analyzer-optimize --run Main setup -s --no-vscheck
|
||||
- name: Building the game
|
||||
run: |
|
||||
haxelib run lime build windows
|
||||
haxelib run lime rebuild windows -nocolor -nocffi -release
|
||||
haxelib run lime build windows -DCOMPILE_EXPERIMENTAL
|
||||
- name: Uploading artifact (executable)
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: Codename Engine (Executable Only)
|
||||
path: export/release/windows/bin/CodenameEngine.exe
|
||||
path: |
|
||||
export/release/windows/bin/CodenameEngine.exe
|
||||
export/release/windows/bin/lime.ndll
|
||||
- name: Uploading artifact (entire build)
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: Codename Engine
|
||||
path: export/release/windows/bin
|
||||
- name: Clearing already existing cache
|
||||
uses: actions/github-script@v6
|
||||
# - name: Clearing already existing cache
|
||||
# uses: actions/github-script@v6
|
||||
# with:
|
||||
# script: |
|
||||
# const caches = await github.rest.actions.getActionsCacheList({
|
||||
# owner: context.repo.owner,
|
||||
# repo: context.repo.repo,
|
||||
# })
|
||||
# for (const cache of caches.data.actions_caches) {
|
||||
# if (cache.key == "cache-build-windows") {
|
||||
# console.log('Clearing ' + cache.key + '...')
|
||||
# await github.rest.actions.deleteActionsCacheById({
|
||||
# owner: context.repo.owner,
|
||||
# repo: context.repo.repo,
|
||||
# cache_id: cache.id,
|
||||
# })
|
||||
# console.log("Cache cleared.")
|
||||
# }
|
||||
# }
|
||||
# - name: Uploading new cache
|
||||
# uses: actions/cache@v4.2.3
|
||||
# with:
|
||||
# # caching again since for some reason it doesnt work with the first post cache shit
|
||||
# key: cache-build-windows
|
||||
# path: |
|
||||
# .haxelib/
|
||||
# export/release/windows/obj/
|
||||
|
||||
# didnt compile debug in the same job or github would have said that job wasn't completed until debug was done too (debug uploads are not essential)
|
||||
debug_build:
|
||||
name: Windows Debug Build
|
||||
permissions: write-all
|
||||
runs-on: windows-latest
|
||||
needs: build # since its low priority, it'll run after, so actions will concentrate first on normal builds
|
||||
steps:
|
||||
- name: Pulling the new commit
|
||||
uses: actions/checkout@v6
|
||||
- name: Setting up Haxe
|
||||
uses: krdlab/setup-haxe@v2
|
||||
with:
|
||||
script: |
|
||||
const caches = await github.rest.actions.getActionsCacheList({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
})
|
||||
for (const cache of caches.data.actions_caches) {
|
||||
if (cache.key == "cache-build-windows") {
|
||||
console.log('Clearing ' + cache.key + '...')
|
||||
await github.rest.actions.deleteActionsCacheById({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
cache_id: cache.id,
|
||||
})
|
||||
console.log("Cache cleared.")
|
||||
}
|
||||
}
|
||||
- name: Uploading new cache
|
||||
uses: actions/cache@v3
|
||||
haxe-version: 4.3.7
|
||||
# - name: Restore existing build cache for faster compilation
|
||||
# uses: actions/cache@v4.2.3
|
||||
# with:
|
||||
# # not caching the bin folder to prevent asset duplication and stuff like that
|
||||
# key: cache-build-windows-debug
|
||||
# path: |
|
||||
# .haxelib/
|
||||
# export/debug/windows/haxe/
|
||||
# export/debug/windows/obj/
|
||||
- run: |
|
||||
echo "HXCPP_COMPILE_CACHE=~/.hxcpp" >> $GITHUB_ENV
|
||||
- name: Installing/Updating libraries
|
||||
run: |
|
||||
haxe -cp commandline -D analyzer-optimize --run Main setup -s --no-vscheck
|
||||
- name: Building the game
|
||||
run: |
|
||||
haxelib run lime rebuild windows -nocolor -nocffi -debug
|
||||
haxelib run lime build windows -debug
|
||||
- name: Uploading artifact (entire build)
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
# caching again since for some reason it doesnt work with the first post cache shit
|
||||
key: cache-build-windows
|
||||
path: |
|
||||
.haxelib/
|
||||
export/release/windows/haxe/
|
||||
export/release/windows/obj/
|
||||
restore-keys: |
|
||||
cache-build-windows
|
||||
name: Codename Engine Debug
|
||||
path: export/debug/windows/bin
|
||||
# - name: Clearing already existing cache
|
||||
# uses: actions/github-script@v6
|
||||
# with:
|
||||
# script: |
|
||||
# const caches = await github.rest.actions.getActionsCacheList({
|
||||
# owner: context.repo.owner,
|
||||
# repo: context.repo.repo,
|
||||
# })
|
||||
# for (const cache of caches.data.actions_caches) {
|
||||
# if (cache.key == "cache-build-windows-debug") {
|
||||
# console.log('Clearing ' + cache.key + '...')
|
||||
# await github.rest.actions.deleteActionsCacheById({
|
||||
# owner: context.repo.owner,
|
||||
# repo: context.repo.repo,
|
||||
# cache_id: cache.id,
|
||||
# })
|
||||
# console.log("Cache cleared.")
|
||||
# }
|
||||
# }
|
||||
# - name: Uploading new cache
|
||||
# uses: actions/cache@v4.2.3
|
||||
# with:
|
||||
# # caching again since for some reason it doesnt work with the first post cache shit
|
||||
# key: cache-build-windows-debug
|
||||
# path: |
|
||||
# .haxelib/
|
||||
# export/debug/windows/obj/
|
||||
|
||||
@@ -73,7 +73,7 @@ _**QOL = Quality of Life**_
|
||||
- If you need to rearrange the weeks in-game, you can use the `data/weeks/weeks.txt` file.
|
||||
- Editors for Charts and Characters (Stage coming soon)
|
||||
- Undos/Redos supported
|
||||
- Warning on closing unsaved work
|
||||
- Warning on closing unsaved work.
|
||||
- Clean UI (for ocd freaks)
|
||||
- Mature Chart editor (Character editor rework soon)
|
||||
- Features not found in other editors!
|
||||
|
||||
@@ -47,7 +47,7 @@ The engine uses [HaxeFlixel](https://haxeflixel.com/) and it mainly features:
|
||||
---
|
||||
|
||||
> [!NOTE]
|
||||
> Codename Engine as for now supports **Windows x64**, **Mac OS x64** and **Linux x64**.<br>
|
||||
> Codename Engine as for now supports **Windows x64**, **Mac OS Universal** and **Linux x64**.<br>
|
||||
> More platforms will soon come, stay tuned!<br>
|
||||
> - [ ] **Web (HTML5) Support**
|
||||
> - [ ] **Mobile Support**
|
||||
@@ -68,7 +68,7 @@ The engine uses [HaxeFlixel](https://haxeflixel.com/) and it mainly features:
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><h2>How to setup and build</h2></summary>
|
||||
<summary><h2>How to setup and build the engine and its documentation</h2></summary>
|
||||
|
||||
Check out our guide [HERE](building/README.md)
|
||||
</details>
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
## DEV (PRIVATE) REPO INSTRUCTIONS TO SYNC UP WITH IT INSTEAD OF SYNCING WITH THE PUBLIC ONE
|
||||
- Open a Command Prompt window in the public codename repo folder
|
||||
- Type those commands:
|
||||
- `git remote add dev https://www.github.com/YoshiCrafter29/CodenameEngine-Dev`
|
||||
- `git branch --set-upstream-to dev/main`
|
||||
- GitHub desktop should be synchronized with the dev repo now. If you're unsure,
|
||||
- Repo name should still say "CodenameEngine"
|
||||
- Current branch should still say "main"
|
||||
- "Fetch" button should say "Fetch dev"
|
||||
- You shouldn't have any commit to push.
|
||||
@@ -1,8 +0,0 @@
|
||||
@ECHO OFF
|
||||
cd ..
|
||||
echo Building Game...
|
||||
lime build windows --haxeflag="-xml docs/doc.xml" -D doc-gen -D DOCUMENTATION --no-output
|
||||
echo art
|
||||
|
||||
echo Generated the api xml file at docs/doc.xml
|
||||
echo Please put this in codename-website/api-generator/api/doc.xml
|
||||
@@ -2,13 +2,6 @@
|
||||
<character x="115" y="325" sprite="gf-christmas" icon="gf" color="#A5004D">
|
||||
<anim name="danceLeft" anim="GF Dancing Beat" x="0" y="-9" fps="24" loop="false" indices="0..14"/>
|
||||
<anim name="danceRight" anim="GF Dancing Beat" x="0" y="-9" fps="24" loop="false" indices="15..30"/>
|
||||
<anim name="singUP" anim="GF Up Note" x="0" y="-9" fps="24" loop="false"/>
|
||||
<anim name="singDOWN" anim="GF Down Note" x="0" y="-9" fps="24" loop="false"/>
|
||||
<anim name="singLEFT" anim="GF left note" x="0" y="-9" fps="24" loop="false"/>
|
||||
<anim name="singRIGHT" anim="GF Right Note" x="0" y="-9" fps="24" loop="false"/>
|
||||
<anim name="scared" anim="GF FEAR" x="0" y="-9" fps="24" loop="true"/>
|
||||
<anim name="hairBlow" anim="GF Dancing Beat Hair blowing" x="0" y="-9" fps="24" loop="false" indices="0..3"/>
|
||||
<anim name="hairFall" anim="GF Dancing Beat Hair Landing" x="0" y="-9" fps="24" loop="false" indices="0..11"/>
|
||||
<anim name="cheer" anim="GF Cheer" x="0" y="-9" fps="24" loop="false"/>
|
||||
<anim name="sad" anim="gf sad" x="-51" y="306" fps="24" loop="true" indices="0..12"/>
|
||||
</character>
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
<!DOCTYPE codename-engine-character>
|
||||
<character x="100" y="275" sprite="gf" icon="gf" color="#A5004D">
|
||||
<anim name="cheer" anim="GF Cheer" x="0" y="0" fps="24" loop="false"/>
|
||||
<anim name="singUP" anim="GF Up Note" x="0" y="0" fps="24" loop="false"/>
|
||||
<anim name="singLEFT" anim="GF left note" x="0" y="0" fps="24" loop="false"/>
|
||||
<anim name="singRIGHT" anim="GF Right Note" x="0" y="0" fps="24" loop="false"/>
|
||||
<anim name="singDOWN" anim="GF Down Note" x="0" y="0" fps="24" loop="false"/>
|
||||
<anim name="danceLeft" anim="GF Dancing Beat" x="0" y="0" fps="24" loop="false" indices="0..14"/>
|
||||
<anim name="danceRight" anim="GF Dancing Beat" x="0" y="0" fps="24" loop="false" indices="15..30"/>
|
||||
<anim name="hairBlow" anim="GF Dancing Beat Hair blowing" x="0" y="0" fps="24" loop="true" indices="0,1,2,3"/>
|
||||
<anim name="hairFall" anim="GF Dancing Beat Hair Landing" x="0" y="0" fps="24" loop="false" indices="0..11"/>
|
||||
<anim name="scared" anim="GF FEAR" x="0" y="0" fps="24" loop="true"/>
|
||||
<anim name="sad" anim="gf sad" x="0" y="0" fps="24" loop="true" indices="0..12"/>
|
||||
<character x="100" y="275" color="#A5004D">
|
||||
<anim name="cheer" anim="GF Cheer"/>
|
||||
<anim name="singUP" anim="GF Up Note"/>
|
||||
<anim name="singLEFT" anim="GF left note"/>
|
||||
<anim name="singRIGHT" anim="GF Right Note"/>
|
||||
<anim name="singDOWN" anim="GF Down Note"/>
|
||||
<anim name="danceLeft" anim="GF Dancing Beat" indices="0..14"/>
|
||||
<anim name="danceRight" anim="GF Dancing Beat" indices="15..30"/>
|
||||
<anim name="hairBlow" anim="GF Dancing Beat Hair blowing" loop="true" indices="0..3"/>
|
||||
<anim name="hairFall" anim="GF Dancing Beat Hair Landing" indices="0..11"/>
|
||||
<anim name="scared" anim="GF FEAR " loop="true"/>
|
||||
<anim name="sad" anim="gf sad" x="-51" y="315" loop="true" indices="0..12"/>
|
||||
</character>
|
||||
|
||||
@@ -75,7 +75,7 @@ function onCountdown(event) {
|
||||
};
|
||||
}
|
||||
|
||||
function onPlayerHit(event:NoteHitEvent) {
|
||||
function onRatingsShown(event:RatingsShowEvent) {
|
||||
if (!enablePixelUI) return;
|
||||
event.ratingPrefix = "stages/school/ui/";
|
||||
event.ratingScale = daPixelZoom * 0.7;
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<sprite name="fgSnow" x="-600" y="680" sprite="fgSnow"/>
|
||||
|
||||
|
||||
<girlfriend x="540" y="110"/>
|
||||
<girlfriend x="440" y="110"/>
|
||||
<dad/>
|
||||
<boyfriend x="1030" camyoffset="-150" camxoffset="-150"/>
|
||||
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
{"ATLAS": {"SPRITES":[
|
||||
{"SPRITE" : {"name": "0000","x":1636,"y":275,"w":183,"h":115,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0001","x":215,"y":360,"w":84,"h":140,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0002","x":419,"y":358,"w":251,"h":121,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0003","x":1636,"y":394,"w":120,"h":65,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0004","x":4,"y":360,"w":108,"h":126,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0005","x":674,"y":358,"w":102,"h":147,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0006","x":116,"y":360,"w":95,"h":130,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0007","x":2038,"y":4,"w":1,"h":4,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0008","x":4,"y":4,"w":411,"h":352,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0009","x":419,"y":4,"w":398,"h":350,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0010","x":1303,"y":275,"w":329,"h":162,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0011","x":303,"y":360,"w":90,"h":103,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0012","x":1823,"y":4,"w":211,"h":236,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0013","x":1823,"y":244,"w":208,"h":235,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0014","x":821,"y":258,"w":478,"h":262,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0015","x":821,"y":4,"w":521,"h":250,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0016","x":1346,"y":4,"w":473,"h":267,"rotated": false}}
|
||||
]},
|
||||
"meta": {
|
||||
"app": "Adobe Animate",
|
||||
"version": "22.0.5.191",
|
||||
"image": "spritemap1.png",
|
||||
"format": "RGBA8888",
|
||||
"size": {"w":2043,"h":524},
|
||||
"resolution": "1"
|
||||
}
|
||||
{"ATLAS":{"SPRITES":[
|
||||
{"SPRITE":{"name":"0","x":1662,"y":282,"w":194,"h":117,"rotated":false}},
|
||||
{"SPRITE":{"name":"1","x":1790,"y":417,"w":92,"h":136,"rotated":false}},
|
||||
{"SPRITE":{"name":"2","x":1193,"y":539,"w":259,"h":123,"rotated":false}},
|
||||
{"SPRITE":{"name":"3","x":483,"y":553,"w":125,"h":68,"rotated":false}},
|
||||
{"SPRITE":{"name":"4","x":1662,"y":417,"w":110,"h":127,"rotated":false}},
|
||||
{"SPRITE":{"name":"5","x":1886,"y":0,"w":105,"h":149,"rotated":false}},
|
||||
{"SPRITE":{"name":"6","x":1886,"y":167,"w":97,"h":130,"rotated":false}},
|
||||
{"SPRITE":{"name":"7","x":1398,"y":0,"w":470,"h":264,"rotated":false}},
|
||||
{"SPRITE":{"name":"8","x":867,"y":0,"w":513,"h":254,"rotated":false}},
|
||||
{"SPRITE":{"name":"9","x":0,"y":372,"w":465,"h":270,"rotated":false}},
|
||||
{"SPRITE":{"name":"10","x":1900,"y":315,"w":101,"h":118,"rotated":false}},
|
||||
{"SPRITE":{"name":"11","x":867,"y":272,"w":308,"h":367,"rotated":false}},
|
||||
{"SPRITE":{"name":"12","x":483,"y":371,"w":338,"h":164,"rotated":false}},
|
||||
{"SPRITE":{"name":"13","x":0,"y":0,"w":422,"h":354,"rotated":false}},
|
||||
{"SPRITE":{"name":"14","x":440,"y":0,"w":409,"h":353,"rotated":false}},
|
||||
{"SPRITE":{"name":"15","x":1900,"y":451,"w":92,"h":103,"rotated":false}},
|
||||
{"SPRITE":{"name":"16","x":1193,"y":282,"w":218,"h":239,"rotated":false}},
|
||||
{"SPRITE":{"name":"17","x":1429,"y":282,"w":215,"h":237,"rotated":false}}]},
|
||||
"meta":{
|
||||
"app":"Adobe Animate (Better TA Extension)",
|
||||
"version":"24.0.2.12",
|
||||
"image":"spritemap1.png",
|
||||
"format":"RGBA8888",
|
||||
"size":{"w":2031,"h":662},
|
||||
"resolution":"1"
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 74 KiB After Width: | Height: | Size: 134 KiB |
@@ -1,58 +1,40 @@
|
||||
{"ATLAS": {"SPRITES":[
|
||||
{"SPRITE" : {"name": "0000","x":994,"y":1029,"w":187,"h":118,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0001","x":1953,"y":524,"w":84,"h":140,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0002","x":471,"y":430,"w":258,"h":137,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0003","x":1300,"y":641,"w":122,"h":66,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0004","x":1825,"y":1078,"w":108,"h":126,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0005","x":360,"y":695,"w":103,"h":149,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0006","x":1945,"y":867,"w":95,"h":130,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0007","x":2034,"y":4,"w":1,"h":4,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0008","x":943,"y":650,"w":309,"h":375,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0009","x":4,"y":4,"w":778,"h":422,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0010","x":786,"y":4,"w":761,"h":393,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0011","x":1551,"y":4,"w":411,"h":352,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0012","x":1551,"y":360,"w":398,"h":350,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0013","x":4,"y":1028,"w":329,"h":162,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0014","x":1945,"y":1001,"w":90,"h":103,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0015","x":1300,"y":401,"w":211,"h":236,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0016","x":782,"y":1029,"w":208,"h":235,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0017","x":782,"y":910,"w":117,"h":83,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0018","x":994,"y":1151,"w":117,"h":83,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0019","x":1937,"y":1108,"w":103,"h":83,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0020","x":1115,"y":1151,"w":117,"h":83,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0021","x":1654,"y":714,"w":287,"h":360,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0022","x":471,"y":571,"w":179,"h":67,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0023","x":654,"y":571,"w":118,"h":75,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0024","x":1966,"y":223,"w":55,"h":112,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0025","x":1966,"y":4,"w":64,"h":106,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0026","x":1185,"y":1029,"w":67,"h":70,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0027","x":337,"y":1182,"w":122,"h":62,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0028","x":1647,"y":1078,"w":174,"h":97,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0029","x":360,"y":870,"w":82,"h":14,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0030","x":1647,"y":1179,"w":128,"h":61,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0031","x":463,"y":1182,"w":124,"h":58,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0032","x":1966,"y":114,"w":59,"h":105,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0033","x":1953,"y":360,"w":87,"h":160,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0034","x":1945,"y":714,"w":92,"h":149,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0035","x":1426,"y":641,"w":104,"h":42,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0036","x":1953,"y":692,"w":73,"h":18,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0037","x":1426,"y":687,"w":72,"h":19,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0038","x":360,"y":848,"w":72,"h":18,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0039","x":1953,"y":668,"w":73,"h":20,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0040","x":471,"y":650,"w":468,"h":256,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0041","x":786,"y":401,"w":510,"h":245,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0042","x":4,"y":430,"w":463,"h":261,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0043","x":360,"y":910,"w":418,"h":268,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0044","x":1256,"y":1008,"w":387,"h":271,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0045","x":1256,"y":714,"w":394,"h":290,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0046","x":4,"y":695,"w":352,"h":329,"rotated": false}}
|
||||
]},
|
||||
"meta": {
|
||||
"app": "Adobe Animate",
|
||||
"version": "22.0.5.191",
|
||||
"image": "spritemap1.png",
|
||||
"format": "RGBA8888",
|
||||
"size": {"w":2044,"h":1283},
|
||||
"resolution": "1"
|
||||
}
|
||||
{"ATLAS":{"SPRITES":[
|
||||
{"SPRITE":{"name":"0","x":349,"y":867,"w":254,"h":136,"rotated":false}},
|
||||
{"SPRITE":{"name":"1","x":1648,"y":328,"w":287,"h":363,"rotated":false}},
|
||||
{"SPRITE":{"name":"2","x":1571,"y":709,"w":185,"h":117,"rotated":false}},
|
||||
{"SPRITE":{"name":"3","x":1686,"y":855,"w":86,"h":136,"rotated":false}},
|
||||
{"SPRITE":{"name":"4","x":349,"y":1021,"w":122,"h":68,"rotated":false}},
|
||||
{"SPRITE":{"name":"5","x":1774,"y":709,"w":110,"h":128,"rotated":false}},
|
||||
{"SPRITE":{"name":"6","x":621,"y":867,"w":105,"h":148,"rotated":false}},
|
||||
{"SPRITE":{"name":"7","x":1571,"y":844,"w":97,"h":131,"rotated":false}},
|
||||
{"SPRITE":{"name":"8","x":800,"y":1,"w":543,"h":308,"rotated":false}},
|
||||
{"SPRITE":{"name":"9","x":800,"y":1,"w":543,"h":308,"rotated":false}},
|
||||
{"SPRITE":{"name":"10","x":800,"y":1,"w":543,"h":308,"rotated":false}},
|
||||
{"SPRITE":{"name":"11","x":800,"y":1,"w":543,"h":308,"rotated":false}},
|
||||
{"SPRITE":{"name":"12","x":800,"y":1,"w":543,"h":308,"rotated":false}},
|
||||
{"SPRITE":{"name":"13","x":800,"y":1,"w":543,"h":308,"rotated":false}},
|
||||
{"SPRITE":{"name":"14","x":800,"y":1,"w":543,"h":308,"rotated":false}},
|
||||
{"SPRITE":{"name":"15","x":800,"y":1,"w":543,"h":308,"rotated":false}},
|
||||
{"SPRITE":{"name":"16","x":1363,"y":1,"w":543,"h":308,"rotated":false}},
|
||||
{"SPRITE":{"name":"17","x":1,"y":444,"w":771,"h":404,"rotated":false}},
|
||||
{"SPRITE":{"name":"18","x":791,"y":700,"w":302,"h":369,"rotated":false}},
|
||||
{"SPRITE":{"name":"19","x":1111,"y":957,"w":120,"h":86,"rotated":false}},
|
||||
{"SPRITE":{"name":"20","x":1790,"y":855,"w":120,"h":86,"rotated":false}},
|
||||
{"SPRITE":{"name":"21","x":1790,"y":959,"w":106,"h":86,"rotated":false}},
|
||||
{"SPRITE":{"name":"22","x":1249,"y":957,"w":120,"h":86,"rotated":false}},
|
||||
{"SPRITE":{"name":"23","x":0,"y":0,"w":781,"h":425,"rotated":false}},
|
||||
{"SPRITE":{"name":"24","x":0,"y":867,"w":331,"h":164,"rotated":false}},
|
||||
{"SPRITE":{"name":"25","x":799,"y":328,"w":413,"h":354,"rotated":false}},
|
||||
{"SPRITE":{"name":"26","x":1230,"y":328,"w":400,"h":353,"rotated":false}},
|
||||
{"SPRITE":{"name":"27","x":1387,"y":954,"w":90,"h":103,"rotated":false}},
|
||||
{"SPRITE":{"name":"28","x":1111,"y":700,"w":213,"h":239,"rotated":false}},
|
||||
{"SPRITE":{"name":"29","x":1342,"y":699,"w":211,"h":237,"rotated":false}}]},
|
||||
"meta":{
|
||||
"app":"Adobe Animate (Better TA Extension)",
|
||||
"version":"24.0.2.12",
|
||||
"image":"spritemap1.png",
|
||||
"format":"RGBA8888",
|
||||
"size":{"w":1965,"h":1089},
|
||||
"resolution":"1"
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 228 KiB After Width: | Height: | Size: 453 KiB |
@@ -1,57 +1,55 @@
|
||||
{"ATLAS": {"SPRITES":[
|
||||
{"SPRITE" : {"name": "0000","x":1623,"y":602,"w":287,"h":360,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0001","x":1310,"y":269,"w":309,"h":375,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0002","x":4,"y":4,"w":420,"h":359,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0003","x":428,"y":4,"w":406,"h":358,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0004","x":4,"y":639,"w":336,"h":165,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0005","x":125,"y":808,"w":90,"h":103,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0006","x":1819,"y":4,"w":215,"h":242,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0007","x":1217,"y":648,"w":213,"h":240,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0008","x":606,"y":660,"w":191,"h":120,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0009","x":606,"y":784,"w":90,"h":151,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0010","x":344,"y":660,"w":258,"h":124,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0011","x":448,"y":859,"w":122,"h":67,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0012","x":1914,"y":755,"w":108,"h":126,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0013","x":1914,"y":602,"w":103,"h":149,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0014","x":700,"y":784,"w":95,"h":130,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0015","x":2038,"y":4,"w":1,"h":4,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0016","x":838,"y":253,"w":468,"h":256,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0017","x":838,"y":4,"w":510,"h":245,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0018","x":1352,"y":4,"w":463,"h":261,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0019","x":4,"y":367,"w":418,"h":268,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0020","x":826,"y":513,"w":387,"h":271,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0021","x":428,"y":366,"w":394,"h":290,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0022","x":1623,"y":269,"w":352,"h":329,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0023","x":1143,"y":788,"w":67,"h":70,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0024","x":1033,"y":875,"w":122,"h":62,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0025","x":1217,"y":513,"w":64,"h":106,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0026","x":1979,"y":359,"w":55,"h":112,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0027","x":799,"y":788,"w":98,"h":118,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0028","x":1979,"y":250,"w":59,"h":105,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0029","x":1434,"y":749,"w":87,"h":160,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0030","x":1525,"y":749,"w":92,"h":149,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0031","x":219,"y":887,"w":104,"h":42,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0032","x":527,"y":811,"w":73,"h":18,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0033","x":527,"y":788,"w":72,"h":19,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0034","x":527,"y":833,"w":72,"h":18,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0035","x":1217,"y":623,"w":73,"h":20,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0036","x":344,"y":788,"w":179,"h":67,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0037","x":219,"y":808,"w":118,"h":75,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0038","x":901,"y":875,"w":128,"h":61,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0039","x":1914,"y":885,"w":124,"h":58,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0040","x":901,"y":788,"w":117,"h":83,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0041","x":1022,"y":788,"w":117,"h":83,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0042","x":341,"y":859,"w":103,"h":83,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0043","x":4,"y":808,"w":117,"h":83,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0044","x":1434,"y":648,"w":174,"h":97,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0045","x":1819,"y":250,"w":82,"h":14,"rotated": false}}
|
||||
]},
|
||||
"meta": {
|
||||
"app": "Adobe Animate",
|
||||
"version": "21.0.1.37179",
|
||||
"image": "spritemap1.png",
|
||||
"format": "RGBA8888",
|
||||
"size": {"w":2043,"h":966},
|
||||
"resolution": "1"
|
||||
}
|
||||
{"ATLAS":{"SPRITES":[
|
||||
{"SPRITE":{"name":"0","x":1129,"y":977,"w":86,"h":17,"rotated":false}},
|
||||
{"SPRITE":{"name":"1","x":1690,"y":1012,"w":86,"h":17,"rotated":false}},
|
||||
{"SPRITE":{"name":"2","x":1656,"y":852,"w":126,"h":64,"rotated":false}},
|
||||
{"SPRITE":{"name":"3","x":1915,"y":841,"w":121,"h":77,"rotated":false}},
|
||||
{"SPRITE":{"name":"4","x":1382,"y":980,"w":131,"h":64,"rotated":false}},
|
||||
{"SPRITE":{"name":"5","x":1132,"y":283,"w":420,"h":270,"rotated":false}},
|
||||
{"SPRITE":{"name":"6","x":1570,"y":277,"w":389,"h":273,"rotated":false}},
|
||||
{"SPRITE":{"name":"7","x":0,"y":743,"w":397,"h":292,"rotated":false}},
|
||||
{"SPRITE":{"name":"8","x":431,"y":267,"w":354,"h":332,"rotated":false}},
|
||||
{"SPRITE":{"name":"9","x":1592,"y":568,"w":190,"h":117,"rotated":false}},
|
||||
{"SPRITE":{"name":"10","x":1444,"y":826,"w":86,"h":136,"rotated":false}},
|
||||
{"SPRITE":{"name":"11","x":723,"y":852,"w":260,"h":123,"rotated":false}},
|
||||
{"SPRITE":{"name":"12","x":1548,"y":947,"w":124,"h":68,"rotated":false}},
|
||||
{"SPRITE":{"name":"13","x":1001,"y":852,"w":110,"h":128,"rotated":false}},
|
||||
{"SPRITE":{"name":"14","x":1933,"y":0,"w":106,"h":148,"rotated":false}},
|
||||
{"SPRITE":{"name":"15","x":1129,"y":828,"w":97,"h":131,"rotated":false}},
|
||||
{"SPRITE":{"name":"16","x":803,"y":283,"w":311,"h":369,"rotated":false}},
|
||||
{"SPRITE":{"name":"17","x":1592,"y":703,"w":167,"h":101,"rotated":false}},
|
||||
{"SPRITE":{"name":"18","x":1835,"y":852,"w":57,"h":105,"rotated":false}},
|
||||
{"SPRITE":{"name":"19","x":1977,"y":270,"w":66,"h":104,"rotated":false}},
|
||||
{"SPRITE":{"name":"20","x":1910,"y":936,"w":70,"h":73,"rotated":false}},
|
||||
{"SPRITE":{"name":"21","x":1244,"y":828,"w":182,"h":69,"rotated":false}},
|
||||
{"SPRITE":{"name":"22","x":1690,"y":934,"w":127,"h":60,"rotated":false}},
|
||||
{"SPRITE":{"name":"23","x":418,"y":617,"w":287,"h":363,"rotated":false}},
|
||||
{"SPRITE":{"name":"24","x":1244,"y":915,"w":120,"h":86,"rotated":false}},
|
||||
{"SPRITE":{"name":"25","x":1777,"y":748,"w":120,"h":86,"rotated":false}},
|
||||
{"SPRITE":{"name":"26","x":1933,"y":166,"w":106,"h":86,"rotated":false}},
|
||||
{"SPRITE":{"name":"27","x":1915,"y":737,"w":120,"h":86,"rotated":false}},
|
||||
{"SPRITE":{"name":"28","x":1800,"y":568,"w":89,"h":162,"rotated":false}},
|
||||
{"SPRITE":{"name":"29","x":1907,"y":568,"w":95,"h":151,"rotated":false}},
|
||||
{"SPRITE":{"name":"30","x":1977,"y":392,"w":61,"h":107,"rotated":false}},
|
||||
{"SPRITE":{"name":"31","x":415,"y":998,"w":107,"h":45,"rotated":false}},
|
||||
{"SPRITE":{"name":"32","x":727,"y":993,"w":77,"h":22,"rotated":false}},
|
||||
{"SPRITE":{"name":"33","x":634,"y":998,"w":75,"h":23,"rotated":false}},
|
||||
{"SPRITE":{"name":"34","x":822,"y":993,"w":75,"h":22,"rotated":false}},
|
||||
{"SPRITE":{"name":"35","x":540,"y":998,"w":76,"h":24,"rotated":false}},
|
||||
{"SPRITE":{"name":"36","x":1445,"y":0,"w":470,"h":259,"rotated":false}},
|
||||
{"SPRITE":{"name":"37","x":431,"y":0,"w":513,"h":249,"rotated":false}},
|
||||
{"SPRITE":{"name":"38","x":962,"y":0,"w":465,"h":265,"rotated":false}},
|
||||
{"SPRITE":{"name":"39","x":723,"y":670,"w":331,"h":164,"rotated":false}},
|
||||
{"SPRITE":{"name":"40","x":0,"y":0,"w":413,"h":354,"rotated":false}},
|
||||
{"SPRITE":{"name":"41","x":0,"y":372,"w":400,"h":353,"rotated":false}},
|
||||
{"SPRITE":{"name":"42","x":1548,"y":826,"w":90,"h":103,"rotated":false}},
|
||||
{"SPRITE":{"name":"43","x":1132,"y":571,"w":213,"h":239,"rotated":false}},
|
||||
{"SPRITE":{"name":"44","x":1363,"y":571,"w":211,"h":237,"rotated":false}}]},
|
||||
"meta":{
|
||||
"app":"Adobe Animate (Better TA Extension)",
|
||||
"version":"24.0.2.12",
|
||||
"image":"spritemap1.png",
|
||||
"format":"RGBA8888",
|
||||
"size":{"w":2064,"h":1065},
|
||||
"resolution":"1"
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 165 KiB After Width: | Height: | Size: 265 KiB |
@@ -1,60 +1,60 @@
|
||||
{"ATLAS": {"SPRITES":[
|
||||
{"SPRITE" : {"name": "0000","x":4076,"y":2,"w":9,"h":12,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0001","x":1957,"y":2,"w":524,"h":501,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0002","x":716,"y":2,"w":721,"h":621,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0003","x":2331,"y":505,"w":139,"h":109,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0004","x":3244,"y":725,"w":303,"h":170,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0005","x":1691,"y":516,"w":248,"h":277,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0006","x":2495,"y":843,"w":173,"h":229,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0007","x":2,"y":642,"w":262,"h":221,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0008","x":2331,"y":616,"w":118,"h":117,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0009","x":3549,"y":865,"w":261,"h":139,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0010","x":3209,"y":897,"w":202,"h":122,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0011","x":580,"y":913,"w":202,"h":122,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0012","x":2831,"y":304,"w":45,"h":42,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0013","x":1957,"y":505,"w":372,"h":311,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0014","x":1439,"y":516,"w":250,"h":325,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0015","x":716,"y":625,"w":235,"h":286,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0016","x":953,"y":625,"w":245,"h":249,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0017","x":3644,"y":373,"w":136,"h":133,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0018","x":2331,"y":735,"w":150,"h":91,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0019","x":3644,"y":508,"w":151,"h":95,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0020","x":784,"y":913,"w":140,"h":90,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0021","x":3644,"y":605,"w":149,"h":92,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0022","x":2670,"y":932,"w":144,"h":87,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0023","x":2670,"y":843,"w":152,"h":87,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0024","x":4087,"y":2,"w":1,"h":4,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0025","x":2831,"y":373,"w":411,"h":352,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0026","x":3244,"y":373,"w":398,"h":350,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0027","x":266,"y":642,"w":329,"h":162,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0028","x":597,"y":642,"w":90,"h":103,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0029","x":1200,"y":625,"w":211,"h":236,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0030","x":2831,"y":727,"w":208,"h":235,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0031","x":2483,"y":2,"w":738,"h":300,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0032","x":2483,"y":304,"w":346,"h":537,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0033","x":2,"y":865,"w":235,"h":158,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0034","x":3812,"y":865,"w":216,"h":141,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0035","x":2000,"y":818,"w":299,"h":155,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0036","x":1200,"y":863,"w":179,"h":208,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0037","x":1691,"y":818,"w":307,"h":154,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0038","x":3644,"y":702,"w":320,"h":161,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0039","x":266,"y":806,"w":312,"h":155,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0040","x":239,"y":963,"w":224,"h":108,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0041","x":3223,"y":2,"w":580,"h":369,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0042","x":3805,"y":2,"w":269,"h":698,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0043","x":1413,"y":843,"w":205,"h":222,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0044","x":3041,"y":727,"w":166,"h":292,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0045","x":953,"y":876,"w":203,"h":137,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0046","x":1439,"y":2,"w":516,"h":512,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0047","x":2,"y":2,"w":712,"h":638,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0048","x":2301,"y":843,"w":192,"h":227,"rotated": false}}
|
||||
]},
|
||||
"meta": {
|
||||
"app": "Adobe Animate",
|
||||
"version": "21.0.1.37179",
|
||||
"image": "spritemap1.png",
|
||||
"format": "RGBA8888",
|
||||
"size": {"w":4090,"h":1074},
|
||||
"resolution": "1"
|
||||
}
|
||||
{"ATLAS":{"SPRITES":[
|
||||
{"SPRITE":{"name":"0","x":2834,"y":332,"w":12,"h":15,"rotated":false}},
|
||||
{"SPRITE":{"name":"1","x":1476,"y":532,"w":527,"h":503,"rotated":false}},
|
||||
{"SPRITE":{"name":"2","x":733,"y":0,"w":725,"h":623,"rotated":false}},
|
||||
{"SPRITE":{"name":"3","x":0,"y":659,"w":741,"h":304,"rotated":false}},
|
||||
{"SPRITE":{"name":"4","x":2311,"y":0,"w":349,"h":540,"rotated":false}},
|
||||
{"SPRITE":{"name":"5","x":759,"y":641,"w":583,"h":373,"rotated":false}},
|
||||
{"SPRITE":{"name":"6","x":2021,"y":0,"w":272,"h":702,"rotated":false}},
|
||||
{"SPRITE":{"name":"7","x":1476,"y":0,"w":518,"h":514,"rotated":false}},
|
||||
{"SPRITE":{"name":"8","x":0,"y":0,"w":715,"h":641,"rotated":false}},
|
||||
{"SPRITE":{"name":"9","x":619,"y":1032,"w":205,"h":122,"rotated":false}},
|
||||
{"SPRITE":{"name":"10","x":842,"y":1032,"w":205,"h":122,"rotated":false}},
|
||||
{"SPRITE":{"name":"11","x":2311,"y":558,"w":115,"h":112,"rotated":false}},
|
||||
{"SPRITE":{"name":"12","x":2801,"y":947,"w":305,"h":172,"rotated":false}},
|
||||
{"SPRITE":{"name":"13","x":2678,"y":0,"w":375,"h":314,"rotated":false}},
|
||||
{"SPRITE":{"name":"14","x":2870,"y":332,"w":252,"h":328,"rotated":false}},
|
||||
{"SPRITE":{"name":"15","x":3071,"y":0,"w":239,"h":290,"rotated":false}},
|
||||
{"SPRITE":{"name":"16","x":3135,"y":678,"w":220,"h":246,"rotated":false}},
|
||||
{"SPRITE":{"name":"17","x":3597,"y":248,"w":173,"h":231,"rotated":false}},
|
||||
{"SPRITE":{"name":"18","x":3769,"y":0,"w":225,"h":190,"rotated":false}},
|
||||
{"SPRITE":{"name":"19","x":1290,"y":1053,"w":131,"h":81,"rotated":false}},
|
||||
{"SPRITE":{"name":"20","x":3905,"y":814,"w":132,"h":85,"rotated":false}},
|
||||
{"SPRITE":{"name":"21","x":1733,"y":1053,"w":122,"h":80,"rotated":false}},
|
||||
{"SPRITE":{"name":"22","x":3905,"y":917,"w":129,"h":82,"rotated":false}},
|
||||
{"SPRITE":{"name":"23","x":1589,"y":1053,"w":126,"h":78,"rotated":false}},
|
||||
{"SPRITE":{"name":"24","x":1439,"y":1053,"w":132,"h":77,"rotated":false}},
|
||||
{"SPRITE":{"name":"25","x":3778,"y":814,"w":109,"h":107,"rotated":false}},
|
||||
{"SPRITE":{"name":"26","x":3124,"y":1123,"w":3,"h":7,"rotated":false}},
|
||||
{"SPRITE":{"name":"27","x":3145,"y":1123,"w":3,"h":7,"rotated":false}},
|
||||
{"SPRITE":{"name":"28","x":3673,"y":497,"w":260,"h":141,"rotated":false}},
|
||||
{"SPRITE":{"name":"29","x":3788,"y":208,"w":237,"h":161,"rotated":false}},
|
||||
{"SPRITE":{"name":"30","x":3542,"y":660,"w":218,"h":144,"rotated":false}},
|
||||
{"SPRITE":{"name":"31","x":3124,"y":947,"w":301,"h":158,"rotated":false}},
|
||||
{"SPRITE":{"name":"32","x":3371,"y":498,"w":284,"h":144,"rotated":false}},
|
||||
{"SPRITE":{"name":"33","x":0,"y":981,"w":295,"h":150,"rotated":false}},
|
||||
{"SPRITE":{"name":"34","x":313,"y":981,"w":288,"h":145,"rotated":false}},
|
||||
{"SPRITE":{"name":"35","x":3443,"y":942,"w":182,"h":212,"rotated":false}},
|
||||
{"SPRITE":{"name":"36","x":3371,"y":255,"w":208,"h":225,"rotated":false}},
|
||||
{"SPRITE":{"name":"37","x":3373,"y":660,"w":151,"h":264,"rotated":false}},
|
||||
{"SPRITE":{"name":"38","x":3778,"y":656,"w":206,"h":140,"rotated":false}},
|
||||
{"SPRITE":{"name":"39","x":3557,"y":0,"w":194,"h":230,"rotated":false}},
|
||||
{"SPRITE":{"name":"40","x":2678,"y":485,"w":47,"h":44,"rotated":false}},
|
||||
{"SPRITE":{"name":"41","x":2870,"y":678,"w":247,"h":251,"rotated":false}},
|
||||
{"SPRITE":{"name":"42","x":2678,"y":332,"w":138,"h":135,"rotated":false}},
|
||||
{"SPRITE":{"name":"43","x":1065,"y":1053,"w":207,"h":101,"rotated":false}},
|
||||
{"SPRITE":{"name":"44","x":2452,"y":947,"w":331,"h":164,"rotated":false}},
|
||||
{"SPRITE":{"name":"45","x":2021,"y":720,"w":413,"h":354,"rotated":false}},
|
||||
{"SPRITE":{"name":"46","x":2452,"y":558,"w":400,"h":353,"rotated":false}},
|
||||
{"SPRITE":{"name":"47","x":3951,"y":387,"w":90,"h":103,"rotated":false}},
|
||||
{"SPRITE":{"name":"48","x":3140,"y":308,"w":213,"h":239,"rotated":false}},
|
||||
{"SPRITE":{"name":"49","x":3328,"y":0,"w":211,"h":237,"rotated":false}}]},
|
||||
"meta":{
|
||||
"app":"Adobe Animate (Better TA Extension)",
|
||||
"version":"24.0.2.12",
|
||||
"image":"spritemap1.png",
|
||||
"format":"RGBA8888",
|
||||
"size":{"w":4061,"h":1154},
|
||||
"resolution":"1"
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 344 KiB After Width: | Height: | Size: 535 KiB |
|
Before Width: | Height: | Size: 804 B After Width: | Height: | Size: 1.0 KiB |
@@ -1,145 +1,241 @@
|
||||
{"ATLAS": {"SPRITES":[
|
||||
{"SPRITE" : {"name": "0000","x":2847,"y":969,"w":327,"h":397,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0001","x":2441,"y":894,"w":110,"h":159,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0002","x":1709,"y":1631,"w":197,"h":185,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0003","x":408,"y":1773,"w":92,"h":155,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0004","x":236,"y":1639,"w":274,"h":132,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0005","x":3427,"y":1495,"w":133,"h":74,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0006","x":3270,"y":540,"w":121,"h":162,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0007","x":359,"y":649,"w":518,"h":294,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0008","x":1957,"y":2,"w":775,"h":483,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0009","x":1014,"y":2,"w":941,"h":607,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0010","x":2,"y":2,"w":1010,"h":645,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0011","x":4059,"y":2,"w":20,"h":142,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0012","x":4035,"y":616,"w":40,"h":83,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0013","x":2755,"y":1508,"w":64,"h":57,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0014","x":3176,"y":1171,"w":91,"h":48,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0015","x":3245,"y":1737,"w":88,"h":41,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0016","x":3064,"y":1368,"w":109,"h":93,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0017","x":3402,"y":2,"w":655,"h":434,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0018","x":1957,"y":487,"w":626,"h":405,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0019","x":3402,"y":438,"w":631,"h":438,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0020","x":1170,"y":1211,"w":393,"h":287,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0021","x":2847,"y":540,"w":421,"h":427,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0022","x":2734,"y":2,"w":666,"h":536,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0023","x":542,"y":1480,"w":224,"h":221,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0024","x":3657,"y":1736,"w":186,"h":175,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0025","x":4035,"y":764,"w":56,"h":52,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0026","x":502,"y":1876,"w":126,"h":104,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0027","x":1709,"y":1818,"w":135,"h":104,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0028","x":2,"y":1440,"w":232,"h":236,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0029","x":3938,"y":1437,"w":139,"h":109,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0030","x":2755,"y":1627,"w":235,"h":158,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0031","x":1147,"y":1500,"w":198,"h":233,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0032","x":2,"y":1860,"w":118,"h":117,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0033","x":1565,"y":1398,"w":262,"h":221,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0034","x":3845,"y":1736,"w":222,"h":145,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0035","x":979,"y":1480,"w":166,"h":292,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0036","x":3657,"y":1592,"w":276,"h":142,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0037","x":925,"y":1774,"w":203,"h":138,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0038","x":236,"y":1467,"w":304,"h":170,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0039","x":4081,"y":2,"w":1,"h":4,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0040","x":2441,"y":1055,"w":135,"h":127,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0041","x":2,"y":1678,"w":195,"h":180,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0042","x":2751,"y":1787,"w":160,"h":144,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0043","x":713,"y":945,"w":243,"h":261,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0044","x":2375,"y":1508,"w":378,"h":121,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0045","x":3064,"y":1495,"w":361,"h":128,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0046","x":713,"y":1211,"w":455,"h":267,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0047","x":2,"y":1112,"w":272,"h":326,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0048","x":3710,"y":878,"w":249,"h":557,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0049","x":2585,"y":540,"w":260,"h":701,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0050","x":1014,"y":611,"w":291,"h":598,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0051","x":1307,"y":611,"w":315,"h":540,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0052","x":2,"y":649,"w":355,"h":461,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0053","x":359,"y":945,"w":352,"h":373,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0054","x":3064,"y":1625,"w":347,"h":110,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0055","x":2039,"y":1248,"w":379,"h":216,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0056","x":2827,"y":1368,"w":235,"h":257,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0057","x":2100,"y":1879,"w":140,"h":92,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0058","x":776,"y":1886,"w":119,"h":79,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0059","x":1565,"y":1249,"w":434,"h":147,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0060","x":276,"y":1320,"w":433,"h":145,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0061","x":3270,"y":878,"w":438,"h":342,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0062","x":3176,"y":1222,"w":385,"h":271,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0063","x":3563,"y":1437,"w":373,"h":153,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0064","x":3245,"y":1786,"w":202,"h":122,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0065","x":3449,"y":1786,"w":202,"h":122,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0066","x":3064,"y":1861,"w":150,"h":91,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0067","x":3938,"y":1548,"w":151,"h":95,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0068","x":3845,"y":1883,"w":140,"h":90,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0069","x":2913,"y":1861,"w":149,"h":92,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0070","x":630,"y":1886,"w":144,"h":87,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0071","x":3935,"y":1645,"w":152,"h":87,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0072","x":2441,"y":1243,"w":384,"h":263,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0073","x":1624,"y":611,"w":248,"h":277,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0074","x":1624,"y":894,"w":413,"h":353,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0075","x":2039,"y":894,"w":400,"h":352,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0076","x":1829,"y":1466,"w":330,"h":163,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0077","x":3987,"y":1883,"w":90,"h":103,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0078","x":2161,"y":1466,"w":212,"h":238,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0079","x":768,"y":1480,"w":209,"h":236,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0080","x":2242,"y":1879,"w":86,"h":84,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0081","x":879,"y":649,"w":126,"h":148,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0082","x":1908,"y":1631,"w":216,"h":168,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0083","x":2575,"y":1631,"w":174,"h":192,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0084","x":1130,"y":1901,"w":106,"h":75,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0085","x":3961,"y":1367,"w":129,"h":63,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0086","x":1829,"y":1398,"w":158,"h":60,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0087","x":3270,"y":704,"w":123,"h":148,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0088","x":3961,"y":878,"w":123,"h":148,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0089","x":199,"y":1773,"w":207,"h":142,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0090","x":1238,"y":1901,"w":91,"h":53,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0091","x":276,"y":1112,"w":65,"h":96,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0092","x":276,"y":1210,"w":65,"h":96,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0093","x":2518,"y":1825,"w":136,"h":102,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0094","x":1537,"y":1857,"w":136,"h":102,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0095","x":3427,"y":1592,"w":228,"h":192,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0096","x":1541,"y":1621,"w":166,"h":234,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0097","x":512,"y":1703,"w":205,"h":171,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0098","x":2126,"y":1706,"w":205,"h":171,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0099","x":719,"y":1718,"w":204,"h":166,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0100","x":1147,"y":1735,"w":206,"h":164,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0101","x":1874,"y":611,"w":79,"h":185,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0102","x":3176,"y":969,"w":83,"h":200,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0103","x":3563,"y":1222,"w":86,"h":180,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0104","x":3961,"y":1028,"w":89,"h":186,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0105","x":2375,"y":1631,"w":198,"h":183,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0106","x":1908,"y":1801,"w":190,"h":120,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0107","x":2656,"y":1825,"w":86,"h":145,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0108","x":1355,"y":1724,"w":180,"h":170,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0109","x":3961,"y":1216,"w":111,"h":149,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0110","x":4035,"y":516,"w":39,"h":98,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0111","x":1307,"y":1153,"w":118,"h":47,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0112","x":1427,"y":1153,"w":120,"h":43,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0113","x":2441,"y":1184,"w":120,"h":41,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0114","x":3216,"y":1910,"w":95,"h":33,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0115","x":3563,"y":1404,"w":95,"h":31,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0116","x":3563,"y":1404,"w":95,"h":31,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0117","x":2330,"y":1906,"w":95,"h":34,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0118","x":2585,"y":487,"w":131,"h":47,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0119","x":4059,"y":258,"w":31,"h":18,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0120","x":1355,"y":1896,"w":122,"h":66,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0121","x":2992,"y":1737,"w":251,"h":122,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0122","x":879,"y":799,"w":114,"h":133,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0123","x":1347,"y":1500,"w":192,"h":222,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0124","x":4035,"y":818,"w":39,"h":34,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0125","x":4035,"y":701,"w":50,"h":61,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0126","x":1874,"y":798,"w":64,"h":78,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0127","x":4035,"y":438,"w":52,"h":76,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0128","x":958,"y":934,"w":46,"h":63,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0129","x":4059,"y":146,"w":30,"h":41,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0130","x":4059,"y":189,"w":23,"h":35,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0131","x":4059,"y":226,"w":20,"h":30,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0132","x":4059,"y":278,"w":17,"h":22,"rotated": false}},
|
||||
{"SPRITE" : {"name": "0133","x":2333,"y":1816,"w":183,"h":88,"rotated": false}}
|
||||
]},
|
||||
"meta": {
|
||||
"app": "Adobe Animate",
|
||||
"version": "21.0.1.37179",
|
||||
"image": "spritemap1.png",
|
||||
"format": "RGBA8888",
|
||||
"size": {"w":4093,"h":1988},
|
||||
"resolution": "1"
|
||||
}
|
||||
{"ATLAS":{"SPRITES":[
|
||||
{"SPRITE":{"name":"0","x":2564,"y":2,"w":23,"h":144,"rotated":false}},
|
||||
{"SPRITE":{"name":"1","x":3024,"y":522,"w":42,"h":85,"rotated":false}},
|
||||
{"SPRITE":{"name":"2","x":2598,"y":1211,"w":67,"h":60,"rotated":false}},
|
||||
{"SPRITE":{"name":"3","x":3964,"y":932,"w":93,"h":51,"rotated":false}},
|
||||
{"SPRITE":{"name":"4","x":3691,"y":1016,"w":91,"h":43,"rotated":false}},
|
||||
{"SPRITE":{"name":"5","x":3877,"y":270,"w":111,"h":95,"rotated":false}},
|
||||
{"SPRITE":{"name":"6","x":3449,"y":1124,"w":113,"h":127,"rotated":false}},
|
||||
{"SPRITE":{"name":"7","x":367,"y":1129,"w":382,"h":123,"rotated":false}},
|
||||
{"SPRITE":{"name":"8","x":2,"y":1122,"w":364,"h":131,"rotated":false}},
|
||||
{"SPRITE":{"name":"9","x":2,"y":1122,"w":364,"h":131,"rotated":false}},
|
||||
{"SPRITE":{"name":"10","x":2437,"y":1136,"w":31,"h":31,"rotated":false}},
|
||||
{"SPRITE":{"name":"11","x":1599,"y":1133,"w":350,"h":113,"rotated":false}},
|
||||
{"SPRITE":{"name":"12","x":1599,"y":1133,"w":350,"h":113,"rotated":false}},
|
||||
{"SPRITE":{"name":"13","x":2670,"y":1175,"w":142,"h":94,"rotated":false}},
|
||||
{"SPRITE":{"name":"14","x":3877,"y":366,"w":122,"h":82,"rotated":false}},
|
||||
{"SPRITE":{"name":"15","x":1162,"y":1112,"w":436,"h":151,"rotated":false}},
|
||||
{"SPRITE":{"name":"16","x":1599,"y":985,"w":435,"h":147,"rotated":false}},
|
||||
{"SPRITE":{"name":"17","x":1599,"y":985,"w":435,"h":147,"rotated":false}},
|
||||
{"SPRITE":{"name":"18","x":779,"y":692,"w":440,"h":344,"rotated":false}},
|
||||
{"SPRITE":{"name":"19","x":1550,"y":711,"w":388,"h":273,"rotated":false}},
|
||||
{"SPRITE":{"name":"20","x":2106,"y":2,"w":376,"h":155,"rotated":false}},
|
||||
{"SPRITE":{"name":"21","x":2,"y":2,"w":932,"h":689,"rotated":false}},
|
||||
{"SPRITE":{"name":"22","x":3907,"y":1171,"w":48,"h":36,"rotated":false}},
|
||||
{"SPRITE":{"name":"23","x":3907,"y":1171,"w":48,"h":36,"rotated":false}},
|
||||
{"SPRITE":{"name":"24","x":3858,"y":1206,"w":48,"h":40,"rotated":false}},
|
||||
{"SPRITE":{"name":"25","x":3762,"y":1093,"w":48,"h":64,"rotated":false}},
|
||||
{"SPRITE":{"name":"26","x":3713,"y":1060,"w":48,"h":66,"rotated":false}},
|
||||
{"SPRITE":{"name":"27","x":3885,"y":1095,"w":48,"h":67,"rotated":false}},
|
||||
{"SPRITE":{"name":"28","x":2106,"y":158,"w":48,"h":69,"rotated":false}},
|
||||
{"SPRITE":{"name":"29","x":2481,"y":498,"w":48,"h":71,"rotated":false}},
|
||||
{"SPRITE":{"name":"30","x":1162,"y":1037,"w":48,"h":73,"rotated":false}},
|
||||
{"SPRITE":{"name":"31","x":4018,"y":188,"w":48,"h":76,"rotated":false}},
|
||||
{"SPRITE":{"name":"32","x":3455,"y":856,"w":48,"h":78,"rotated":false}},
|
||||
{"SPRITE":{"name":"33","x":3785,"y":1011,"w":48,"h":81,"rotated":false}},
|
||||
{"SPRITE":{"name":"34","x":4002,"y":1164,"w":48,"h":82,"rotated":false}},
|
||||
{"SPRITE":{"name":"35","x":3953,"y":1083,"w":48,"h":87,"rotated":false}},
|
||||
{"SPRITE":{"name":"36","x":3904,"y":1004,"w":48,"h":90,"rotated":false}},
|
||||
{"SPRITE":{"name":"37","x":4013,"y":1070,"w":48,"h":93,"rotated":false}},
|
||||
{"SPRITE":{"name":"38","x":3964,"y":984,"w":48,"h":98,"rotated":false}},
|
||||
{"SPRITE":{"name":"39","x":1550,"y":985,"w":48,"h":103,"rotated":false}},
|
||||
{"SPRITE":{"name":"40","x":3848,"y":894,"w":50,"h":109,"rotated":false}},
|
||||
{"SPRITE":{"name":"41","x":3797,"y":894,"w":50,"h":116,"rotated":false}},
|
||||
{"SPRITE":{"name":"42","x":2777,"y":452,"w":50,"h":121,"rotated":false}},
|
||||
{"SPRITE":{"name":"43","x":4002,"y":585,"w":50,"h":119,"rotated":false}},
|
||||
{"SPRITE":{"name":"44","x":3913,"y":886,"w":50,"h":117,"rotated":false}},
|
||||
{"SPRITE":{"name":"45","x":3059,"y":2,"w":52,"h":129,"rotated":false}},
|
||||
{"SPRITE":{"name":"46","x":3964,"y":886,"w":123,"h":45,"rotated":false}},
|
||||
{"SPRITE":{"name":"47","x":1770,"y":228,"w":123,"h":43,"rotated":false}},
|
||||
{"SPRITE":{"name":"48","x":3424,"y":486,"w":99,"h":35,"rotated":false}},
|
||||
{"SPRITE":{"name":"49","x":2979,"y":1141,"w":99,"h":34,"rotated":false}},
|
||||
{"SPRITE":{"name":"50","x":2979,"y":1141,"w":99,"h":34,"rotated":false}},
|
||||
{"SPRITE":{"name":"51","x":2590,"y":360,"w":99,"h":36,"rotated":false}},
|
||||
{"SPRITE":{"name":"52","x":3709,"y":783,"w":35,"h":21,"rotated":false}},
|
||||
{"SPRITE":{"name":"53","x":1220,"y":711,"w":329,"h":400,"rotated":false}},
|
||||
{"SPRITE":{"name":"54","x":3042,"y":979,"w":112,"h":161,"rotated":false}},
|
||||
{"SPRITE":{"name":"55","x":2929,"y":163,"w":199,"h":188,"rotated":false}},
|
||||
{"SPRITE":{"name":"56","x":2175,"y":574,"w":96,"h":158,"rotated":false}},
|
||||
{"SPRITE":{"name":"57","x":1623,"y":570,"w":277,"h":134,"rotated":false}},
|
||||
{"SPRITE":{"name":"58","x":1550,"y":1089,"w":38,"h":22,"rotated":false}},
|
||||
{"SPRITE":{"name":"59","x":3666,"y":152,"w":124,"h":165,"rotated":false}},
|
||||
{"SPRITE":{"name":"60","x":1623,"y":272,"w":309,"h":297,"rotated":false}},
|
||||
{"SPRITE":{"name":"61","x":3801,"y":2,"w":121,"h":91,"rotated":false}},
|
||||
{"SPRITE":{"name":"62","x":3281,"y":522,"w":320,"h":77,"rotated":false}},
|
||||
{"SPRITE":{"name":"63","x":3921,"y":755,"w":17,"h":22,"rotated":false}},
|
||||
{"SPRITE":{"name":"64","x":1351,"y":272,"w":162,"h":74,"rotated":false}},
|
||||
{"SPRITE":{"name":"65","x":3801,"y":94,"w":69,"h":50,"rotated":false}},
|
||||
{"SPRITE":{"name":"66","x":2273,"y":574,"w":277,"h":174,"rotated":false}},
|
||||
{"SPRITE":{"name":"67","x":2261,"y":1136,"w":175,"h":123,"rotated":false}},
|
||||
{"SPRITE":{"name":"68","x":4058,"y":932,"w":32,"h":49,"rotated":false}},
|
||||
{"SPRITE":{"name":"69","x":3791,"y":270,"w":66,"h":38,"rotated":false}},
|
||||
{"SPRITE":{"name":"70","x":3079,"y":1141,"w":71,"h":40,"rotated":false}},
|
||||
{"SPRITE":{"name":"71","x":2690,"y":360,"w":82,"h":29,"rotated":false}},
|
||||
{"SPRITE":{"name":"72","x":3602,"y":516,"w":88,"h":69,"rotated":false}},
|
||||
{"SPRITE":{"name":"73","x":4022,"y":806,"w":69,"h":27,"rotated":false}},
|
||||
{"SPRITE":{"name":"74","x":1894,"y":228,"w":30,"h":40,"rotated":false}},
|
||||
{"SPRITE":{"name":"75","x":3987,"y":654,"w":10,"h":13,"rotated":false}},
|
||||
{"SPRITE":{"name":"76","x":3896,"y":1084,"w":7,"h":7,"rotated":false}},
|
||||
{"SPRITE":{"name":"77","x":3834,"y":1074,"w":9,"h":9,"rotated":false}},
|
||||
{"SPRITE":{"name":"78","x":3885,"y":1084,"w":10,"h":10,"rotated":false}},
|
||||
{"SPRITE":{"name":"79","x":3441,"y":736,"w":12,"h":12,"rotated":false}},
|
||||
{"SPRITE":{"name":"80","x":3811,"y":1128,"w":19,"h":17,"rotated":false}},
|
||||
{"SPRITE":{"name":"81","x":3971,"y":654,"w":15,"h":14,"rotated":false}},
|
||||
{"SPRITE":{"name":"82","x":3858,"y":1150,"w":7,"h":7,"rotated":false}},
|
||||
{"SPRITE":{"name":"83","x":3794,"y":452,"w":5,"h":5,"rotated":false}},
|
||||
{"SPRITE":{"name":"84","x":3326,"y":751,"w":32,"h":57,"rotated":false}},
|
||||
{"SPRITE":{"name":"85","x":2583,"y":147,"w":6,"h":7,"rotated":false}},
|
||||
{"SPRITE":{"name":"86","x":935,"y":617,"w":198,"h":66,"rotated":false}},
|
||||
{"SPRITE":{"name":"87","x":426,"y":692,"w":352,"h":436,"rotated":false}},
|
||||
{"SPRITE":{"name":"88","x":3814,"y":452,"w":156,"h":69,"rotated":false}},
|
||||
{"SPRITE":{"name":"89","x":2829,"y":452,"w":194,"h":197,"rotated":false}},
|
||||
{"SPRITE":{"name":"90","x":2670,"y":733,"w":181,"h":216,"rotated":false}},
|
||||
{"SPRITE":{"name":"91","x":3791,"y":150,"w":93,"h":119,"rotated":false}},
|
||||
{"SPRITE":{"name":"92","x":4000,"y":372,"w":86,"h":75,"rotated":false}},
|
||||
{"SPRITE":{"name":"93","x":3587,"y":320,"w":113,"h":195,"rotated":false}},
|
||||
{"SPRITE":{"name":"94","x":2483,"y":2,"w":80,"h":151,"rotated":false}},
|
||||
{"SPRITE":{"name":"95","x":3493,"y":2,"w":177,"h":149,"rotated":false}},
|
||||
{"SPRITE":{"name":"96","x":3327,"y":183,"w":9,"h":8,"rotated":false}},
|
||||
{"SPRITE":{"name":"97","x":3787,"y":452,"w":6,"h":6,"rotated":false}},
|
||||
{"SPRITE":{"name":"98","x":4002,"y":705,"w":57,"h":48,"rotated":false}},
|
||||
{"SPRITE":{"name":"99","x":2574,"y":147,"w":8,"h":8,"rotated":false}},
|
||||
{"SPRITE":{"name":"100","x":3814,"y":605,"w":8,"h":12,"rotated":false}},
|
||||
{"SPRITE":{"name":"101","x":1589,"y":1089,"w":9,"h":10,"rotated":false}},
|
||||
{"SPRITE":{"name":"102","x":3701,"y":318,"w":85,"h":140,"rotated":false}},
|
||||
{"SPRITE":{"name":"103","x":2,"y":692,"w":423,"h":429,"rotated":false}},
|
||||
{"SPRITE":{"name":"104","x":3533,"y":152,"w":132,"h":167,"rotated":false}},
|
||||
{"SPRITE":{"name":"105","x":3249,"y":961,"w":66,"h":16,"rotated":false}},
|
||||
{"SPRITE":{"name":"106","x":3576,"y":808,"w":52,"h":43,"rotated":false}},
|
||||
{"SPRITE":{"name":"107","x":3858,"y":1163,"w":46,"h":42,"rotated":false}},
|
||||
{"SPRITE":{"name":"108","x":3834,"y":1011,"w":13,"h":62,"rotated":false}},
|
||||
{"SPRITE":{"name":"109","x":3654,"y":1025,"w":34,"h":29,"rotated":false}},
|
||||
{"SPRITE":{"name":"110","x":3811,"y":1150,"w":46,"h":65,"rotated":false}},
|
||||
{"SPRITE":{"name":"111","x":3701,"y":459,"w":112,"h":46,"rotated":false}},
|
||||
{"SPRITE":{"name":"112","x":2035,"y":898,"w":226,"h":223,"rotated":false}},
|
||||
{"SPRITE":{"name":"113","x":3233,"y":351,"w":190,"h":170,"rotated":false}},
|
||||
{"SPRITE":{"name":"114","x":3654,"y":1060,"w":58,"h":55,"rotated":false}},
|
||||
{"SPRITE":{"name":"115","x":3885,"y":94,"w":112,"h":94,"rotated":false}},
|
||||
{"SPRITE":{"name":"116","x":3576,"y":706,"w":132,"h":101,"rotated":false}},
|
||||
{"SPRITE":{"name":"117","x":1939,"y":493,"w":235,"h":239,"rotated":false}},
|
||||
{"SPRITE":{"name":"118","x":3242,"y":1150,"w":141,"h":111,"rotated":false}},
|
||||
{"SPRITE":{"name":"119","x":2822,"y":2,"w":236,"h":160,"rotated":false}},
|
||||
{"SPRITE":{"name":"120","x":2475,"y":749,"w":194,"h":236,"rotated":false}},
|
||||
{"SPRITE":{"name":"121","x":3455,"y":736,"w":120,"h":119,"rotated":false}},
|
||||
{"SPRITE":{"name":"122","x":2551,"y":398,"w":225,"h":189,"rotated":false}},
|
||||
{"SPRITE":{"name":"123","x":3923,"y":2,"w":130,"h":81,"rotated":false}},
|
||||
{"SPRITE":{"name":"124","x":3691,"y":621,"w":132,"h":83,"rotated":false}},
|
||||
{"SPRITE":{"name":"125","x":3531,"y":1025,"w":122,"h":80,"rotated":false}},
|
||||
{"SPRITE":{"name":"126","x":3814,"y":522,"w":129,"h":82,"rotated":false}},
|
||||
{"SPRITE":{"name":"127","x":3709,"y":705,"w":125,"h":77,"rotated":false}},
|
||||
{"SPRITE":{"name":"128","x":3885,"y":189,"w":132,"h":76,"rotated":false}},
|
||||
{"SPRITE":{"name":"129","x":2035,"y":1122,"w":225,"h":142,"rotated":false}},
|
||||
{"SPRITE":{"name":"130","x":2777,"y":187,"w":151,"h":264,"rotated":false}},
|
||||
{"SPRITE":{"name":"131","x":2551,"y":588,"w":277,"h":144,"rotated":false}},
|
||||
{"SPRITE":{"name":"132","x":3327,"y":197,"w":205,"h":140,"rotated":false}},
|
||||
{"SPRITE":{"name":"133","x":2175,"y":401,"w":305,"h":172,"rotated":false}},
|
||||
{"SPRITE":{"name":"134","x":2841,"y":1136,"w":137,"h":129,"rotated":false}},
|
||||
{"SPRITE":{"name":"135","x":3129,"y":172,"w":197,"h":178,"rotated":false}},
|
||||
{"SPRITE":{"name":"136","x":2,"y":1122,"w":364,"h":131,"rotated":false}},
|
||||
{"SPRITE":{"name":"137","x":3424,"y":338,"w":162,"h":147,"rotated":false}},
|
||||
{"SPRITE":{"name":"138","x":1933,"y":228,"w":223,"h":264,"rotated":false}},
|
||||
{"SPRITE":{"name":"139","x":1351,"y":2,"w":418,"h":269,"rotated":false}},
|
||||
{"SPRITE":{"name":"140","x":1599,"y":1133,"w":350,"h":113,"rotated":false}},
|
||||
{"SPRITE":{"name":"141","x":1599,"y":985,"w":435,"h":147,"rotated":false}},
|
||||
{"SPRITE":{"name":"142","x":3921,"y":670,"w":80,"h":84,"rotated":false}},
|
||||
{"SPRITE":{"name":"143","x":2564,"y":147,"w":9,"h":8,"rotated":false}},
|
||||
{"SPRITE":{"name":"144","x":2437,"y":1168,"w":31,"h":27,"rotated":false}},
|
||||
{"SPRITE":{"name":"145","x":3664,"y":808,"w":110,"h":88,"rotated":false}},
|
||||
{"SPRITE":{"name":"146","x":3024,"y":608,"w":43,"h":39,"rotated":false}},
|
||||
{"SPRITE":{"name":"147","x":3563,"y":1106,"w":55,"h":58,"rotated":false}},
|
||||
{"SPRITE":{"name":"148","x":3971,"y":619,"w":19,"h":34,"rotated":false}},
|
||||
{"SPRITE":{"name":"149","x":3416,"y":1250,"w":30,"h":23,"rotated":false}},
|
||||
{"SPRITE":{"name":"150","x":1939,"y":898,"w":82,"h":85,"rotated":false}},
|
||||
{"SPRITE":{"name":"151","x":4054,"y":39,"w":34,"h":41,"rotated":false}},
|
||||
{"SPRITE":{"name":"152","x":3691,"y":516,"w":122,"h":104,"rotated":false}},
|
||||
{"SPRITE":{"name":"153","x":3762,"y":1060,"w":17,"h":32,"rotated":false}},
|
||||
{"SPRITE":{"name":"154","x":3745,"y":783,"w":28,"h":20,"rotated":false}},
|
||||
{"SPRITE":{"name":"155","x":3524,"y":486,"w":45,"h":35,"rotated":false}},
|
||||
{"SPRITE":{"name":"156","x":4000,"y":266,"w":74,"h":105,"rotated":false}},
|
||||
{"SPRITE":{"name":"157","x":3775,"y":836,"w":137,"h":57,"rotated":false}},
|
||||
{"SPRITE":{"name":"158","x":3384,"y":1250,"w":31,"h":23,"rotated":false}},
|
||||
{"SPRITE":{"name":"159","x":3504,"y":908,"w":24,"h":24,"rotated":false}},
|
||||
{"SPRITE":{"name":"160","x":4013,"y":984,"w":55,"h":85,"rotated":false}},
|
||||
{"SPRITE":{"name":"161","x":4054,"y":2,"w":40,"h":36,"rotated":false}},
|
||||
{"SPRITE":{"name":"162","x":3775,"y":783,"w":163,"h":52,"rotated":false}},
|
||||
{"SPRITE":{"name":"163","x":1950,"y":1133,"w":73,"h":115,"rotated":false}},
|
||||
{"SPRITE":{"name":"164","x":3531,"y":962,"w":159,"h":62,"rotated":false}},
|
||||
{"SPRITE":{"name":"165","x":3811,"y":1093,"w":20,"h":34,"rotated":false}},
|
||||
{"SPRITE":{"name":"166","x":4067,"y":230,"w":27,"h":32,"rotated":false}},
|
||||
{"SPRITE":{"name":"167","x":4067,"y":188,"w":24,"h":41,"rotated":false}},
|
||||
{"SPRITE":{"name":"168","x":3504,"y":856,"w":26,"h":51,"rotated":false}},
|
||||
{"SPRITE":{"name":"169","x":2929,"y":352,"w":86,"h":98,"rotated":false}},
|
||||
{"SPRITE":{"name":"170","x":3824,"y":605,"w":146,"h":64,"rotated":false}},
|
||||
{"SPRITE":{"name":"171","x":1589,"y":1100,"w":9,"h":10,"rotated":false}},
|
||||
{"SPRITE":{"name":"172","x":3327,"y":172,"w":8,"h":10,"rotated":false}},
|
||||
{"SPRITE":{"name":"173","x":3939,"y":806,"w":82,"h":27,"rotated":false}},
|
||||
{"SPRITE":{"name":"174","x":3944,"y":522,"w":141,"h":62,"rotated":false}},
|
||||
{"SPRITE":{"name":"175","x":3024,"y":352,"w":208,"h":169,"rotated":false}},
|
||||
{"SPRITE":{"name":"176","x":3129,"y":2,"w":208,"h":169,"rotated":false}},
|
||||
{"SPRITE":{"name":"177","x":3042,"y":814,"w":206,"h":164,"rotated":false}},
|
||||
{"SPRITE":{"name":"178","x":3072,"y":522,"w":208,"h":161,"rotated":false}},
|
||||
{"SPRITE":{"name":"179","x":779,"y":1037,"w":382,"h":218,"rotated":false}},
|
||||
{"SPRITE":{"name":"180","x":935,"y":357,"w":237,"h":259,"rotated":false}},
|
||||
{"SPRITE":{"name":"181","x":3155,"y":979,"w":86,"h":203,"rotated":false}},
|
||||
{"SPRITE":{"name":"182","x":3364,"y":751,"w":90,"h":183,"rotated":false}},
|
||||
{"SPRITE":{"name":"183","x":3357,"y":961,"w":91,"h":188,"rotated":false}},
|
||||
{"SPRITE":{"name":"184","x":2852,"y":814,"w":185,"h":122,"rotated":false}},
|
||||
{"SPRITE":{"name":"185","x":3787,"y":318,"w":89,"h":133,"rotated":false}},
|
||||
{"SPRITE":{"name":"186","x":2590,"y":187,"w":183,"h":172,"rotated":false}},
|
||||
{"SPRITE":{"name":"187","x":3242,"y":979,"w":114,"h":151,"rotated":false}},
|
||||
{"SPRITE":{"name":"188","x":4047,"y":834,"w":42,"h":36,"rotated":false}},
|
||||
{"SPRITE":{"name":"189","x":1134,"y":617,"w":53,"h":63,"rotated":false}},
|
||||
{"SPRITE":{"name":"190","x":3166,"y":1183,"w":67,"h":80,"rotated":false}},
|
||||
{"SPRITE":{"name":"191","x":3848,"y":1004,"w":55,"h":79,"rotated":false}},
|
||||
{"SPRITE":{"name":"192","x":3834,"y":1084,"w":50,"h":65,"rotated":false}},
|
||||
{"SPRITE":{"name":"193","x":3629,"y":808,"w":33,"h":43,"rotated":false}},
|
||||
{"SPRITE":{"name":"194","x":3493,"y":152,"w":26,"h":38,"rotated":false}},
|
||||
{"SPRITE":{"name":"195","x":3971,"y":585,"w":23,"h":33,"rotated":false}},
|
||||
{"SPRITE":{"name":"196","x":2530,"y":498,"w":20,"h":24,"rotated":false}},
|
||||
{"SPRITE":{"name":"197","x":3939,"y":755,"w":121,"h":50,"rotated":false}},
|
||||
{"SPRITE":{"name":"198","x":3913,"y":836,"w":133,"h":49,"rotated":false}},
|
||||
{"SPRITE":{"name":"199","x":3971,"y":449,"w":119,"h":69,"rotated":false}},
|
||||
{"SPRITE":{"name":"200","x":3072,"y":684,"w":253,"h":125,"rotated":false}},
|
||||
{"SPRITE":{"name":"201","x":3441,"y":600,"w":116,"h":135,"rotated":false}},
|
||||
{"SPRITE":{"name":"202","x":2475,"y":986,"w":194,"h":224,"rotated":false}},
|
||||
{"SPRITE":{"name":"203","x":1770,"y":2,"w":335,"h":225,"rotated":false}},
|
||||
{"SPRITE":{"name":"204","x":2157,"y":158,"w":217,"h":242,"rotated":false}},
|
||||
{"SPRITE":{"name":"205","x":3249,"y":810,"w":114,"h":150,"rotated":false}},
|
||||
{"SPRITE":{"name":"206","x":3326,"y":600,"w":114,"h":150,"rotated":false}},
|
||||
{"SPRITE":{"name":"207","x":3835,"y":670,"w":85,"h":87,"rotated":false}},
|
||||
{"SPRITE":{"name":"208","x":3671,"y":2,"w":129,"h":147,"rotated":false}},
|
||||
{"SPRITE":{"name":"209","x":2852,"y":650,"w":219,"h":163,"rotated":false}},
|
||||
{"SPRITE":{"name":"210","x":3338,"y":2,"w":154,"h":194,"rotated":false}},
|
||||
{"SPRITE":{"name":"211","x":1514,"y":272,"w":108,"h":68,"rotated":false}},
|
||||
{"SPRITE":{"name":"212","x":3664,"y":897,"w":132,"h":64,"rotated":false}},
|
||||
{"SPRITE":{"name":"213","x":2437,"y":1211,"w":160,"h":62,"rotated":false}},
|
||||
{"SPRITE":{"name":"214","x":3449,"y":935,"w":81,"h":188,"rotated":false}},
|
||||
{"SPRITE":{"name":"215","x":2841,"y":950,"w":200,"h":185,"rotated":false}},
|
||||
{"SPRITE":{"name":"216","x":3384,"y":1150,"w":63,"h":99,"rotated":false}},
|
||||
{"SPRITE":{"name":"217","x":2481,"y":398,"w":63,"h":99,"rotated":false}},
|
||||
{"SPRITE":{"name":"218","x":3558,"y":600,"w":132,"h":105,"rotated":false}},
|
||||
{"SPRITE":{"name":"219","x":3531,"y":856,"w":132,"h":105,"rotated":false}},
|
||||
{"SPRITE":{"name":"220","x":2590,"y":2,"w":231,"h":184,"rotated":false}},
|
||||
{"SPRITE":{"name":"221","x":2670,"y":950,"w":170,"h":224,"rotated":false}},
|
||||
{"SPRITE":{"name":"222","x":2273,"y":749,"w":198,"h":144,"rotated":false}},
|
||||
{"SPRITE":{"name":"223","x":3691,"y":962,"w":93,"h":53,"rotated":false}},
|
||||
{"SPRITE":{"name":"224","x":2979,"y":1183,"w":186,"h":91,"rotated":false}},
|
||||
{"SPRITE":{"name":"225","x":1939,"y":733,"w":333,"h":164,"rotated":false}},
|
||||
{"SPRITE":{"name":"226","x":935,"y":2,"w":415,"h":354,"rotated":false}},
|
||||
{"SPRITE":{"name":"227","x":1220,"y":357,"w":402,"h":353,"rotated":false}},
|
||||
{"SPRITE":{"name":"228","x":3998,"y":84,"w":90,"h":103,"rotated":false}},
|
||||
{"SPRITE":{"name":"229","x":2375,"y":158,"w":214,"h":239,"rotated":false}},
|
||||
{"SPRITE":{"name":"230","x":2262,"y":898,"w":212,"h":237,"rotated":false}}]},
|
||||
"meta":{
|
||||
"app":"Adobe Animate (Better TA Extension)",
|
||||
"version":"22.0.3.179",
|
||||
"image":"spritemap1.png",
|
||||
"format":"RGBA8888",
|
||||
"size":{"w":4096,"h":1280},
|
||||
"resolution":"1"
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 642 KiB After Width: | Height: | Size: 1.2 MiB |
@@ -203,6 +203,7 @@
|
||||
<str id="paste">Paste</str>
|
||||
<str id="cut">Cut</str>
|
||||
<str id="delete">Delete</str>
|
||||
<str id="deletestacked">Delete Stacked Notes</str>
|
||||
</group>
|
||||
|
||||
<str id="topBar.chart">Chart</str>
|
||||
@@ -223,6 +224,7 @@
|
||||
<str id="resetZoom">Reset Zoom</str>
|
||||
<str id="showSectionsSeparator">Show Sections Separator</str>
|
||||
<str id="showBeatsSeparator">Show Beats Separator</str>
|
||||
<str id="showCameraHighlights">Show Camera Highlights</str>
|
||||
<str id="rainbowWaveforms">Rainbow Waveforms</str>
|
||||
<str id="lowDetailWaveforms">Low Detail Waveforms</str>
|
||||
<str id="scrollLeft">Scroll Left</str>
|
||||
@@ -236,8 +238,9 @@
|
||||
<str id="goEnd">Go forward to the end</str> <!-- used to be "Go to the end" -->
|
||||
<str id="addOpponentCamera">Add camera on Opponent</str>
|
||||
<str id="addPlayerCamera">Add camera on Player</str>
|
||||
<str id="muteInst">Mute instrumental</str>
|
||||
<str id="muteVoices">Mute voices</str>
|
||||
<str id="inst">Instrumental</str>
|
||||
<str id="voices">Voices</str>
|
||||
<str id="hitsounds">Hitsounds</str>
|
||||
</group>
|
||||
|
||||
<group name="BookmarkMenu" prefix="bookmarks.">
|
||||
@@ -250,6 +253,7 @@
|
||||
<str id="editBookmarkListTitle">Bookmark List</str>
|
||||
<str id="editBookmarksTitle">Edit Bookmarks</str>
|
||||
<str id="newBookmarkName">New Bookmark</str>
|
||||
<str id="bookmarkList">Bookmark List</str>
|
||||
</group>
|
||||
|
||||
<str id="topBar.note">Note</str>
|
||||
@@ -258,6 +262,7 @@
|
||||
<str id="subtractSustainLength">Subtract sustain length</str>
|
||||
<str id="selectAll">Select all</str>
|
||||
<str id="selectMeasure">Select measure</str>
|
||||
<str id="noteTypesList">Note Types List</str>
|
||||
<str id="editNoteTypesList">Edit Note Types List</str>
|
||||
</group>
|
||||
<str id="topBar.snap">Snap</str>
|
||||
@@ -308,8 +313,9 @@
|
||||
<group name="StrumlineOptions" prefix="strumLine.">
|
||||
<str id="button-name">Options ↓</str>
|
||||
|
||||
<str id="waveforms">Waveforms</str>
|
||||
<str id="hitsounds">Hitsounds</str>
|
||||
<str id="muteVocals">Mute Vocals</str>
|
||||
<str id="vocals">Vocals</str>
|
||||
<str id="edit">Edit</str>
|
||||
<str id="delete">Delete</str>
|
||||
|
||||
@@ -433,6 +439,8 @@
|
||||
<str id="position">Position (X, Y)</str>
|
||||
<str id="fps">FPS</str>
|
||||
<str id="indices">Indices (Frames)</str>
|
||||
<str id="looping">Looping?</str>
|
||||
<str id="label">Label</str>
|
||||
</group>
|
||||
|
||||
<group name="CharacterSpriteScreen" prefix="characterSpriteScreen.">
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
<str id="category.engine">Engine</str>
|
||||
<group name="engine" prefix="engine.">
|
||||
<str id="switchMod">Switch Mod</str>
|
||||
<str id="fpsCounter">FPS Counter</str>
|
||||
</group>
|
||||
|
||||
<str id="category.volume">Volume</str>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
<str id="animation">Animación</str>
|
||||
<str id="atlas">Atlas</str>
|
||||
<str id="spritemap">Mapa de sprites</str>
|
||||
|
||||
|
||||
<str id="directory">Ubicación ({0}/)</str>
|
||||
<str id="found">{0} {1} Encontrado</str>
|
||||
<str id="foundplural">{0} {1} Encontrados</str>
|
||||
@@ -188,6 +188,7 @@
|
||||
<str id="paste">Pegar</str>
|
||||
<str id="cut">Cortar</str>
|
||||
<str id="delete">Eliminar</str>
|
||||
<str id="deletestacked">Eliminar Notas Apiladas</str>
|
||||
</group>
|
||||
|
||||
<str id="topBar.chart">Chart</str>
|
||||
|
||||
@@ -46,8 +46,9 @@
|
||||
|
||||
<group name="engine" prefix="engine.">
|
||||
<str id="switchMod">Cambiar Mod</str>
|
||||
<str id="fpsCounter">Contador de FPS</str>
|
||||
</group>
|
||||
|
||||
|
||||
<str id="category.volume">Volumen</str>
|
||||
<str id="volume.up">Arriba</str>
|
||||
<str id="volume.down">Abajo</str>
|
||||
|
||||
@@ -194,6 +194,7 @@
|
||||
<str id="paste">Incolla</str>
|
||||
<str id="cut">Taglia</str>
|
||||
<str id="delete">Elimina</str>
|
||||
<str id="deletestacked">Elimina Note Impilate</str>
|
||||
</group>
|
||||
|
||||
<str id="topBar.chart">Chart</str>
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
|
||||
<group name="engine" prefix="engine.">
|
||||
<str id="switchMod">Cambia Mod</str>
|
||||
<str id="fpsCounter">Contatore FPS</str>
|
||||
</group>
|
||||
|
||||
<str id="volume.up">Su</str>
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
<str id="animation">Animacja</str>
|
||||
<str id="atlas">Atlas</str>
|
||||
<str id="spritemap">Mapa sprite'ów</str>
|
||||
|
||||
|
||||
<str id="directory">Folder ({0}/)</str>
|
||||
<str id="found">{0} {1} Znaleziono</str>
|
||||
<str id="foundplural">{0} {1} Znaleziono</str>
|
||||
@@ -87,7 +87,7 @@
|
||||
<group name="CharterEventScreen" prefix="charterEventScreen.">
|
||||
<str id="title-creating">Stwórz Grupę Wydarzeń</str>
|
||||
<str id="title-editing">Edytuj Grupę Wydarzeń</str>
|
||||
|
||||
|
||||
<str id="noEvent">Brak Wydarzenia</str>
|
||||
|
||||
<str id="strumLine.format">Struma #{0} ({1})</str>
|
||||
@@ -197,6 +197,7 @@
|
||||
<str id="paste">Wklej</str>
|
||||
<str id="cut">Wytnij</str>
|
||||
<str id="delete">Usuń</str>
|
||||
<str id="deletestacked">Usuń Notatki Ułożone w Stos</str>
|
||||
</group>
|
||||
|
||||
<str id="topBar.chart">Mapa</str>
|
||||
@@ -223,7 +224,7 @@
|
||||
<str id="scrollRight">Przewiń w Prawo</str>
|
||||
<str id="scrollReset">Resetuj Przewinięcie</str>
|
||||
</group>
|
||||
|
||||
|
||||
<str id="topBar.song">Ścieżka</str>
|
||||
<group name="SongMenu" prefix="song.">
|
||||
<str id="goStart">Wróć do początku</str>
|
||||
|
||||
@@ -44,8 +44,9 @@
|
||||
<str id="category.engine">Silnik</str>
|
||||
<group name="engine" prefix="engine.">
|
||||
<str id="switchMod">Zmień Moda</str>
|
||||
<str id="fpsCounter">Licznik FPS</str>
|
||||
</group>
|
||||
|
||||
|
||||
<str id="category.volume">Głośność</str>
|
||||
<str id="volume.up">Głóśniej</str>
|
||||
<str id="volume.down">Ciszej</str>
|
||||
|
||||
@@ -203,6 +203,7 @@
|
||||
<str id="paste">Colar</str>
|
||||
<str id="cut">Cortar</str>
|
||||
<str id="delete">Apagar</str>
|
||||
<str id="deletestacked">Apagar Notas Empilhadas</str>
|
||||
</group>
|
||||
|
||||
<str id="topBar.chart">Mapa</str>
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
<str id="category.engine">Codename Engine</str>
|
||||
<group name="engine" prefix="engine.">
|
||||
<str id="switchMod">Trocar Mod</str>
|
||||
<str id="fpsCounter">Contador de FPS</str>
|
||||
</group>
|
||||
|
||||
<str id="category.volume">Volume</str>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#pragma header
|
||||
|
||||
// Used in charter by waveforms
|
||||
#version 120 // this shader doesnt require expensive calculations
|
||||
|
||||
const vec3 gradient1 = vec3(114.0/255.0, 81.0/255.0, 135.0/255.0);
|
||||
const vec3 gradient2 = vec3(144.0/255.0, 80.0/255.0, 186.0/255.0);
|
||||
@@ -18,6 +17,21 @@ uniform vec2 waveformSize;
|
||||
|
||||
uniform bool lowDetail;
|
||||
|
||||
float catmullRom(
|
||||
float p0, float p1, float p2, float p3,
|
||||
float t
|
||||
) {
|
||||
float t2 = t * t;
|
||||
float t3 = t2 * t;
|
||||
|
||||
return 0.5 * (
|
||||
(2.0 * p1) +
|
||||
(-p0 + p2) * t +
|
||||
(2.0*p0 - 5.0*p1 + 4.0*p2 - p3) * t2 +
|
||||
(-p0 + 3.0*p1 - 3.0*p2 + p3) * t3
|
||||
);
|
||||
}
|
||||
|
||||
float getAmplitude(vec2 pixel) {
|
||||
float pixelID = floor((pixel.y+pixelOffset)/3.0);
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ function create() {
|
||||
tankman = new FunkinSprite(game.dad.x + game.dad.globalOffset.x + 520, game.dad.y + game.dad.globalOffset.y + 225);
|
||||
tankman.antialiasing = true;
|
||||
tankman.loadSprite(Paths.image('game/cutscenes/tank/guns-tankman'));
|
||||
tankman.animateAtlas.anim.addBySymbol('tank', 'TANK TALK 2', 0, false);
|
||||
tankman.addAnim('tank', 'TANK TALK 2', 0, false);
|
||||
|
||||
game.insert(game.members.indexOf(game.dad), tankman);
|
||||
game.dad.visible = false;
|
||||
@@ -65,4 +65,4 @@ function destroy() {
|
||||
for(thing in [tankman, tankTalk]) thing.destroy();
|
||||
if(destroyDistorto) distorto.destroy();
|
||||
FlxTween.tween(FlxG.camera, {zoom: game.defaultCamZoom}, 0.7, {ease: FlxEase.quadInOut, startDelay: 0});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,20 +33,20 @@ function create() {
|
||||
tankman = new FunkinSprite(game.dad.x + game.dad.globalOffset.x + 520, game.dad.y + game.dad.globalOffset.y + 225);
|
||||
tankman.antialiasing = true;
|
||||
tankman.loadSprite(Paths.image('game/cutscenes/tank/stress-tankman'));
|
||||
tankman.animateAtlas.anim.addBySymbol('p1', 'TANK TALK 3 P1 UNCUT', 0, false);
|
||||
tankman.animateAtlas.anim.addBySymbol('p2', 'TANK TALK 3 P2 UNCUT', 0, false);
|
||||
tankman.addAnim('p1', 'TANK TALK 3 P1 UNCUT', 0, false);
|
||||
tankman.addAnim('p2', 'TANK TALK 3 P2 UNCUT', 0, false);
|
||||
tankman.playAnim('p1');
|
||||
|
||||
pico = new FunkinSprite(game.gf.x + game.gf.globalOffset.x + 150, game.gf.y + game.gf.globalOffset.y + 395);
|
||||
pico = new FunkinSprite(game.gf.x + game.gf.globalOffset.x - 615, game.gf.y + game.gf.globalOffset.y - 130);
|
||||
pico.antialiasing = true;
|
||||
pico.loadSprite(Paths.image('game/cutscenes/tank/stress-pico'));
|
||||
pico.animateAtlas.anim.addBySymbol('die', 'GF Time to Die sequence', 24, false);
|
||||
pico.animateAtlas.anim.addBySymbol('saves', 'Pico Saves them sequence', 24, false);
|
||||
pico.animateAtlas.anim.addBySymbol('idle', 'Pico Dual Wield on Speaker idle', 24, true);
|
||||
pico.addAnim('die', 'die', 24, false, null, null, 0, 0, null, true);
|
||||
pico.addAnim('saves', 'saves', 24, false, null, null, 0, 0, null, true);
|
||||
pico.addAnim('idle', 'idle', 24, true, null, null, 0, 0, null, true);
|
||||
pico.scrollFactor.set(0.95, 0.95);
|
||||
pico.playAnim("idle");
|
||||
pico.visible = false;
|
||||
game.insert(game.members.indexOf(game.gf) + 1, pico);
|
||||
game.insert(game.members.indexOf(game.gf) + 2, pico);
|
||||
|
||||
game.insert(game.members.indexOf(game.dad) + 1, tankman);
|
||||
game.dad.visible = false;
|
||||
@@ -59,7 +59,11 @@ function update(elapsed) {
|
||||
lipSync(tankman, 0, 16750);
|
||||
if (stressCutscene.time > 15100) {
|
||||
step = 1;
|
||||
focusOn(game.gf);
|
||||
|
||||
//focusOn(game.gf);
|
||||
game.camFollow.x += 350;
|
||||
game.camFollow.y -= 200;
|
||||
|
||||
pico.visible = true;
|
||||
pico.playAnim('die', true);
|
||||
|
||||
@@ -118,7 +122,7 @@ function update(elapsed) {
|
||||
}
|
||||
|
||||
function lipSync(char:FunkinSprite, begin:Float, end:Float) {
|
||||
char.animateAtlas.anim.curFrame = Std.int(FlxMath.remapToRange(stressCutscene.time, begin, end, 0, char.animateAtlas.anim.length-1));
|
||||
char.anim.curAnim.curFrame = Std.int(FlxMath.remapToRange(stressCutscene.time, begin, end, 0, char.anim.curAnim.numFrames - 1));
|
||||
}
|
||||
|
||||
function focusOn(char, snap:Bool = false) {
|
||||
|
||||
@@ -12,8 +12,8 @@ function create() {
|
||||
tankman = new FunkinSprite(game.dad.x + game.dad.globalOffset.x + 520, game.dad.y + game.dad.globalOffset.y + 225);
|
||||
tankman.antialiasing = true;
|
||||
tankman.loadSprite(Paths.image('game/cutscenes/tank/ugh-tankman'));
|
||||
tankman.animateAtlas.anim.addBySymbol('1', 'TANK TALK 1 P1', 0, false);
|
||||
tankman.animateAtlas.anim.addBySymbol('2', 'TANK TALK 1 P2', 0, false);
|
||||
tankman.addAnim('1', 'TANK TALK 1 P1', 0, false);
|
||||
tankman.addAnim('2', 'TANK TALK 1 P2', 0, false);
|
||||
|
||||
game.insert(game.members.indexOf(game.dad), tankman);
|
||||
game.dad.visible = false;
|
||||
@@ -77,4 +77,4 @@ function destroy() {
|
||||
for(timer in timers) timer.cancel();
|
||||
for(thing in [tankTalk1, tankTalk2, bfBeep, tankman]) thing.destroy();
|
||||
if(destroyDistorto) distorto.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Here's the full guide on how to setup and compile Codename Engine!<br>
|
||||
|
||||
> **Open the instructions for your platform**
|
||||
# Compiling Codename Engine
|
||||
Do you want to turn your source code into a playable build to play? Then you want to **compile the source code**, follow this guide.
|
||||
> **Open the instructions for your platform.**
|
||||
<details>
|
||||
<summary>Windows</summary>
|
||||
|
||||
@@ -38,3 +38,22 @@ Here's the full guide on how to setup and compile Codename Engine!<br>
|
||||
> You can also run `./cne-windows.bat -help` or `./cne-unix.sh -help` (depending on your platform) to check out more useful commands!<br>
|
||||
> For example `./cne-windows test` or `./cne-unix.sh test` builds the game and uses the source assets folder instead of the export one for easier development (although you can still use `lime test` normally).
|
||||
> - If you're running the terminal from the project's main folder, use instead `./building/cne-windows.bat -COMMAND HERE` or `./building/cne-unix.sh -COMMAND HERE` depending on your platform.
|
||||
|
||||
# Generating Codename Engine's API documentation
|
||||
**Mainly recommended if you intend to fork the engine and make your own custom version to publish.**<br>Do you want to generate an API documentation so people can understand and mod your playable build? This documentation can be uploaded to your website.<br>If you just want to compile the engine normally for your hardcoded mod or for yourself you can skip this step.
|
||||
> **Select your platform to continue.**
|
||||
<details>
|
||||
<summary>Windows</summary>
|
||||
|
||||
1. Run `generate-docs-windows.bat` using cmd or double-clicking it and wait for the `doc.xml` to be generated inside the `docs` folder.
|
||||
</details>
|
||||
<details>
|
||||
<summary>MacOS/Linux</summary>
|
||||
|
||||
1. Run `generate-docs-unix.sh` using the terminal or double-clicking it and wait for the `doc.xml` to be generated inside the `docs` folder.
|
||||
</details>
|
||||
|
||||
2. You can use this `doc.xml` file to generate a full HTML documentation (that you can open in your browser for example) using Haxe's [dox](https://github.com/HaxeFoundation/dox) generator; check [Codename Engine's webiste](https://github.com/CodenameCrew/codename-website/tree/main/api-generator) for example.
|
||||
|
||||
> [!CAUTION]
|
||||
> The doc.xml might contain some sensible paths of your computer: make sure to filter the file before publishing it for everyone if you want to keep those paths private!<br>To filter and delete those paths, you may use Codename Engine's website's [doc filter Python script](https://github.com/CodenameCrew/codename-website/blob/main/api-generator/api/filter.py) by simply running it in the same folder of your `doc.xml` file. This script will also delete everything irrelevant to the engine that was generated in your documentation, such as libraries' (like OpenFL or Flixel) APIs.
|
||||
@@ -1,14 +0,0 @@
|
||||
[general]
|
||||
sample-type=float32
|
||||
stereo-mode=speakers
|
||||
stereo-encoding=panpot
|
||||
hrtf=false
|
||||
cf_level=0
|
||||
resampler=fast_bsinc24
|
||||
front-stablizer=false
|
||||
output-limiter=false
|
||||
volume-adjust=0
|
||||
[decoder]
|
||||
hq-mode=false
|
||||
distance-comp=false
|
||||
nfc=false
|
||||
@@ -0,0 +1,13 @@
|
||||
#!/usr/bin/env sh
|
||||
cd "$(dirname "$0")/.."
|
||||
echo "Generating documentation..."
|
||||
if [ $(uname) == "Darwin" ]; then
|
||||
echo "Platform is macOS"
|
||||
haxelib run lime build mac --haxeflag="-xml docs/doc.xml" -D doc-gen -D DOCUMENTATION --no-output
|
||||
else
|
||||
echo "Platform is not macOS; assuming platform to be Linux compatible"
|
||||
haxelib run lime build linux --haxeflag="-xml docs/doc.xml" -D doc-gen -D DOCUMENTATION --no-output
|
||||
fi
|
||||
|
||||
echo "The XML file for the API documentation has been generated at docs/doc.xml."
|
||||
echo "For updating the API documentation hosted at the website, please replace codename-website/api-generator/api/doc.xml with the file listed above."
|
||||
@@ -0,0 +1,8 @@
|
||||
@ECHO OFF
|
||||
cd /d "%~dp0.."
|
||||
echo Generating documentation...
|
||||
echo Platform is based on Windows
|
||||
haxelib run lime build windows --haxeflag="-xml docs/doc.xml" -D doc-gen -D DOCUMENTATION --no-output
|
||||
|
||||
echo The XML file for the API documentation has been generated at docs/doc.xml.
|
||||
echo For updating the API documentation hosted at the website, please replace codename-website/api-generator/api/doc.xml with the file listed above.
|
||||
@@ -3,35 +3,32 @@
|
||||
<if cond="update || all">
|
||||
<print pretty="true">Preparing installation...</print>
|
||||
|
||||
<!-- OpenFL & Lime (Required for Flixel) -->
|
||||
<git name="openfl" url="https://github.com/CodenameCrew/cne-openfl" />
|
||||
<lib name="lime" version="8.1.2" />
|
||||
<!-- <git name="lime" url="https://github.com/CodenameCrew/cne-lime" /> disabled for now until fixed -->
|
||||
<!-- Hxcpp & OpenFL & Lime (Required for Flixel) -->
|
||||
<git name="hxcpp" url="https://github.com/CodenameCrew/cne-hxcpp"/>
|
||||
<git name="openfl" url="https://github.com/CodenameCrew/cne-openfl" ref="cne" skipDeps="true"/>
|
||||
<git name="lime" url="https://github.com/CodenameCrew/cne-lime" ref="cne" skipDeps="true"/>
|
||||
|
||||
<!-- Flixel -->
|
||||
<git name="flixel" url="https://github.com/CodenameCrew/cne-flixel" />
|
||||
<git name="flixel-addons" url="https://github.com/CodenameCrew/cne-flixel-addons" />
|
||||
<git name="flixel" url="https://github.com/CodenameCrew/cne-flixel" ref="cne" skipDeps="true"/>
|
||||
<git name="flixel-addons" url="https://github.com/CodenameCrew/cne-flixel-addons" ref="dev" skipDeps="true"/>
|
||||
|
||||
<!-- CNE Core Libraries -->
|
||||
<git name="flixel-animate" url="https://github.com/CodenameCrew/cne-flixel-animate" skipDeps="true"/>
|
||||
<git name="hscript-improved" url="https://github.com/CodenameCrew/hscript-improved" ref="codename-dev"/>
|
||||
<git name="away3d" url="https://github.com/CodenameCrew/away3d" skipDeps="true"/>
|
||||
|
||||
<!-- Other Libraries -->
|
||||
<git name="hscript-improved" url="https://github.com/CodenameCrew/hscript-improved" ref="codename-dev" />
|
||||
<git name="flxanimate" url="https://github.com/CodenameCrew/cne-flxanimate" />
|
||||
<git name="hxdiscord_rpc" url="https://github.com/CodenameCrew/cne-hxdiscord_rpc" skipDeps="true" />
|
||||
<git name="funkin-modchart" url="https://github.com/TheoDevelops/FunkinModchart" ref="f30676579d8de7ccac7d12e13b664e8b2c42c6bf" skipDeps="true" />
|
||||
<lib name="hxvlc" version="1.9.3" skipDeps="true" />
|
||||
|
||||
<!-- Documentation and other features -->
|
||||
<git name="away3d" url="https://github.com/CodenameCrew/away3d" />
|
||||
<!-- <lib name="dox" /> -->
|
||||
<lib name="markdown" />
|
||||
<lib name="hxcpp-debug-server" />
|
||||
|
||||
<lib name="nape-haxe4" />
|
||||
<git name="hxdiscord_rpc" url="https://github.com/CodenameCrew/cne-hxdiscord_rpc" skipDeps="true"/>
|
||||
<git name="hxvlc" url="https://github.com/CodenameCrew/cne-hxvlc" skipDeps="true"/>
|
||||
<lib name="funkin-modchart" skipDeps="true"/>
|
||||
<lib name="hxcpp-debug-server"/>
|
||||
<lib name="format"/>
|
||||
<lib name="markdown"/>
|
||||
<lib name="nape-haxe4"/>
|
||||
|
||||
<!-- For building lime -->
|
||||
<lib global="true" name="hxp" /> <lib name="hxp" />
|
||||
<lib global="true" name="format" /> <lib name="format" />
|
||||
|
||||
<git name="hxcpp" url="https://github.com/CodenameCrew/cne-hxcpp" />
|
||||
<!-- <lib global="true" name="hxp"/> <lib name="hxp"/> -->
|
||||
<!-- <lib global="true" name="format"/> <lib name="format"/> -->
|
||||
</if>
|
||||
|
||||
<!-- Hxcpp Building -->
|
||||
@@ -40,15 +37,16 @@
|
||||
|
||||
<!-- Build hxcpp -->
|
||||
<cmd inLib="hxcpp" dir="tools/hxcpp" cmd="haxe compile.hxml" />
|
||||
<cmd inLib="lime" cmd="haxelib run lime rebuild hxcpp"/>
|
||||
</if>
|
||||
|
||||
<!-- Lime Building -->
|
||||
<!-- <if cond="build-lime || all">
|
||||
<if cond="build-lime">
|
||||
<print pretty="true">Rebuilding Lime...</print>
|
||||
|
||||
<!- - Build lime - ->
|
||||
<cmd inLib="lime" cmd="haxelib run lime rebuild . $PLATFORM -release -clean" />
|
||||
<cmd inLib="lime" dir="tools" cmd="haxe tools.hxml" />
|
||||
</if> -->
|
||||
<!-- Build lime -->
|
||||
<cmd inLib="lime" dir="tools" cmd="haxe tools.hxml"/>
|
||||
<cmd inLib="lime" cmd="haxelib run lime rebuild $PLATFORM -nocolor -nocffi -release"/>
|
||||
</if>
|
||||
|
||||
</libraries>
|
||||
|
||||
@@ -1,81 +1,54 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<project>
|
||||
<!-- _________________________ Application Settings _________________________ -->
|
||||
<app
|
||||
title="Friday Night Funkin' - Codename Engine" main="funkin.backend.system.Main"
|
||||
file="CodenameEngine" packageName="com.yoshman29.codenameengine"
|
||||
package="com.yoshman29.codenameengine"
|
||||
version="1.0.1" company="Yoshman29" />
|
||||
<project xmlns="http://lime.software/project/1.0.4" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://lime.software/project/1.0.4 http://lime.software/xsd/project-1.0.4.xsd">
|
||||
<!-- ____________________________ Window Settings ___________________________ -->
|
||||
|
||||
<!--
|
||||
CHANGE THE SAVE PATH & NAME FOR YOUR MOD HERE!
|
||||
-->
|
||||
<!-- CHANGE THE SAVE PATH & NAME FOR YOUR MOD HERE! -->
|
||||
<haxedef name="SAVE_PATH" value="CodenameEngine"/>
|
||||
<haxedef name="SAVE_NAME" value="save-default"/>
|
||||
|
||||
<haxedef name="SAVE_OPTIONS_PATH" value="CodenameEngine"/>
|
||||
<haxedef name="SAVE_OPTIONS_NAME" value="options"/>
|
||||
|
||||
<!--Switch Export with Unique ApplicationID and Icon-->
|
||||
<set name="APP_ID" value="0x0100f6c013bbc000" />
|
||||
<!-- Comment this out to disable commit number on FPS -->
|
||||
<define name="SHOW_BUILD_ON_FPS"/>
|
||||
|
||||
<!-- DO NOT REMOVE!! ALLOWS ME TO DO REGIONS LIKE IN C# AND KEEP CODE ORGANIZED. REMOVING IT WOULD BREAK THE ENGINE -->
|
||||
<haxedef name="REGION" />
|
||||
<!-- Comment this out to disable dark mode windows -->
|
||||
<define name="DARK_MODE_WINDOW"/>
|
||||
|
||||
<!--The flixel preloader is not accurate in Chrome. You can use it regularly if you embed the swf into a html file
|
||||
or you can set the actual size of your file manually at "FlxPreloaderBase-onUpdate-bytesTotal"-->
|
||||
<app preloader="flixel.system.FlxPreloader" />
|
||||
<!-- Should it checks for updates? -->
|
||||
<define name="UPDATE_CHECKING" if="desktop" unless="hl || debug"/>
|
||||
|
||||
<!--Minimum without FLX_NO_GAMEPAD: 11.8, without FLX_NO_NATIVE_CURSOR: 11.2-->
|
||||
<set name="SWF_VERSION" value="11.8" />
|
||||
|
||||
<!-- ____________________________ Window Settings ___________________________ -->
|
||||
|
||||
<!--These window settings apply to all targets-->
|
||||
<window width="1280" height="720" background="#000000" hardware="true" vsync="false" />
|
||||
|
||||
<!--HTML5-specific-->
|
||||
<window if="html5" resizable="true" />
|
||||
|
||||
<!--Desktop-specific-->
|
||||
<window if="desktop" orientation="landscape" fullscreen="false" resizable="true" vsync="false"/>
|
||||
<window if="mac" allow-high-dpi="true" />
|
||||
|
||||
<!--Mobile-specific-->
|
||||
<window if="mobile" orientation="landscape" fullscreen="true" width="0" height="0" resizable="false"/>
|
||||
|
||||
<!--Switch-specific-->
|
||||
<window if="switch" orientation="landscape" fullscreen="true" width="0" height="0" resizable="true" />
|
||||
|
||||
<!-- _________________________________ Engine Settings _______________________________ -->
|
||||
|
||||
<!-- Comment this out to disable updates !-->
|
||||
<define name="UPDATE_CHECKING" unless="web || hl || neko"/>
|
||||
|
||||
<!-- Comment this out to disable Discord RPC !-->
|
||||
<section if="cpp">
|
||||
<define name="DISCORD_RPC" if="desktop"/>
|
||||
<!-- Compile With Discord Rich Presence -->
|
||||
<!-- TODO: Update Discord RPC Library & Rewrite DiscordUtil -->
|
||||
<!-- <define name="DISCORD_RPC" if="desktop"/> -->
|
||||
|
||||
<!-- Compile with video support (hxvlc) -->
|
||||
<define name="VIDEO_CUTSCENES" if="desktop || mobile"/>
|
||||
</section>
|
||||
|
||||
<!-- Uncomment this to achive faster compile times, will strip extraneous and commonly unused features. -->
|
||||
<!-- <define name="STRIPPED_COMPILE" unless="debug"/> -->
|
||||
|
||||
<!-- Comment this out to disable modcharting features -->
|
||||
<define name="MODCHARTING_FEATURES" unless="STRIPPED_COMPILE" />
|
||||
<!-- Compile with _theo0p's modcharting tools -->
|
||||
<define name="MODCHARTING_FEATURES" unless="STRIPPED_COMPILE"/>
|
||||
|
||||
<!-- Comment this out to disable GitHub API integration !-->
|
||||
<define name="GITHUB_API" unless="web || hl"/>
|
||||
|
||||
<!-- Comment this out to prevent unused classes from being compiled.
|
||||
Reduces compilation time at the cost of limited HScript flexibility. !-->
|
||||
<define name="COMPILE_ALL_CLASSES" unless="STRIPPED_COMPILE" />
|
||||
<define name="COMPILE_ALL_CLASSES" unless="STRIPPED_COMPILE"/>
|
||||
|
||||
<!-- Comment this out to prevent extending classes in hscript.
|
||||
Reduces compilation time at the cost of limited HScript flexibility. !-->
|
||||
<define name="CUSTOM_CLASSES" unless="STRIPPED_COMPILE" />
|
||||
<define name="CUSTOM_CLASSES" unless="STRIPPED_COMPILE"/>
|
||||
|
||||
<!-- Comment this out to disable abstract support in hscript. !-->
|
||||
<haxedef name="HSCRIPT_ABSTRACT_SUPPORT" unless="STRIPPED_COMPILE" />
|
||||
|
||||
<!-- Comment this out to disable multithreading !-->
|
||||
<haxedef name="ALLOW_MULTITHREADING" unless="web || flash" />
|
||||
<haxedef name="ALLOW_MULTITHREADING" if="cpp"/>
|
||||
|
||||
<!-- Comment this out to disable mods folder !-->
|
||||
<haxedef name="MOD_SUPPORT" unless="web"/>
|
||||
@@ -84,36 +57,60 @@
|
||||
<haxedef name="TRANSLATIONS_SUPPORT"/>
|
||||
|
||||
<!-- Comment this out to disable global scripts !-->
|
||||
<haxedef name="GLOBAL_SCRIPT" />
|
||||
<haxedef name="GLOBAL_SCRIPT"/>
|
||||
|
||||
<!-- Comment this out to disable softcoded states and state scripting !-->
|
||||
<haxedef name="SOFTCODED_STATES" />
|
||||
<haxedef name="SOFTCODED_STATES"/>
|
||||
|
||||
<!-- Comment this out to disable support for custom ndlls. !-->
|
||||
<haxedef name="NDLLS_SUPPORTED" unless="web || iphonesim || hl" />
|
||||
<haxedef name="NDLLS_SUPPORTED" unless="web || iphonesim || hl"/>
|
||||
|
||||
<!-- Comment this out to use the default OpenFL assets system for the assets/ folder. !-->
|
||||
<define name="USE_ADAPTED_ASSETS" unless="web" />
|
||||
<define name="USE_ADAPTED_ASSETS" unless="web"/>
|
||||
|
||||
<!-- Comment this out to disable support for Away3D Flixel Integration (reduces compile times) !-->
|
||||
<define name="THREE_D_SUPPORT" unless="STRIPPED_COMPILE" />
|
||||
<define name="THREE_D_SUPPORT" unless="STRIPPED_COMPILE"/>
|
||||
|
||||
<!-- Comment this out to disable support for Nape integration (flixel.addons.nape) (reduces compile times) !-->
|
||||
<define name="NAPE_ENABLED" unless="STRIPPED_COMPILE" />
|
||||
|
||||
<!-- Comment this out to disable video cutscene support, in case of compilation errors. !-->
|
||||
<section if="cpp">
|
||||
<define name="VIDEO_CUTSCENES" if="desktop || android" />
|
||||
</section>
|
||||
|
||||
<!-- Comment this out to disable commit number on FPS -->
|
||||
<define name="SHOW_BUILD_ON_FPS" />
|
||||
|
||||
<!-- Comment this out to disable dark mode windows -->
|
||||
<define name="DARK_MODE_WINDOW"/>
|
||||
<define name="NAPE_ENABLED" unless="STRIPPED_COMPILE"/>
|
||||
|
||||
<!-- Disable a optimization, to allow reflection to use more functions -->
|
||||
<define name="FLX_NO_GENERIC" />
|
||||
<define name="FLX_NO_GENERIC"/>
|
||||
|
||||
<!-- _________________________ Application Settings _________________________ -->
|
||||
<app
|
||||
title="Friday Night Funkin' - Codename Engine"
|
||||
file="CodenameEngine" packageName="com.yoshman29.codenameengine"
|
||||
package="com.yoshman29.codenameengine"
|
||||
version="1.0.2" company="Yoshman29"/>
|
||||
|
||||
<!--Switch Export with Unique ApplicationID and Icon-->
|
||||
<set name="APP_ID" value="0x0100f6c013bbc000"/>
|
||||
|
||||
<!--<set name="SWF_VERSION" value="11.8"/>-->
|
||||
|
||||
<!--Place custom nodes like icons here (higher priority to override the HaxeFlixel icon)-->
|
||||
<icon path="art/icon16.png" size='16'/>
|
||||
<icon path="art/icon32.png" size='24'/>
|
||||
<icon path="art/icon32.png" size='32'/>
|
||||
<icon path="art/icon64.png" size='40'/>
|
||||
<icon path="art/icon64.png" size='48'/>
|
||||
<icon path="art/icon64.png" size='64'/>
|
||||
<icon path="art/iconOG.png" size='96'/>
|
||||
<icon path="art/iconOG.png" size='128'/>
|
||||
<icon path="art/iconOG.png" size='196'/>
|
||||
<icon path="art/iconOG.png" size='256'/>
|
||||
<icon path="art/iconOG.png" size='512'/>
|
||||
<icon path="art/iconOG.png" size='768'/>
|
||||
<icon path="art/iconOG.png" size='1024'/>
|
||||
|
||||
<!-- ____________________________ Window Settings ___________________________ -->
|
||||
|
||||
<window hardware="true" colorDepth="32" background="" fps="0" orientation="landscape"/>
|
||||
<window unless="desktop" width="0" height="0" vsync="true" fullscreen="true"/>
|
||||
<window if="desktop" type="opengl" width="1280" height="720" fullscreen="false" resizable="true" vsync="false" allowHighDPI="true"/>
|
||||
<window if="mobile" resizable="false"/>
|
||||
<window if="html5 || switch" resizable="true"/>
|
||||
|
||||
<!-- _______________________________ Libraries ______________________________ -->
|
||||
|
||||
@@ -121,32 +118,46 @@
|
||||
<define name="disable-version-check"/>
|
||||
<haxedef name="disable-version-check"/>
|
||||
|
||||
<haxedef name="no-deprecation-warnings"/>
|
||||
<haxedef name="DISCORD_DISABLE_IO_THREAD" if="DISCORD_RPC"/>
|
||||
<haxelib name="flixel"/>
|
||||
|
||||
<haxelib name="flixel" />
|
||||
<haxelib name="flixel-addons" />
|
||||
<haxelib name="flixel-addons"/>
|
||||
<haxelib name="flixel-animate"/>
|
||||
|
||||
<haxelib name="hxvlc" if="VIDEO_CUTSCENES" />
|
||||
<haxelib name="away3d" if="THREE_D_SUPPORT" />
|
||||
<haxelib name="format" />
|
||||
<haxelib name="flxanimate" />
|
||||
<haxelib name="hscript-improved"/>
|
||||
|
||||
<haxelib name="format" unless="STRIPPED_COMPILE"/>
|
||||
<haxelib name="markdown" unless="STRIPPED_COMPILE"/>
|
||||
|
||||
<haxelib name="hxvlc" if="VIDEO_CUTSCENES"/>
|
||||
<haxelib name="hxdiscord_rpc" if="DISCORD_RPC"/>
|
||||
<haxelib name="away3d" if="THREE_D_SUPPORT"/>
|
||||
<haxelib name="nape-haxe4" if="NAPE_ENABLED"/>
|
||||
|
||||
<haxelib name="hscript-improved" />
|
||||
<haxelib name="hxdiscord_rpc" if="DISCORD_RPC"/>
|
||||
<haxelib name="markdown" />
|
||||
<haxelib name="hxcpp-debug-server" if="TEST_BUILD debug" />
|
||||
<haxelib name="hxcpp-debug-server" if="debug"/>
|
||||
|
||||
<!-- _____________________________ Path Settings ____________________________ -->
|
||||
<!-- ____________________________ Source Settings ___________________________ -->
|
||||
|
||||
<set name="BUILD_DIR" value="export/debug" if="debug" />
|
||||
<set name="BUILD_DIR" value="export/release" unless="debug" />
|
||||
<set name="BUILD_DIR" value="export/debug-32bit" if="debug 32bit" />
|
||||
<set name="BUILD_DIR" value="export/release-32bit" if="32bit" unless="debug" />
|
||||
<set name="BUILD_DIR" value="latest/" if="beta" />
|
||||
<!-- DO NO REMOVE THIS -->
|
||||
<haxedef name="REGION"/>
|
||||
|
||||
<source name="source" />
|
||||
<set name="BUILD_DIR" value="export/debug" if="debug"/>
|
||||
<set name="BUILD_DIR" value="export/release" unless="debug"/>
|
||||
<set name="BUILD_DIR" value="export/debug-32bit" if="debug 32bit"/>
|
||||
<set name="BUILD_DIR" value="export/release-32bit" if="32bit" unless="debug"/>
|
||||
<set name="BUILD_DIR" value="latest/" if="beta"/>
|
||||
|
||||
<app main="funkin.backend.system.Main" preloader="flixel.system.FlxPreloader"/>
|
||||
<source name="source"/>
|
||||
|
||||
<section if="MODCHARTING_FEATURES">
|
||||
<haxedef name="FM_ENGINE" value="CODENAME"/>
|
||||
<haxedef name="FM_ENGINE_VERSION" value="1.0"/>
|
||||
|
||||
<haxelib name="funkin-modchart" />
|
||||
<haxeflag name="--macro" value="modchart.backend.macros.Macro.includeFiles()"/>
|
||||
</section>
|
||||
|
||||
<!-- ____________________________ Assets Settings ___________________________ -->
|
||||
|
||||
<define name="PRELOAD_ALL" unless="web" />
|
||||
<define name="NO_PRELOAD_ALL" unless="PRELOAD_ALL"/>
|
||||
@@ -162,78 +173,69 @@
|
||||
<assets path='mods' rename='mods' embed='false' />
|
||||
</section>
|
||||
|
||||
<assets path='art/readme.txt' rename='do NOT readme.txt' />
|
||||
|
||||
<!-- OpenAL config -->
|
||||
<section if="desktop">
|
||||
<assets path="building/alsoft.txt" rename="plugins/alsoft.ini" type="text" if="windows"/>
|
||||
<assets path="building/alsoft.txt" rename="plugins/alsoft.conf" type="text" unless="windows"/>
|
||||
</section>
|
||||
<!-- <assets path='art/readme.txt' rename='do NOT readme.txt' /> -->
|
||||
|
||||
<!-- ______________________________ Haxedefines _____________________________ -->
|
||||
|
||||
<haxeflag name="--macro" value="funkin.backend.system.macros.BuildInfo.printBuildInfo()" />
|
||||
<haxeflag name="--macro" value="funkin.backend.system.macros.Macros.initMacros()"/>
|
||||
|
||||
<haxedef name="FLX_NO_FOCUS_LOST_SCREEN" />
|
||||
<haxedef name="VIDEO_CUTSCENES" if="VIDEO_CUTSCENES"/>
|
||||
<haxedef name="UPDATE_CHECKING" if="UPDATE_CHECKING"/>
|
||||
<haxedef name="DISCORD_RPC" if="DISCORD_RPC"/>
|
||||
<haxedef name="SHOW_BUILD_ON_FPS" if="SHOW_BUILD_ON_FPS"/>
|
||||
<haxedef name="SOFTCODED_CLASSES" if="SOFTCODED_CLASSES"/>
|
||||
<haxedef name="USE_ADAPTED_ASSETS" if="USE_ADAPTED_ASSETS"/>
|
||||
|
||||
<!--Disable the Flixel core debugger. Automatically gets set whenever you compile in release mode!-->
|
||||
<haxedef name="FLX_NO_DEBUG" unless="debug" />
|
||||
<!-- Backward Compatibilities -->
|
||||
<haxedef name="FLX_HEALTH" />
|
||||
|
||||
<haxedef name="analyzer-optimize" unless="debug" />
|
||||
<haxedef name="FLX_NO_FOCUS_LOST_SCREEN"/>
|
||||
<haxedef name="FLX_NO_DEBUG" unless="debug"/>
|
||||
|
||||
<haxedef name="VIDEO_CUTSCENES" if="VIDEO_CUTSCENES" />
|
||||
<haxedef name="UPDATE_CHECKING" if="UPDATE_CHECKING" />
|
||||
<haxedef name="DISCORD_RPC" if="DISCORD_RPC" />
|
||||
<haxedef name="SHOW_BUILD_ON_FPS" if="SHOW_BUILD_ON_FPS" />
|
||||
<haxedef name="SOFTCODED_CLASSES" if="SOFTCODED_CLASSES" />
|
||||
<haxedef name="USE_ADAPTED_ASSETS" if="USE_ADAPTED_ASSETS" />
|
||||
<haxedef name="openfl_dpi_aware" if="openfl_dpi_aware" />
|
||||
<haxedef name="DISCORD_DISABLE_IO_THREAD" if="DISCORD_RPC"/>
|
||||
|
||||
<!-- _________________________________ Custom _______________________________ -->
|
||||
|
||||
<!--Place custom nodes like icons here (higher priority to override the HaxeFlixel icon)-->
|
||||
<icon path="art/icon16.png" size='16'/>
|
||||
<icon path="art/icon32.png" size='24'/>
|
||||
<icon path="art/icon32.png" size='32'/>
|
||||
<icon path="art/icon64.png" size='40'/>
|
||||
<icon path="art/icon64.png" size='48'/>
|
||||
<icon path="art/icon64.png" size='64'/>
|
||||
<icon path="art/iconOG.png" size='96' />
|
||||
<icon path="art/iconOG.png" size='128' />
|
||||
<icon path="art/iconOG.png" size='196' />
|
||||
<icon path="art/iconOG.png" size='256' />
|
||||
<icon path="art/iconOG.png" size='512' />
|
||||
<icon path="art/iconOG.png" size='768' />
|
||||
<icon path="art/iconOG.png" size='1024' />
|
||||
|
||||
<!-- _________________________________ Additional stuff _______________________________ -->
|
||||
|
||||
<section if="MODCHARTING_FEATURES">
|
||||
<haxedef name="FM_ENGINE" value="CODENAME"/>
|
||||
<haxedef name="FM_ENGINE_VERSION" value="1.0"/>
|
||||
|
||||
<haxelib name="funkin-modchart" />
|
||||
<haxeflag name="--macro" value="modchart.backend.macros.Macro.includeFiles()"/>
|
||||
</section>
|
||||
|
||||
<section if="COMPILE_ALL_CLASSES">
|
||||
<haxeflag name="-dce" value="no" />
|
||||
<haxeflag name="--macro" value="funkin.backend.system.macros.Macros.addAdditionalClasses()" />
|
||||
</section>
|
||||
|
||||
<haxeflag name="--macro" value="funkin.backend.system.macros.Macros.initMacros()" />
|
||||
<!-- <haxedef name="no-deprecation-warnings"/> -->
|
||||
|
||||
<!-- Fix compiling issues -->
|
||||
<setenv name="HAXEPATH" value="./"/>
|
||||
|
||||
<haxedef name="HXCPP_M32" if="32bit" />
|
||||
<haxedef name="HXCPP_DEBUG_LINK" if="debug" />
|
||||
<haxedef name="HXCPP_CHECK_POINTER" />
|
||||
<haxedef name="HXCPP_STACK_LINE" />
|
||||
<haxedef name="HXCPP_CATCH_SEGV" />
|
||||
<!-- Haxe 4.3.0+: Enable pretty syntax errors and stuff. -->
|
||||
<haxedef name="message.reporting" value="pretty"/>
|
||||
|
||||
<haxedef name="hscriptPos" /> <!-- for logging -->
|
||||
<!-- for logging -->
|
||||
<haxedef name="hscriptPos"/>
|
||||
|
||||
<section if="COMPILE_ALL_CLASSES">
|
||||
<haxeflag name="-dce" value="no"/>
|
||||
<haxeflag name="--macro" value="funkin.backend.system.macros.Macros.addAdditionalClasses()"/>
|
||||
</section>
|
||||
|
||||
<haxeflag name="--macro" value="funkin.backend.system.macros.BuildInfo.printBuildInfo()"/>
|
||||
|
||||
<!-- EXPERMENTAL FEATURES -->
|
||||
<haxedef name="EXPERIMENTAL_FLXGRAPHIC_DESTROY_FIX" />
|
||||
<haxedef name="openfl_dpi_aware"/>
|
||||
<haxedef name="openfl_pool_events"/>
|
||||
<haxedef name="openfl-enable-handle-error"/>
|
||||
<haxedef name="openfl_no_custom_render_event"/>
|
||||
|
||||
<haxedef name="HXCPP_M32" if="32bit"/>
|
||||
<haxedef name="HXCPP_DEBUG_LINK" if="debug"/>
|
||||
<!--C++20 seems doesn't seem to do anything but causes compile warnings-->
|
||||
<!--<haxedef name="HXCPP_CPP20"/>-->
|
||||
<!--<haxedef name="HXCPP_CLANG"/>-->
|
||||
<!--<haxedef name="HXCPP_MSVC"/>-->
|
||||
<!-- This seems to causes more harm, but to be fair, its mostly because of text rendering -->
|
||||
<!-- This is really important to fix honestly, try to get cairo text rendering not memory leak in the future -->
|
||||
<!--<haxedef name="HXCPP_GC_BIG_BLOCKS"/>-->
|
||||
<!--<haxedef name="HXCPP_GC_GENERATIONAL"/>-->
|
||||
<!--<haxedef name="HXCPP_GC_DYNAMIC_SIZE"/>-->
|
||||
<haxedef name="HXCPP_CHECK_POINTER"/>
|
||||
<haxedef name="HXCPP_STACK_LINE"/>
|
||||
<haxedef name="HXCPP_STACK_TRACE"/>
|
||||
<!--<haxedef name="HXCPP_CATCH_SEGV"/>-->
|
||||
<haxedef name="HXCPP_FAST_LINK" unless="debug"/>
|
||||
<!--<haxedef name="HXCPP_ALIGN_ALLOC"/>--> <!--hxcpp.h(71): warning C4005: 'HXCPP_ALIGN_ALLOC': macro redefinition-->
|
||||
|
||||
<haxedef name="analyzer-optimize" unless="debug"/>
|
||||
</project>
|
||||
|
||||
@@ -1,929 +0,0 @@
|
||||
package flixel.sound;
|
||||
|
||||
import lime.media.AudioBuffer;
|
||||
import lime.media.AudioSource;
|
||||
import lime.media.AudioManager;
|
||||
|
||||
import openfl.Assets;
|
||||
import openfl.events.IEventDispatcher;
|
||||
import openfl.events.Event;
|
||||
import openfl.media.Sound;
|
||||
import openfl.media.SoundChannel;
|
||||
import openfl.media.SoundTransform;
|
||||
import openfl.media.SoundMixer;
|
||||
import openfl.net.URLRequest;
|
||||
import openfl.utils.AssetType;
|
||||
#if flash11
|
||||
import openfl.utils.ByteArray;
|
||||
#end
|
||||
|
||||
import flixel.math.FlxMath;
|
||||
import flixel.math.FlxPoint;
|
||||
import flixel.system.FlxAssets.FlxSoundAsset;
|
||||
import flixel.tweens.FlxTween;
|
||||
import flixel.util.FlxSignal;
|
||||
import flixel.util.FlxStringUtil;
|
||||
import flixel.FlxBasic;
|
||||
import flixel.FlxObject;
|
||||
import flixel.FlxG;
|
||||
|
||||
@:access(flixel.FlxGame)
|
||||
class FlxSound extends FlxBasic {
|
||||
/**
|
||||
* The x position of this sound in world coordinates.
|
||||
* Only really matters if you are doing proximity/panning stuff.
|
||||
*/
|
||||
public var x:Float;
|
||||
|
||||
/**
|
||||
* The y position of this sound in world coordinates.
|
||||
* Only really matters if you are doing proximity/panning stuff.
|
||||
*/
|
||||
public var y:Float;
|
||||
|
||||
/**
|
||||
* Whether or not this sound should be automatically destroyed when you switch states.
|
||||
*/
|
||||
public var persist:Bool;
|
||||
|
||||
/**
|
||||
* Whether or not the sound is currently playing.
|
||||
*/
|
||||
public var playing(get, never):Bool;
|
||||
|
||||
/**
|
||||
* Set volume to a value between 0 and 1* to change how this sound is.
|
||||
*/
|
||||
public var volume(get, set):Float;
|
||||
|
||||
/**
|
||||
* Whether to make this sound muted or not.
|
||||
*/
|
||||
public var muted(default, set):Bool;
|
||||
|
||||
#if FLX_PITCH
|
||||
/**
|
||||
* Set pitch, which also alters the playback speed. Default is 1.
|
||||
* @since 5.0.0
|
||||
*/
|
||||
public var pitch(get, set):Float;
|
||||
|
||||
/**
|
||||
* Alters the pitch of the sound depends on the current FlxG.timeScale. Default is true.
|
||||
* @since raltyMod
|
||||
*/
|
||||
public var timeScaleBased:Bool;
|
||||
#end
|
||||
|
||||
/**
|
||||
* Pan amount. -1 = full left, 1 = full right. Proximity based panning overrides this.
|
||||
*/
|
||||
public var pan(get, set):Float;
|
||||
|
||||
/**
|
||||
* The position in runtime of the music playback in milliseconds.
|
||||
* If set while paused, changes only come into effect after a `resume()` call.
|
||||
*/
|
||||
public var time(get, set):Float;
|
||||
|
||||
/**
|
||||
* The offset for this FlxSound.
|
||||
* Useful for just generally offsetting this sound without affecting time.
|
||||
* @since raltyMod
|
||||
*/
|
||||
public var offset(get, set):Float;
|
||||
|
||||
/**
|
||||
* The length of the sound in milliseconds.
|
||||
* @since 4.2.0
|
||||
*/
|
||||
public var length(get, never):Float;
|
||||
|
||||
/**
|
||||
* The latency of the sound in milliseconds.
|
||||
* @since raltyMod
|
||||
*/
|
||||
//public var latency(get, never):Float;
|
||||
|
||||
/**
|
||||
* Whether or not this sound should loop.
|
||||
*/
|
||||
public var looped(default, set):Bool;
|
||||
|
||||
/**
|
||||
* In case of looping, the point (in milliseconds) from where to restart the sound when it loops back
|
||||
* @since 4.1.0
|
||||
*/
|
||||
public var loopTime(default, set):Float;
|
||||
|
||||
/**
|
||||
* At which point to stop playing the sound, in milliseconds.
|
||||
* If not set / `null`, the sound completes normally.
|
||||
* @since 4.2.0
|
||||
*/
|
||||
public var endTime(default, set):Null<Float>;
|
||||
|
||||
/**
|
||||
* The sound's "target" (for proximity and panning).
|
||||
* @since raltyMod
|
||||
*/
|
||||
public var target:Null<FlxObject>;
|
||||
|
||||
/**
|
||||
* The maximum effective radius of this sound (for proximity and panning).
|
||||
* @since raltyMod
|
||||
*/
|
||||
public var radius:Float;
|
||||
|
||||
/**
|
||||
* Whether the proximity alters the pan or not
|
||||
* @since raltyMod
|
||||
*/
|
||||
public var proximityPan:Bool;
|
||||
|
||||
/**
|
||||
* Stores for how much channels are in the loaded sound.
|
||||
* @since raltyMod
|
||||
*/
|
||||
public var channels(get, never):Int;
|
||||
|
||||
/**
|
||||
* Whether or not this sound is stereo instead of mono.
|
||||
* @since raltyMod
|
||||
*/
|
||||
public var stereo(get, never):Bool;
|
||||
|
||||
/**
|
||||
* Whether or not this sound is loaded yet.
|
||||
* @since raltyMod
|
||||
*/
|
||||
public var loaded(get, never):Bool;
|
||||
|
||||
/**
|
||||
* Whether or not this sound is streamed, only vorbis though.
|
||||
* @since raltyMod
|
||||
*/
|
||||
public var streamed(get, never):Bool;
|
||||
|
||||
/**
|
||||
* Stores the average wave amplitude of both stereo channels.
|
||||
* @since raltyMod
|
||||
*/
|
||||
public var amplitude(get, never):Float;
|
||||
|
||||
/**
|
||||
* Just the amplitude of the left stereo channel
|
||||
* @since raltyMod
|
||||
*/
|
||||
public var amplitudeLeft(get, never):Float;
|
||||
|
||||
/**
|
||||
* Just the amplitude of the right stereo channel
|
||||
* @since raltyMod
|
||||
*/
|
||||
public var amplitudeRight(get, never):Float;
|
||||
|
||||
/**
|
||||
* The ID3 song name. Defaults to null. Currently only works for MP3 streamed sounds.
|
||||
*/
|
||||
public var name(default, null):String;
|
||||
|
||||
/**
|
||||
* The ID3 artist name. Defaults to null. Currently only works for MP3 streamed sounds.
|
||||
*/
|
||||
public var artist(default, null):String;
|
||||
|
||||
/**
|
||||
* Whether to call `destroy()` when the sound has finished playing.
|
||||
*/
|
||||
public var autoDestroy:Bool;
|
||||
|
||||
/**
|
||||
* Signal that is dispatched on sound complete.
|
||||
* Seperates the looping from onComplete.
|
||||
*/
|
||||
public final onFinish:FlxSignal;
|
||||
|
||||
/**
|
||||
* Tracker for sound complete callback. If assigned, will be called
|
||||
* each time when sound reaches its end.
|
||||
*/
|
||||
//@:deprecated("`FlxSound.onComplete` is deprecated! Use `FlxSound.onFinish` instead.")
|
||||
public var onComplete:Void->Void;
|
||||
|
||||
/**
|
||||
* The sound group this sound belongs to
|
||||
*/
|
||||
public var group(default, set):FlxSoundGroup;
|
||||
|
||||
/**
|
||||
* Stores the sound lime AudioBuffer if exists.
|
||||
* @since raltyMod
|
||||
*/
|
||||
public var buffer(get, never):AudioBuffer;
|
||||
|
||||
/**
|
||||
* The tween used to fade this sound's volume in and out (set via `fadeIn()` and `fadeOut()`)
|
||||
* @since 4.1.0
|
||||
*/
|
||||
public var fadeTween:FlxTween;
|
||||
|
||||
@:allow(flixel.system.frontEnds.SoundFrontEnd.load) var _sound:Sound;
|
||||
var _transform:SoundTransform;
|
||||
var _channel:SoundChannel;
|
||||
var _source:AudioSource;
|
||||
var _paused:Bool;
|
||||
var _volume:Float;
|
||||
var _volumeAdjust:Float;
|
||||
var _pan:Float;
|
||||
var _panAdjust:Float;
|
||||
var _time:Float;
|
||||
var _offset:Float;
|
||||
var _timeInterpolation:Float;
|
||||
var _lastTime:Null<Float>; // FlxG.game.getTicks(), in MS
|
||||
var _length:Float;
|
||||
#if FLX_PITCH
|
||||
var _pitch:Float;
|
||||
var _timeScaleAdjust:Float;
|
||||
var _realPitch:Float;
|
||||
#end
|
||||
var _amplitudeLeft:Float;
|
||||
var _amplitudeRight:Float;
|
||||
var _amplitudeUpdate:Bool;
|
||||
var _alreadyPaused:Null<Bool>;
|
||||
|
||||
public function new() {
|
||||
super();
|
||||
onFinish = new FlxSignal();
|
||||
revive();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets this FlxSound properties.
|
||||
*
|
||||
* @param clean Whether if this FlxSound also needs to be cleaned up too.
|
||||
*/
|
||||
public function reset():Void {
|
||||
if (_source != null) stop();
|
||||
onFinish.removeAll();
|
||||
|
||||
x = y = 0;
|
||||
@:bypassAccessor muted = false;
|
||||
@:bypassAccessor looped = false;
|
||||
@:bypassAccessor loopTime = 0;
|
||||
@:bypassAccessor endTime = null;
|
||||
autoDestroy = false;
|
||||
visible = false;
|
||||
target = null;
|
||||
radius = 0;
|
||||
proximityPan = true;
|
||||
onComplete = null;
|
||||
timeScaleBased = true;
|
||||
|
||||
_alreadyPaused = null;
|
||||
_cameras = null;
|
||||
_lastTime = null;
|
||||
_paused = false;
|
||||
_offset = _length = _time = 0;
|
||||
_volume = _volumeAdjust = 1;
|
||||
_amplitudeLeft = _amplitudeRight = 0;
|
||||
_amplitudeUpdate = true;
|
||||
#if FLX_PITCH _pitch = _realPitch = _timeScaleAdjust = 1; #end
|
||||
|
||||
if (_transform == null) _transform = new SoundTransform();
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal cleanup function for cleaning up this FlxSound.
|
||||
* @since raltyMod
|
||||
*/
|
||||
function cleanup(destroySound:Bool, resetPosition:Bool = true) @:privateAccess {
|
||||
active = false;
|
||||
_lastTime = null;
|
||||
|
||||
if (destroySound) {
|
||||
if (group != null) group.remove(this);
|
||||
|
||||
if (_channel != null) {
|
||||
_channel.stop();
|
||||
_channel = null;
|
||||
}
|
||||
if (_source != null) {
|
||||
_source.onComplete.remove(stopped);
|
||||
_source.onLoop.remove(source_looped);
|
||||
_source.dispose();
|
||||
}
|
||||
_source = null;
|
||||
_sound = null;
|
||||
|
||||
if (autoDestroy) persist = false;
|
||||
reset();
|
||||
}
|
||||
else if (_channel != null && _channel.__isValid) {
|
||||
if (resetPosition) {
|
||||
_source.stop();
|
||||
|
||||
_time = 0;
|
||||
_paused = false;
|
||||
}
|
||||
else if (!_paused) {
|
||||
get_time();
|
||||
_source.pause();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles fade out, fade in, panning, proximity, and amplitude operations each frame.
|
||||
*/
|
||||
override function update(elapsed:Float):Void {
|
||||
if (!playing) return;
|
||||
|
||||
var timeScaleTarget = timeScaleBased ? FlxG.timeScale : 1.0;
|
||||
if (_timeScaleAdjust != timeScaleTarget) {
|
||||
_timeScaleAdjust = timeScaleTarget;
|
||||
pitch = _pitch;
|
||||
if (_channel == null) return;
|
||||
}
|
||||
|
||||
_amplitudeUpdate = true;
|
||||
|
||||
// Distance-based volume control (TODO for Ralty: REDO THIS)
|
||||
if (target != null) {
|
||||
var targetPosition = target.getPosition();
|
||||
var radialMultiplier = targetPosition.distanceTo(FlxPoint.weak(x, y)) / radius;
|
||||
targetPosition.put();
|
||||
radialMultiplier = 1 - FlxMath.bound(radialMultiplier, 0, 1);
|
||||
|
||||
_volumeAdjust = radialMultiplier;
|
||||
if (proximityPan) _panAdjust = (x - target.x) / radius;
|
||||
}
|
||||
else
|
||||
_volumeAdjust = 1.0;
|
||||
|
||||
updateTransform();
|
||||
}
|
||||
|
||||
override function revive() {
|
||||
reset();
|
||||
super.revive();
|
||||
}
|
||||
|
||||
override function kill() {
|
||||
super.kill();
|
||||
reset();
|
||||
}
|
||||
|
||||
override function destroy() {
|
||||
super.destroy();
|
||||
cleanup(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* One of the main setup functions for sounds, this function loads a sound from an embedded MP3.
|
||||
*
|
||||
* @param embeddedSound An embedded Class object representing an MP3 file.
|
||||
* @param looped Whether or not this sound should loop endlessly.
|
||||
* @param autoDestroy Whether or not this FlxSound instance should be destroyed when the sound finishes playing.
|
||||
* Default value is false, but `FlxG.sound.play()` and `FlxG.sound.stream()` will set it to true by default.
|
||||
* @param onComplete Called when the sound finished playing
|
||||
* @return This FlxSound instance (nice for chaining stuff together, if you're into that).
|
||||
*/
|
||||
public function loadEmbedded(embeddedSound:FlxSoundAsset, looped = false, autoDestroy = false, ?onComplete:Void->Void):FlxSound {
|
||||
if (!exists || embeddedSound == null) return this;
|
||||
cleanup(true);
|
||||
|
||||
if ((embeddedSound is Sound)) _sound = embeddedSound;
|
||||
else if ((embeddedSound is Class)) _sound = Type.createInstance(embeddedSound, []);
|
||||
else if ((embeddedSound is String)) {
|
||||
if (Assets.exists(embeddedSound, AssetType.MUSIC) && this == FlxG.sound.music)
|
||||
_sound = Assets.getMusic(embeddedSound);
|
||||
else if (Assets.exists(embeddedSound, AssetType.SOUND))
|
||||
_sound = Assets.getSound(embeddedSound);
|
||||
else
|
||||
FlxG.log.error('Could not find a Sound asset with an ID of \'$embeddedSound\'.');
|
||||
}
|
||||
|
||||
return init(looped, autoDestroy, onComplete);
|
||||
}
|
||||
|
||||
/**
|
||||
* One of the main setup functions for sounds, this function loads a sound from a URL.
|
||||
*
|
||||
* @param soundURL A string representing the URL of the MP3 file you want to play.
|
||||
* @param looped Whether or not this sound should loop endlessly.
|
||||
* @param autoDestroy Whether or not this FlxSound instance should be destroyed when the sound finishes playing.
|
||||
* Default value is false, but `FlxG.sound.play()` and `FlxG.sound.stream()` will set it to true by default.
|
||||
* @param onComplete Called when the sound finished playing
|
||||
* @param onLoad Called when the sound finished loading.
|
||||
* @return This FlxSound instance (nice for chaining stuff together, if you're into that).
|
||||
*/
|
||||
public function loadStream(soundURL:String, looped = false, autoDestroy = false, ?onComplete:Void->Void, ?onLoad:Void->Void):FlxSound {
|
||||
if (!exists) return this;
|
||||
cleanup(true);
|
||||
|
||||
_sound = new Sound();
|
||||
_sound.addEventListener(Event.ID3, gotID3);
|
||||
var loadCallback:Event->Void = null;
|
||||
loadCallback = function(e:Event)
|
||||
{
|
||||
(e.target : IEventDispatcher).removeEventListener(e.type, loadCallback);
|
||||
// Check if the sound was destroyed before calling. Weak ref doesn't guarantee GC.
|
||||
if (_sound == e.target)
|
||||
{
|
||||
_length = _sound.length;
|
||||
if (onLoad != null)
|
||||
onLoad();
|
||||
}
|
||||
}
|
||||
// Use a weak reference so this can be garbage collected if destroyed before loading.
|
||||
_sound.addEventListener(Event.COMPLETE, loadCallback, false, 0, true);
|
||||
_sound.load(new URLRequest(soundURL));
|
||||
|
||||
return init(looped, autoDestroy, onComplete);
|
||||
}
|
||||
|
||||
#if flash11
|
||||
/**
|
||||
* One of the main setup functions for sounds, this function loads a sound from a ByteArray.
|
||||
*
|
||||
* @param bytes A ByteArray object.
|
||||
* @param looped Whether or not this sound should loop endlessly.
|
||||
* @param autoDestroy Whether or not this FlxSound instance should be destroyed when the sound finishes playing.
|
||||
* Default value is false, but `FlxG.sound.play()` and `FlxG.sound.stream()` will set it to true by default.
|
||||
* @return This FlxSound instance (nice for chaining stuff together, if you're into that).
|
||||
*/
|
||||
public function loadByteArray(bytes:ByteArray, looped = false, autoDestroy = false, ?onComplete:Void->Void):FlxSound {
|
||||
if (!exists) return this;
|
||||
cleanup(true);
|
||||
|
||||
_sound = new Sound();
|
||||
_sound.addEventListener(Event.ID3, gotID3);
|
||||
_sound.loadCompressedDataFromByteArray(bytes, bytes.length);
|
||||
|
||||
return init(looped, autoDestroy, onComplete);
|
||||
}
|
||||
#end
|
||||
|
||||
function init(?looped:Null<Bool>, ?autoDestroy:Null<Bool>, ?onComplete:Null<Void->Void>):FlxSound {
|
||||
if (looped != null) this.looped = looped;
|
||||
if (autoDestroy != null) this.autoDestroy = autoDestroy;
|
||||
if (onComplete != null) this.onComplete = onComplete;
|
||||
|
||||
if (_sound != null) makeChannel();
|
||||
else _length = 0;
|
||||
|
||||
endTime = null;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call inbetween init function if a sound asset does exists.
|
||||
* @since raltyMod
|
||||
*/
|
||||
function makeChannel() @:privateAccess {
|
||||
if (_sound.__buffer == null) return;
|
||||
if (_source != null) _source.dispose();
|
||||
|
||||
if (_channel == null) (_source = (_channel = new SoundChannel(null)).__source = new AudioSource(_sound.__buffer)).gain = 0;
|
||||
else {
|
||||
(_source = new AudioSource(_sound.__buffer)).gain = 0;
|
||||
_channel.__dispose();
|
||||
_channel.__source = _source;
|
||||
SoundMixer.__registerSoundChannel(_channel);
|
||||
}
|
||||
_length = _source.length;
|
||||
|
||||
_source.onComplete.add(stopped);
|
||||
_source.onLoop.add(source_looped);
|
||||
_channel.__soundTransform = _transform;
|
||||
_channel.__isValid = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call after adjusting the volume to update the sound channel's settings.
|
||||
*/
|
||||
@:allow(flixel.sound.FlxSoundGroup)
|
||||
function updateTransform() {
|
||||
_transform.volume = calcTransformVolume();
|
||||
_transform.pan = _pan + _panAdjust;
|
||||
if (_channel != null) _channel.soundTransform = _transform;
|
||||
}
|
||||
|
||||
public function calcTransformVolume():Float {
|
||||
if (muted) return 0.0;
|
||||
|
||||
#if FLX_SOUND_SYSTEM
|
||||
if (FlxG.sound.muted) return 0.0;
|
||||
|
||||
// TODO: when flixel-cne is updated, enable this
|
||||
//return FlxG.sound.applySoundCurve(FlxG.sound.volume * volume);
|
||||
return FlxG.sound.volume * getActualVolume();
|
||||
#else
|
||||
return getActualVolume();
|
||||
#end
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this function if you want this sound's volume to change
|
||||
* based on distance from a particular FlxObject.
|
||||
*
|
||||
* @param X The X position of the sound.
|
||||
* @param Y The Y position of the sound.
|
||||
* @param TargetObject The object you want to track.
|
||||
* @param Radius The maximum distance this sound can travel.
|
||||
* @param Pan Whether panning should be used in addition to the volume changes.
|
||||
* @return This FlxSound instance (nice for chaining stuff together, if you're into that).
|
||||
*/
|
||||
public function proximity(x = 0.0, y = 0.0, ?targetObject:FlxObject, ?radius:Float, pan = true):FlxSound {
|
||||
setPosition(x, y);
|
||||
if (targetObject != null) this.target = targetObject;
|
||||
if (radius != null) this.radius = radius;
|
||||
proximityPan = pan;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to set the coordinates of this object.
|
||||
* Sound positioning is used in conjunction with proximity/panning.
|
||||
*
|
||||
* @param x The new x position
|
||||
* @param y The new y position
|
||||
*/
|
||||
public inline function setPosition(x = 0.0, y = 0.0):Void {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this function to play the sound - also works on paused sounds.
|
||||
*
|
||||
* @param forceRestart Whether to start the sound over or not.
|
||||
* Default value is false, meaning if the sound is already playing or was
|
||||
* paused when you call play(), it will continue playing from its current
|
||||
* position, NOT start again from the beginning.
|
||||
* @param startTime At which point to start playing the sound, in milliseconds.
|
||||
* @param endTime At which point to stop playing the sound, in milliseconds.
|
||||
* If not set / `null`, the sound completes normally.
|
||||
*/
|
||||
public function play(forceRestart = false, startTime = 0.0, ?endTime:Null<Float>):FlxSound {
|
||||
if (!exists) return this;
|
||||
|
||||
if (forceRestart) cleanup(false, true);
|
||||
else if (playing) return this;
|
||||
|
||||
if (endTime != null) this.endTime = endTime;
|
||||
if (_paused) resume();
|
||||
else startSound(startTime);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unpause a sound. Only works on sounds that have been paused.
|
||||
* @return This FlxSound instance (nice for chaining stuff together, if you're into that).
|
||||
*/
|
||||
public function resume():FlxSound {
|
||||
if (_paused) startSound(_time);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this function to pause this sound.
|
||||
* @return This FlxSound instance (nice for chaining stuff together, if you're into that).
|
||||
*/
|
||||
public function pause():FlxSound {
|
||||
if (!playing) return this;
|
||||
|
||||
cleanup(false, false);
|
||||
_paused = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this function to stop this sound.
|
||||
* @return This FlxSound instance (nice for chaining stuff together, if you're into that).
|
||||
*/
|
||||
public function stop():FlxSound {
|
||||
cleanup(autoDestroy, true);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function that tweens this sound's volume.
|
||||
*
|
||||
* @param duration The amount of time the fade-out operation should take.
|
||||
* @param to The volume to tween to, 0 by default.
|
||||
* @return This FlxSound instance (nice for chaining stuff together, if you're into that).
|
||||
*/
|
||||
public function fadeOut(duration = 1.0, to = 0.0, ?onComplete:FlxTween->Void):FlxSound {
|
||||
if (fadeTween != null) fadeTween.cancel();
|
||||
fadeTween = FlxTween.num(volume, to, duration, {onComplete: onComplete}, volumeTween);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function that tweens this sound's volume.
|
||||
* If the sound wasn't playing at all, it'll play before the tween starts.
|
||||
*
|
||||
* @param duration The amount of time the fade-in operation should take.
|
||||
* @param from The volume to tween from, 0 by default.
|
||||
* @param to The volume to tween to, 1 by default.
|
||||
* @return This FlxSound instance (nice for chaining stuff together, if you're into that).
|
||||
*/
|
||||
public function fadeIn(duration = 1.0, from = 0.0, to = 1.0, ?onComplete:FlxTween->Void):FlxSound {
|
||||
if (!playing) play();
|
||||
if (fadeTween != null) fadeTween.cancel();
|
||||
fadeTween = FlxTween.num(from, to, duration, {onComplete: onComplete}, volumeTween);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
function volumeTween(f:Float) volume = f;
|
||||
|
||||
/**
|
||||
* Returns the currently selected "real" volume of the sound (takes fades and proximity into account).
|
||||
*
|
||||
* @return The adjusted volume of the sound.
|
||||
*/
|
||||
public inline function getActualVolume():Float
|
||||
return (group != null ? group.getVolume() : 1.0) * _volume * _volumeAdjust;
|
||||
|
||||
#if FLX_PITCH
|
||||
/**
|
||||
* Returns the currently selected "real" pitch of the sound.
|
||||
*
|
||||
* @return The adjusted pitch of the sound.
|
||||
*/
|
||||
public inline function getActualPitch():Float
|
||||
return _realPitch;
|
||||
#end
|
||||
|
||||
/**
|
||||
* Returns the actual time coming from the internal, can be used for detecting sync error.
|
||||
*
|
||||
* @return The actual time of the sound.
|
||||
*/
|
||||
public inline function getActualTime():Float {
|
||||
get_time();
|
||||
return _time;
|
||||
}
|
||||
|
||||
/**
|
||||
* An internal helper function used to attempt to start playing
|
||||
* the sound and populate the _channel variable.
|
||||
*/
|
||||
function startSound(startTime:Float) @:privateAccess {
|
||||
if (_sound == null) return;
|
||||
|
||||
_paused = false;
|
||||
_time = startTime;
|
||||
_lastTime = FlxG.game.getTicks();
|
||||
if (_channel == null || !_channel.__isValid || _source == null #if lime_cffi || _source.__backend.disposed || _source.__backend.handle == null #end)
|
||||
makeChannel();
|
||||
|
||||
if (_channel != null) {
|
||||
#if FLX_PITCH
|
||||
_timeScaleAdjust = timeScaleBased ? FlxG.timeScale : 1.0;
|
||||
pitch = _pitch;
|
||||
#end
|
||||
|
||||
updateTransform();
|
||||
_channel.__lastPeakTime = -10;
|
||||
_channel.__leftPeak = 0;
|
||||
_channel.__rightPeak = 0;
|
||||
|
||||
#if lime_cffi _source.__backend.playing = true; #end
|
||||
_source.offset = 0;
|
||||
_source.currentTime = startTime + _offset;
|
||||
#if !lime_cffi _source.play(); #end
|
||||
|
||||
looped = looped;
|
||||
loopTime = loopTime;
|
||||
endTime = endTime;
|
||||
|
||||
active = true;
|
||||
}
|
||||
else {
|
||||
exists = false;
|
||||
active = false;
|
||||
}
|
||||
}
|
||||
|
||||
function stopped() {
|
||||
onFinish.dispatch();
|
||||
|
||||
if (onComplete != null) onComplete();
|
||||
|
||||
if (looped) {
|
||||
cleanup(false);
|
||||
play(false, loopTime, endTime);
|
||||
}
|
||||
else cleanup(autoDestroy);
|
||||
}
|
||||
|
||||
function source_looped() {
|
||||
if (onComplete != null) onComplete();
|
||||
|
||||
if (!looped) {
|
||||
cleanup(autoDestroy);
|
||||
_lastTime = FlxG.game.getTicks();
|
||||
_time = loopTime;
|
||||
}
|
||||
else _channel.loops = 999;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal event handler for ID3 info (i.e. fetching the song name).
|
||||
*/
|
||||
function gotID3(_) {
|
||||
name = _sound.id3.songName;
|
||||
artist = _sound.id3.artist;
|
||||
_sound.removeEventListener(Event.ID3, gotID3);
|
||||
}
|
||||
|
||||
#if FLX_SOUND_SYSTEM
|
||||
@:allow(flixel.system.frontEnds.SoundFrontEnd)
|
||||
function onFocus() if (!_alreadyPaused) {
|
||||
resume();
|
||||
_alreadyPaused = null;
|
||||
}
|
||||
|
||||
@:allow(flixel.system.frontEnds.SoundFrontEnd)
|
||||
function onFocusLost() if (_alreadyPaused == null && !(_alreadyPaused = _paused)) pause();
|
||||
#end
|
||||
|
||||
function set_group(value:FlxSoundGroup):FlxSoundGroup {
|
||||
if (value != null) value.add(this);
|
||||
else group.remove(this);
|
||||
return group;
|
||||
}
|
||||
|
||||
inline function get_playing():Bool @:privateAccess
|
||||
return _channel != null && _channel.__isValid && _source.playing;
|
||||
|
||||
inline function get_volume():Float
|
||||
return _volume;
|
||||
|
||||
inline function set_volume(v:Float):Float {
|
||||
_volume = FlxMath.bound(v, 0, 10);
|
||||
updateTransform();
|
||||
return _volume;
|
||||
}
|
||||
|
||||
inline function set_muted(v:Bool):Bool {
|
||||
muted = v;
|
||||
updateTransform();
|
||||
return muted;
|
||||
}
|
||||
|
||||
inline function get_pan():Float return _pan;
|
||||
inline function set_pan(v:Float):Float {
|
||||
_pan = FlxMath.bound(v, -1, 1);
|
||||
updateTransform();
|
||||
return _pan;
|
||||
}
|
||||
|
||||
inline function get_loaded():Bool
|
||||
return buffer != null;
|
||||
|
||||
inline function get_streamed():Bool
|
||||
@:privateAccess return #if lime_vorbis _sound != null && _sound.__buffer.__srcVorbisFile != null #else false #end;
|
||||
|
||||
inline function get_buffer():AudioBuffer
|
||||
@:privateAccess return _sound != null ? _sound.__buffer : null;
|
||||
|
||||
function update_amplitude():Void @:privateAccess {
|
||||
if (_channel == null || !_channel.__updatePeaks(get_time()) || !_amplitudeUpdate) return;
|
||||
|
||||
_amplitudeUpdate = false;
|
||||
_amplitudeLeft = _channel.__leftPeak;
|
||||
_amplitudeRight = _channel.__rightPeak;
|
||||
}
|
||||
|
||||
inline function get_amplitudeLeft():Float {
|
||||
update_amplitude();
|
||||
return _amplitudeLeft;
|
||||
}
|
||||
|
||||
inline function get_amplitudeRight():Float {
|
||||
update_amplitude();
|
||||
return _amplitudeRight;
|
||||
}
|
||||
|
||||
inline function get_amplitude():Float {
|
||||
update_amplitude();
|
||||
return Math.max(_amplitudeLeft, _amplitudeRight);//if (stereo) (_amplitudeLeft + _amplitudeRight) * 0.5; else _amplitudeLeft;
|
||||
}
|
||||
|
||||
inline function get_channels():Int
|
||||
@:privateAccess return (buffer != null) ? buffer.channels : 0;
|
||||
|
||||
inline function get_stereo():Bool
|
||||
return channels > 1;
|
||||
|
||||
#if FLX_PITCH
|
||||
inline function get_pitch():Float
|
||||
return _pitch;
|
||||
|
||||
function set_pitch(v:Float):Float {
|
||||
_realPitch = (_pitch = v) * _timeScaleAdjust;
|
||||
if (_channel != null) _channel.pitch = _realPitch;
|
||||
return _pitch;
|
||||
}
|
||||
#end
|
||||
|
||||
function set_looped(v:Bool):Bool {
|
||||
if (playing) {
|
||||
if (v) _channel.loops = 999;
|
||||
else _channel.loops = 0;
|
||||
}
|
||||
return looped = v;
|
||||
}
|
||||
|
||||
function set_loopTime(v:Float):Float {
|
||||
if (playing) _channel.loopTime = v;
|
||||
return loopTime = v;
|
||||
}
|
||||
|
||||
function set_endTime(v:Null<Float>):Null<Float> {
|
||||
if (playing) {
|
||||
if (v != null && v > 0 && v < _length) _channel.endTime = v;
|
||||
else _channel.endTime = null;
|
||||
}
|
||||
return endTime = v;
|
||||
}
|
||||
|
||||
inline function getFakeTime():Float {
|
||||
if (_source.playing && _realPitch > 0 && _lastTime != null)
|
||||
return _time + (FlxG.game.getTicks() - _lastTime) * _realPitch * _timeInterpolation;
|
||||
else
|
||||
return _time;
|
||||
}
|
||||
function get_time():Float {
|
||||
if (_channel == null || @:privateAccess !_channel.__isValid || /*AudioManager.context == null*/funkin.backend.system.Main.audioDisconnected) return _time;
|
||||
|
||||
final sourceTime = _source.currentTime - _source.offset - _offset;
|
||||
if (!_source.playing || _realPitch <= 0) {
|
||||
_lastTime = null;
|
||||
return _time = sourceTime;
|
||||
}
|
||||
|
||||
final fakeTime = getFakeTime();
|
||||
if (sourceTime != _time) {
|
||||
_lastTime = FlxG.game.getTicks();
|
||||
if ((_timeInterpolation = 1 - Math.min(fakeTime - sourceTime, 1000) * 0.001) < 1 && _timeInterpolation > .9)
|
||||
return _time = fakeTime;
|
||||
else {
|
||||
_timeInterpolation = 1;
|
||||
return _time = sourceTime;
|
||||
}
|
||||
}
|
||||
else
|
||||
return fakeTime;
|
||||
}
|
||||
|
||||
function set_time(time:Float):Float @:privateAccess {
|
||||
time = FlxMath.bound(time, _offset, length - 1);
|
||||
if (_channel != null && _realPitch > 0) {
|
||||
if (!_channel.__isValid) {
|
||||
cleanup(false, true);
|
||||
startSound(time);
|
||||
}
|
||||
else {
|
||||
_source.offset = 0;
|
||||
_source.currentTime = time + _offset;
|
||||
}
|
||||
}
|
||||
|
||||
_lastTime = null;
|
||||
return _time = time;
|
||||
}
|
||||
|
||||
inline function get_offset():Float return _offset;
|
||||
inline function set_offset(offset:Float):Float {
|
||||
if (_offset == (_offset = offset)) return offset;
|
||||
//time = time + _offset;
|
||||
return offset;
|
||||
}
|
||||
|
||||
inline function get_length():Float return _length - _offset;
|
||||
|
||||
/*function get_latency():Float {
|
||||
if (_channel != null) return _source.latency;
|
||||
return 0;
|
||||
}*/
|
||||
|
||||
override function toString():String {
|
||||
return FlxStringUtil.getDebugString([
|
||||
LabelValuePair.weak("playing", playing),
|
||||
LabelValuePair.weak("time", _time),
|
||||
LabelValuePair.weak("length", length),
|
||||
LabelValuePair.weak("volume", volume),
|
||||
LabelValuePair.weak("pitch", pitch)
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -1,120 +0,0 @@
|
||||
package flixel.sound;
|
||||
|
||||
/**
|
||||
* A way of grouping sounds for things such as collective volume control
|
||||
*/
|
||||
class FlxSoundGroup
|
||||
{
|
||||
/**
|
||||
* The sounds in this group
|
||||
*/
|
||||
public var sounds:Array<FlxSound> = [];
|
||||
|
||||
/**
|
||||
* The volume of this group
|
||||
*/
|
||||
public var volume(default, set):Float;
|
||||
|
||||
/**
|
||||
* Whether or not this group is muted
|
||||
*/
|
||||
public var muted(default, set):Bool;
|
||||
|
||||
/**
|
||||
* Create a new sound group
|
||||
* @param volume The initial volume of this group
|
||||
*/
|
||||
public function new(volume:Float = 1)
|
||||
{
|
||||
this.volume = volume;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a sound to this group, will remove the sound from any group it is currently in
|
||||
* @param sound The sound to add to this group
|
||||
* @return True if sound was successfully added, false otherwise
|
||||
*/
|
||||
public function add(sound:FlxSound):Bool
|
||||
{
|
||||
if (!sounds.contains(sound))
|
||||
{
|
||||
// remove from prev group
|
||||
if (sound.group != null)
|
||||
sound.group.sounds.remove(sound);
|
||||
|
||||
sounds.push(sound);
|
||||
@:bypassAccessor
|
||||
sound.group = this;
|
||||
sound.updateTransform();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a sound from this group
|
||||
* @param sound The sound to remove
|
||||
* @return True if sound was successfully removed, false otherwise
|
||||
*/
|
||||
public function remove(sound:FlxSound):Bool
|
||||
{
|
||||
if (sounds.contains(sound))
|
||||
{
|
||||
@:bypassAccessor
|
||||
sound.group = null;
|
||||
sounds.remove(sound);
|
||||
sound.updateTransform();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this function to pause all sounds in this group.
|
||||
* @since 4.3.0
|
||||
*/
|
||||
public function pause():Void
|
||||
{
|
||||
for (sound in sounds)
|
||||
sound.pause();
|
||||
}
|
||||
|
||||
/**
|
||||
* Unpauses all sounds in this group. Only works on sounds that have been paused.
|
||||
* @since 4.3.0
|
||||
*/
|
||||
public function resume():Void
|
||||
{
|
||||
for (sound in sounds)
|
||||
sound.resume();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the volume of this group, taking `muted` in account.
|
||||
* @return The volume of the group or 0 if the group is muted.
|
||||
*/
|
||||
public function getVolume():Float
|
||||
{
|
||||
return muted ? 0.0 : volume;
|
||||
}
|
||||
|
||||
function set_volume(volume:Float):Float
|
||||
{
|
||||
this.volume = volume;
|
||||
for (sound in sounds)
|
||||
{
|
||||
sound.updateTransform();
|
||||
}
|
||||
return volume;
|
||||
}
|
||||
|
||||
function set_muted(value:Bool):Bool
|
||||
{
|
||||
muted = value;
|
||||
for (sound in sounds)
|
||||
{
|
||||
sound.updateTransform();
|
||||
}
|
||||
return muted;
|
||||
}
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
package funkin.backend;
|
||||
|
||||
import flixel.graphics.frames.FlxFrame;
|
||||
import flixel.math.FlxAngle;
|
||||
import flixel.math.FlxMatrix;
|
||||
import openfl.display.BlendMode;
|
||||
import openfl.geom.ColorTransform;
|
||||
|
||||
class FlxAnimate extends flxanimate.FlxAnimate {
|
||||
static var rMatrix = new FlxMatrix();
|
||||
|
||||
override function drawLimb(limb:FlxFrame, _rMatrix:FlxMatrix, ?colorTransform:ColorTransform, ?blendMode:BlendMode)
|
||||
{
|
||||
if (alpha == 0 || colorTransform != null && (colorTransform.alphaMultiplier == 0 || colorTransform.alphaOffset == -255) || limb == null || limb.type == EMPTY)
|
||||
return;
|
||||
|
||||
if (blendMode == null)
|
||||
blendMode = BlendMode.NORMAL;
|
||||
|
||||
for (camera in cameras)
|
||||
{
|
||||
rMatrix.identity();
|
||||
limb.prepareMatrix(rMatrix, FlxFrameAngle.ANGLE_0, _checkFlipX() != camera.flipX, _checkFlipY() != camera.flipY);
|
||||
rMatrix.concat(_rMatrix);
|
||||
if (!camera.visible || !camera.exists || !limbOnScreen(limb, _rMatrix, camera))
|
||||
return;
|
||||
|
||||
getScreenPosition(_point, camera).subtractPoint(offset);
|
||||
rMatrix.translate(-origin.x, -origin.y);
|
||||
if (limb != _pivot) {
|
||||
if (frameOffsetAngle != null && frameOffsetAngle != angle)
|
||||
{
|
||||
var angleOff = (frameOffsetAngle - angle) * FlxAngle.TO_RAD;
|
||||
var cos = Math.cos(angleOff);
|
||||
var sin = Math.sin(angleOff);
|
||||
// cos doesn't need to be negated
|
||||
rMatrix.rotateWithTrig(cos, -sin);
|
||||
rMatrix.translate(-frameOffset.x, -frameOffset.y);
|
||||
rMatrix.rotateWithTrig(cos, sin);
|
||||
}
|
||||
else
|
||||
{
|
||||
rMatrix.translate(-frameOffset.x, -frameOffset.y);
|
||||
}
|
||||
rMatrix.scale(scale.x, scale.y);
|
||||
|
||||
if (!matrixExposed && bakedRotationAngle <= 0)
|
||||
{
|
||||
updateTrig();
|
||||
|
||||
if (angle != 0)
|
||||
rMatrix.rotateWithTrig(_cosAngle, _sinAngle);
|
||||
}
|
||||
}
|
||||
else
|
||||
rMatrix.a = rMatrix.d = 0.7 / camera.zoom;
|
||||
|
||||
if (matrixExposed)
|
||||
{
|
||||
rMatrix.concat(transformMatrix);
|
||||
}
|
||||
else
|
||||
{
|
||||
rMatrix.concat(@:privateAccess flxanimate.FlxAnimate._skewMatrix);
|
||||
}
|
||||
|
||||
_point.addPoint(origin);
|
||||
if (isPixelPerfectRender(camera))
|
||||
{
|
||||
_point.floor();
|
||||
}
|
||||
|
||||
rMatrix.translate(_point.x, _point.y);
|
||||
camera.drawPixels(limb, null, rMatrix, colorTransform, blendMode, antialiasing, shaderEnabled ? shader : null);
|
||||
#if FLX_DEBUG
|
||||
FlxBasic.visibleCount++;
|
||||
#end
|
||||
}
|
||||
|
||||
// doesn't work, needs to be remade
|
||||
// #if FLX_DEBUG
|
||||
// if (FlxG.debugger.drawDebug)
|
||||
// drawDebug();
|
||||
// #end
|
||||
}
|
||||
|
||||
override function limbOnScreen(limb:FlxFrame, m:FlxMatrix, ?Camera:FlxCamera)
|
||||
{
|
||||
// TODO: ACTUAL OPTIMIZATION
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
package funkin.backend;
|
||||
|
||||
import animate.FlxAnimate;
|
||||
import animate.FlxAnimateController.FlxAnimateAnimation;
|
||||
import flixel.addons.effects.FlxSkewedSprite;
|
||||
import flixel.animation.FlxAnimation;
|
||||
import flixel.math.FlxMatrix;
|
||||
@@ -7,7 +9,6 @@ import flixel.math.FlxPoint;
|
||||
import flixel.math.FlxRect;
|
||||
import flixel.system.FlxAssets.FlxGraphicAsset;
|
||||
import flixel.util.typeLimit.OneOfTwo;
|
||||
import flxanimate.animate.FlxAnim.FlxSymbolAnimation;
|
||||
import funkin.backend.scripting.events.sprite.PlayAnimContext;
|
||||
import funkin.backend.system.interfaces.IBeatReceiver;
|
||||
import funkin.backend.system.interfaces.IOffsetCompatible;
|
||||
@@ -15,6 +16,10 @@ import funkin.backend.utils.XMLUtil.AnimData;
|
||||
import funkin.backend.utils.XMLUtil.BeatAnim;
|
||||
import funkin.backend.utils.XMLUtil.IXMLEvents;
|
||||
import haxe.io.Path;
|
||||
import flixel.graphics.frames.FlxFrame;
|
||||
import flixel.math.FlxAngle;
|
||||
import animate.internal.RenderTexture;
|
||||
import animate.FlxAnimateFrames;
|
||||
|
||||
enum abstract XMLAnimType(Int)
|
||||
{
|
||||
@@ -43,7 +48,7 @@ enum abstract XMLAnimType(Int)
|
||||
}
|
||||
}
|
||||
|
||||
class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements IOffsetCompatible implements IXMLEvents
|
||||
class FunkinSprite extends FlxAnimate implements IBeatReceiver implements IOffsetCompatible implements IXMLEvents
|
||||
{
|
||||
public var extra:Map<String, Dynamic> = [];
|
||||
|
||||
@@ -56,6 +61,9 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
|
||||
public var animEnabled:Bool = true;
|
||||
public var zoomFactorEnabled:Bool = true;
|
||||
|
||||
//Backwards compatibility
|
||||
public var animateAtlas(get, never):FunkinSprite;
|
||||
|
||||
public var globalCurFrame(get, set):Int;
|
||||
|
||||
/**
|
||||
@@ -66,9 +74,9 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
|
||||
public var beatOffset:Int = 0;
|
||||
public var skipNegativeBeats:Bool = false;
|
||||
|
||||
public var animateAtlas:FlxAnimate;
|
||||
@:noCompletion public var atlasPlayingAnim:String;
|
||||
@:noCompletion public var atlasPath:String;
|
||||
public var animateSettings:FlxAnimateSettings = {};
|
||||
|
||||
var _rect2:FlxRect;
|
||||
|
||||
public function new(?X:Float = 0, ?Y:Float = 0, ?SimpleGraphic:FlxGraphicAsset)
|
||||
{
|
||||
@@ -83,6 +91,7 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
|
||||
}
|
||||
|
||||
moves = false;
|
||||
applyStageMatrix = true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -98,8 +107,6 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
|
||||
@:privateAccess {
|
||||
spr.setPosition(source.x, source.y);
|
||||
spr.frames = source.frames;
|
||||
if (casted != null && casted.animateAtlas != null && casted.atlasPath != null)
|
||||
spr.loadSprite(casted.atlasPath);
|
||||
spr.animation.copyFrom(source.animation);
|
||||
spr.visible = source.visible;
|
||||
spr.alpha = source.alpha;
|
||||
@@ -109,9 +116,8 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
|
||||
|
||||
if (casted != null) {
|
||||
spr.skew.set(casted.skew.x, casted.skew.y);
|
||||
spr.transformMatrix = casted.transformMatrix;
|
||||
spr.matrixExposed = casted.matrixExposed;
|
||||
spr.animOffsets = casted.animOffsets.copy();
|
||||
spr.zoomFactor = casted.zoomFactor;
|
||||
}
|
||||
}
|
||||
return spr;
|
||||
@@ -120,8 +126,6 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
|
||||
public override function update(elapsed:Float)
|
||||
{
|
||||
super.update(elapsed);
|
||||
if (animateAtlas != null)
|
||||
animateAtlas.update(elapsed);
|
||||
|
||||
// hate how it looks like but hey at least its optimized and fast - Nex
|
||||
if (!debugMode && isAnimFinished()) {
|
||||
@@ -131,18 +135,15 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
|
||||
}
|
||||
}
|
||||
|
||||
override function initVars() {
|
||||
super.initVars();
|
||||
_rect2 = FlxRect.get();
|
||||
}
|
||||
|
||||
public function loadSprite(path:String, Unique:Bool = false, Key:String = null)
|
||||
{
|
||||
var noExt = Path.withoutExtension(path);
|
||||
if (Assets.exists('$noExt/Animation.json'))
|
||||
{
|
||||
atlasPath = noExt;
|
||||
animateAtlas = new FlxAnimate(x, y, noExt);
|
||||
}
|
||||
else
|
||||
{
|
||||
frames = Paths.getFrames(path, true);
|
||||
}
|
||||
frames = Paths.getFrames(path, true, null, null, animateSettings);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -172,50 +173,22 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
|
||||
{
|
||||
}
|
||||
|
||||
// ANIMATE ATLAS DRAWING
|
||||
#if REGION
|
||||
public override function draw()
|
||||
{
|
||||
if (animateAtlas != null)
|
||||
{
|
||||
copyAtlasValues();
|
||||
animateAtlas.draw();
|
||||
}
|
||||
else
|
||||
{
|
||||
super.draw();
|
||||
}
|
||||
public override function draw() {
|
||||
// re-implementing the `onDraw` functionality from `FlxSprite` since `FlxAnimate` didn't have this, so we have to add it back in ourselves
|
||||
if (this.isAnimate && this.__drawOverrided) {
|
||||
this.__drawOverrided = false;
|
||||
this.onDraw(this);
|
||||
this.__drawOverrided = true;
|
||||
return;
|
||||
}
|
||||
super.draw();
|
||||
}
|
||||
|
||||
public function copyAtlasValues()
|
||||
{
|
||||
@:privateAccess {
|
||||
animateAtlas.cameras = cameras; // investigate if we can use _cameras
|
||||
animateAtlas.scrollFactor = scrollFactor;
|
||||
animateAtlas.scale = scale;
|
||||
animateAtlas.offset = offset;
|
||||
animateAtlas.frameOffset = frameOffset;
|
||||
animateAtlas.x = x;
|
||||
animateAtlas.y = y;
|
||||
animateAtlas.angle = angle;
|
||||
animateAtlas.alpha = alpha;
|
||||
animateAtlas.visible = visible;
|
||||
animateAtlas.flipX = flipX;
|
||||
animateAtlas.flipY = flipY;
|
||||
animateAtlas.shader = shader;
|
||||
animateAtlas.shaderEnabled = shaderEnabled;
|
||||
animateAtlas.antialiasing = antialiasing;
|
||||
animateAtlas.skew = skew;
|
||||
animateAtlas.transformMatrix = transformMatrix;
|
||||
animateAtlas.matrixExposed = matrixExposed;
|
||||
animateAtlas.colorTransform = colorTransform;
|
||||
}
|
||||
}
|
||||
// ANIMATE ATLAS DRAWING
|
||||
#if REGION
|
||||
|
||||
public override function destroy()
|
||||
{
|
||||
animateAtlas = FlxDestroyUtil.destroy(animateAtlas);
|
||||
|
||||
if (animOffsets != null) {
|
||||
for (key in animOffsets.keys()) {
|
||||
final point = animOffsets[key];
|
||||
@@ -226,6 +199,8 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
|
||||
animOffsets = null;
|
||||
}
|
||||
super.destroy();
|
||||
|
||||
_rect2 = FlxDestroyUtil.put(_rect2);
|
||||
}
|
||||
#end
|
||||
|
||||
@@ -233,27 +208,21 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
|
||||
private inline function __shouldDoZoomFactor()
|
||||
return zoomFactorEnabled && zoomFactor != 1;
|
||||
|
||||
public override function getScreenBounds(?newRect:FlxRect, ?camera:FlxCamera):FlxRect
|
||||
{
|
||||
if (camera == null)
|
||||
camera = FlxG.camera;
|
||||
|
||||
var r = super.getScreenBounds(newRect, camera);
|
||||
|
||||
if(__shouldDoZoomFactor()) {
|
||||
r.x -= camera.width / 2;
|
||||
r.y -= camera.height / 2;
|
||||
|
||||
var ratio = (camera.zoom > 0 ? Math.max : Math.min)(0, FlxMath.lerp(1 / camera.zoom, 1, zoomFactor));
|
||||
r.x *= ratio;
|
||||
r.y *= ratio;
|
||||
r.width *= ratio;
|
||||
r.height *= ratio;
|
||||
|
||||
r.x += camera.width / 2;
|
||||
r.y += camera.height / 2;
|
||||
}
|
||||
return r;
|
||||
private inline function __prepareZoomFactor(?rect:FlxRect, camera:FlxCamera):FlxRect {
|
||||
if (Flags.USE_LEGACY_ZOOM_FACTOR)
|
||||
return (rect ?? FlxRect.get()).set(
|
||||
camera.width * 0.5,
|
||||
camera.height * 0.5,
|
||||
(camera.scaleX > 0 ? Math.max : Math.min)(0, FlxMath.lerp(1 / camera.scaleX, 1, zoomFactor)),
|
||||
(camera.scaleY > 0 ? Math.max : Math.min)(0, FlxMath.lerp(1 / camera.scaleY, 1, zoomFactor))
|
||||
);
|
||||
else
|
||||
return (rect ?? FlxRect.get()).set(
|
||||
camera.width * 0.5 + camera.scroll.x * scrollFactor.x,
|
||||
camera.height * 0.5 + camera.scroll.y * scrollFactor.y,
|
||||
(camera.scaleX > 0 ? Math.max : Math.min)(0, FlxMath.lerp(1 / camera.scaleX, 1, zoomFactor)),
|
||||
(camera.scaleY > 0 ? Math.max : Math.min)(0, FlxMath.lerp(1 / camera.scaleY, 1, zoomFactor))
|
||||
);
|
||||
}
|
||||
|
||||
override public function isOnScreen(?camera:FlxCamera):Bool
|
||||
@@ -270,20 +239,6 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
|
||||
return camera.containsRect(bounds);
|
||||
}
|
||||
|
||||
// ZOOM FACTOR RENDERING
|
||||
public override function doAdditionalMatrixStuff(matrix:FlxMatrix, camera:FlxCamera)
|
||||
{
|
||||
super.doAdditionalMatrixStuff(matrix, camera);
|
||||
if(__shouldDoZoomFactor()) {
|
||||
matrix.translate(-camera.width / 2, -camera.height / 2);
|
||||
|
||||
var requestedZoom = (camera.zoom >= 0 ? Math.max : Math.min)(FlxMath.lerp(1, camera.zoom, zoomFactor), 0);
|
||||
var diff = requestedZoom / camera.zoom;
|
||||
matrix.scale(diff, diff);
|
||||
matrix.translate(camera.width / 2, camera.height / 2);
|
||||
}
|
||||
}
|
||||
|
||||
// OFFSETTING
|
||||
#if REGION
|
||||
public var animOffsets:Map<String, FlxPoint> = new Map<String, FlxPoint>();
|
||||
@@ -315,13 +270,7 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
|
||||
Force = anim != null && anim.forced;
|
||||
}
|
||||
|
||||
if (animateAtlas != null)
|
||||
{
|
||||
@:privateAccess
|
||||
animateAtlas.anim.play(AnimName, Force, Reversed, Frame);
|
||||
atlasPlayingAnim = AnimName;
|
||||
}
|
||||
else animation.play(AnimName, Force, Reversed, Frame);
|
||||
animation.play(AnimName, Force, Reversed, Frame);
|
||||
|
||||
var daOffset = getAnimOffset(AnimName);
|
||||
frameOffset.set(daOffset.x, daOffset.y);
|
||||
@@ -330,7 +279,7 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
|
||||
lastAnimContext = Context;
|
||||
}
|
||||
|
||||
public inline function addAnim(name:String, prefix:String, frameRate:Float = 24, ?looped:Bool, ?forced:Bool, ?indices:Array<Int>, x:Float = 0, y:Float = 0, animType:XMLAnimType = NONE)
|
||||
public inline function addAnim(name:String, prefix:String, frameRate:Float = 24, ?looped:Bool, ?forced:Bool, ?indices:Array<Int>, x:Float = 0, y:Float = 0, animType:XMLAnimType = NONE, animateAtlasLabel:Bool = false)
|
||||
{
|
||||
return XMLUtil.addAnimToSprite(this, {
|
||||
name: name,
|
||||
@@ -341,22 +290,16 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
|
||||
x: x,
|
||||
y: y,
|
||||
indices: indices,
|
||||
forced: forced
|
||||
forced: forced,
|
||||
label: animateAtlasLabel
|
||||
});
|
||||
}
|
||||
|
||||
public inline function removeAnim(name:String)
|
||||
{
|
||||
if (animateAtlas != null)
|
||||
@:privateAccess animateAtlas.anim.animsMap.remove(name);
|
||||
else
|
||||
animation.remove(name);
|
||||
public inline function removeAnim(name:String) {
|
||||
animation.remove(name);
|
||||
}
|
||||
|
||||
public function getAnim(name:String):OneOfTwo<FlxAnimation, FlxSymbolAnimation>
|
||||
{
|
||||
if(animateAtlas != null)
|
||||
return animateAtlas.anim.getByName(name);
|
||||
public function getAnim(name:String):OneOfTwo<FlxAnimation, FlxAnimateAnimation> {
|
||||
return animation.getByName(name);
|
||||
}
|
||||
|
||||
@@ -367,40 +310,26 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
|
||||
return FlxPoint.weak(0, 0);
|
||||
}
|
||||
|
||||
public inline function hasAnim(AnimName:String):Bool @:privateAccess
|
||||
return animateAtlas != null ? (animateAtlas.anim.animsMap.exists(AnimName)
|
||||
|| animateAtlas.anim.symbolDictionary.exists(AnimName)) : animation.exists(AnimName);
|
||||
public inline function hasAnim(AnimName:String):Bool
|
||||
return animation.exists(AnimName);
|
||||
|
||||
public inline function getAnimName() {
|
||||
return (animateAtlas != null) ? atlasPlayingAnim : animation.name;
|
||||
}
|
||||
public inline function getAnimName()
|
||||
return animation.name;
|
||||
|
||||
public inline function isAnimReversed():Bool {
|
||||
return animateAtlas != null ? animateAtlas.anim.reversed : animation.curAnim != null ? animation.curAnim.reversed : false;
|
||||
}
|
||||
public inline function isAnimReversed():Bool
|
||||
return animation.curAnim?.reversed ?? false;
|
||||
|
||||
public inline function getNameList():Array<String> {
|
||||
if (animateAtlas != null)
|
||||
return [for (name in @:privateAccess animateAtlas.anim.animsMap.keys()) name];
|
||||
else
|
||||
return animation.getNameList();
|
||||
}
|
||||
public inline function getNameList():Array<String>
|
||||
return animation.getNameList();
|
||||
|
||||
public inline function stopAnim()
|
||||
{
|
||||
if (animateAtlas != null)
|
||||
animateAtlas.anim.pause();
|
||||
else
|
||||
animation.stop();
|
||||
}
|
||||
animation.stop();
|
||||
|
||||
public inline function isAnimFinished() {
|
||||
return animateAtlas != null ? animateAtlas.anim.finished : (animation.curAnim != null ? animation.curAnim.finished : true);
|
||||
}
|
||||
public inline function isAnimFinished()
|
||||
return animation.curAnim?.finished ?? true;
|
||||
|
||||
public inline function isAnimAtEnd() {
|
||||
return animateAtlas != null ? animateAtlas.anim.isAtEnd : (animation.curAnim != null ? animation.curAnim.isAtEnd : false);
|
||||
}
|
||||
public inline function isAnimAtEnd()
|
||||
return animation.curAnim?.isAtEnd ?? false;
|
||||
|
||||
override function updateAnimation(elapsed:Float) {
|
||||
if (animEnabled)
|
||||
@@ -422,10 +351,38 @@ class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements I
|
||||
return beatInterval = v;
|
||||
}
|
||||
|
||||
@:noCompletion private inline function get_globalCurFrame() {
|
||||
return animateAtlas != null ? (animateAtlas.anim.curFrame) : (animation.curAnim != null ? animation.curAnim.curFrame : 0);
|
||||
}
|
||||
@:noCompletion
|
||||
@:deprecated("`FunkinSprite.animateAtlas` is deprecated, just use `FunkinSprite` instead")
|
||||
public function get_animateAtlas():FunkinSprite
|
||||
return isAnimate ? this : null;
|
||||
|
||||
@:noCompletion private inline function get_globalCurFrame()
|
||||
return animation.curAnim?.curFrame ?? 0;
|
||||
|
||||
@:noCompletion private inline function set_globalCurFrame(val:Int) {
|
||||
return animateAtlas != null ? (animateAtlas.anim.curFrame = val) : (animation.curAnim != null ? animation.curAnim.curFrame = val : val);
|
||||
if (animation.curAnim != null)
|
||||
animation.curAnim.curFrame = val;
|
||||
return val;
|
||||
}
|
||||
|
||||
override function prepareDrawMatrix(matrix:FlxMatrix, camera:FlxCamera):Void {
|
||||
super.prepareDrawMatrix(matrix, camera);
|
||||
|
||||
if (__shouldDoZoomFactor()) {
|
||||
__prepareZoomFactor(_rect2, camera);
|
||||
matrix.setTo(
|
||||
matrix.a * _rect2.width, matrix.b * _rect2.height,
|
||||
matrix.c * _rect2.width, matrix.d * _rect2.height,
|
||||
(matrix.tx - _rect2.x) * _rect2.width + _rect2.x,
|
||||
(matrix.ty - _rect2.y) * _rect2.height + _rect2.y,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
override function checkFlipX() {
|
||||
return super.checkFlipX() != camera.flipX;
|
||||
}
|
||||
override function checkFlipY() {
|
||||
return super.checkFlipY() != camera.flipY;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,98 @@
|
||||
package funkin.backend;
|
||||
|
||||
import flixel.FlxCamera;
|
||||
import flixel.FlxG;
|
||||
import flixel.math.FlxMath;
|
||||
import flixel.text.FlxText;
|
||||
import flixel.util.FlxColor;
|
||||
import funkin.backend.system.Flags;
|
||||
|
||||
class FunkinText extends FlxText {
|
||||
public function new(X:Float = 0, Y:Float = 0, FieldWidth:Float = 0, ?Text:String, ?Size:Int, Border:Bool = true) {
|
||||
if (Size == null) Size = Flags.DEFAULT_FONT_SIZE;
|
||||
class FunkinText extends FlxText
|
||||
{
|
||||
public var zoomFactor:Float = 1;
|
||||
public var zoomFactorEnabled:Bool = true;
|
||||
|
||||
public function new(X:Float = 0, Y:Float = 0, FieldWidth:Float = 0, ?Text:String, ?Size:Int, Border:Bool = true)
|
||||
{
|
||||
if (Size == null)
|
||||
Size = Flags.DEFAULT_FONT_SIZE;
|
||||
|
||||
super(X, Y, FieldWidth, Text, Size);
|
||||
|
||||
setFormat(Paths.font(Flags.DEFAULT_FONT), Size, FlxColor.WHITE);
|
||||
if (Border) {
|
||||
|
||||
if (Border)
|
||||
{
|
||||
borderStyle = OUTLINE;
|
||||
borderSize = 1;
|
||||
borderColor = 0xFF000000;
|
||||
}
|
||||
}
|
||||
|
||||
private inline function __shouldDoZoomFactor():Bool
|
||||
{
|
||||
return zoomFactorEnabled && zoomFactor != 1;
|
||||
}
|
||||
|
||||
private inline function __getZoomScaleX(camera:FlxCamera):Float
|
||||
{
|
||||
return (camera.scaleX > 0 ? Math.max : Math.min)(0, FlxMath.lerp(1 / camera.scaleX, 1, zoomFactor));
|
||||
}
|
||||
|
||||
private inline function __getZoomScaleY(camera:FlxCamera):Float
|
||||
{
|
||||
return (camera.scaleY > 0 ? Math.max : Math.min)(0, FlxMath.lerp(1 / camera.scaleY, 1, zoomFactor));
|
||||
}
|
||||
|
||||
private inline function __getZoomAnchorX(camera:FlxCamera):Float
|
||||
{
|
||||
if (Flags.USE_LEGACY_ZOOM_FACTOR)
|
||||
return camera.width * 0.5;
|
||||
|
||||
return camera.width * 0.5 + camera.scroll.x * scrollFactor.x;
|
||||
}
|
||||
|
||||
private inline function __getZoomAnchorY(camera:FlxCamera):Float
|
||||
{
|
||||
if (Flags.USE_LEGACY_ZOOM_FACTOR)
|
||||
return camera.height * 0.5;
|
||||
|
||||
return camera.height * 0.5 + camera.scroll.y * scrollFactor.y;
|
||||
}
|
||||
|
||||
override public function draw():Void
|
||||
{
|
||||
if (!__shouldDoZoomFactor())
|
||||
{
|
||||
super.draw();
|
||||
return;
|
||||
}
|
||||
|
||||
var camera:FlxCamera = this.camera;
|
||||
|
||||
if (camera == null)
|
||||
camera = FlxG.camera;
|
||||
|
||||
var oldX:Float = x;
|
||||
var oldY:Float = y;
|
||||
var oldScaleX:Float = scale.x;
|
||||
var oldScaleY:Float = scale.y;
|
||||
|
||||
var zoomScaleX:Float = __getZoomScaleX(camera);
|
||||
var zoomScaleY:Float = __getZoomScaleY(camera);
|
||||
|
||||
var anchorX:Float = __getZoomAnchorX(camera);
|
||||
var anchorY:Float = __getZoomAnchorY(camera);
|
||||
|
||||
x = (x - anchorX) * zoomScaleX + anchorX;
|
||||
y = (y - anchorY) * zoomScaleY + anchorY;
|
||||
|
||||
scale.set(scale.x * zoomScaleX, scale.y * zoomScaleY);
|
||||
|
||||
super.draw();
|
||||
|
||||
x = oldX;
|
||||
y = oldY;
|
||||
scale.set(oldScaleX, oldScaleY);
|
||||
}
|
||||
}
|
||||
@@ -236,6 +236,12 @@ class MusicBeatSubstate extends FlxSubState implements IBeatCancellableReceiver
|
||||
super.openSubState(e.substate is FlxSubState ? cast e.substate : subState);
|
||||
}
|
||||
|
||||
public override function closeSubState() {
|
||||
var e = event("onCloseSubState", EventManager.get(StateEvent).recycle(subState));
|
||||
if (!e.cancelled)
|
||||
super.closeSubState();
|
||||
}
|
||||
|
||||
public override function onResize(w:Int, h:Int) {
|
||||
super.onResize(w, h);
|
||||
event("onResize", EventManager.get(ResizeEvent).recycle(w, h, null, null));
|
||||
|
||||
@@ -114,12 +114,8 @@ class MusicBeatTransition extends MusicBeatSubstate {
|
||||
}
|
||||
|
||||
if (transitionSprite != null) {
|
||||
if (transitionSprite.animateAtlas == null) {
|
||||
transitionSprite.setGraphicSize(transitionCamera.width, transitionCamera.height);
|
||||
transitionSprite.updateHitbox();
|
||||
} else {
|
||||
transitionSprite.screenCenter();
|
||||
}
|
||||
transitionSprite.setGraphicSize(transitionCamera.width, transitionCamera.height);
|
||||
transitionSprite.updateHitbox();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,9 +5,21 @@ import funkin.backend.assets.TranslatedAssetLibrary;
|
||||
#end
|
||||
import funkin.backend.assets.IModsAssetLibrary;
|
||||
import lime.utils.AssetLibrary;
|
||||
import haxe.ds.Map;
|
||||
|
||||
class AssetsLibraryList extends AssetLibrary {
|
||||
public var libraries:Array<AssetLibrary> = [];
|
||||
public var cleanLibraries(get, never):Array<AssetLibrary>;
|
||||
function get_cleanLibraries():Array<AssetLibrary> {
|
||||
return [for (l in libraries) getCleanLibrary(l)];
|
||||
}
|
||||
|
||||
// is true if any library in `libraries` contains some kind of compressed library.
|
||||
public var hasCompressedLibrary(get, never):Bool;
|
||||
function get_hasCompressedLibrary():Bool {
|
||||
for (l in libraries) if (getCleanLibrary(l).isCompressed) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@:allow(funkin.backend.system.Main)
|
||||
@:allow(funkin.backend.system.MainState)
|
||||
@@ -18,6 +30,9 @@ class AssetsLibraryList extends AssetLibrary {
|
||||
public var transLib:TranslatedAssetLibrary;
|
||||
#end
|
||||
|
||||
private var cachePaths:Map<String, AssetLibrary> = [];
|
||||
private var cacheNonExistentPaths:Map<String, Int> = [];
|
||||
|
||||
public function removeLibrary(lib:AssetLibrary) {
|
||||
if (lib != null) {
|
||||
libraries.remove(lib);
|
||||
@@ -41,12 +56,29 @@ class AssetsLibraryList extends AssetLibrary {
|
||||
public function existsSpecific(id:String, type:String, source:AssetSource = BOTH) {
|
||||
if (!id.startsWith("assets/") && existsSpecific('assets/$id', type, source))
|
||||
return true;
|
||||
|
||||
// There's a mod that heavily relies on addons and that can causes lags just to get a path.
|
||||
final sec = Date.now().getSeconds();
|
||||
if (cacheNonExistentPaths.exists(id) && sec - 10 < cacheNonExistentPaths.get(id)) {
|
||||
return false;
|
||||
}
|
||||
else if (cachePaths.exists(id)) {
|
||||
if (cachePaths.get(id).exists(id, type)) return true;
|
||||
else cachePaths.remove(id);
|
||||
}
|
||||
|
||||
|
||||
for(k=>l in libraries) {
|
||||
if (shouldSkipLib(l, source)) continue;
|
||||
if (l.exists(id, type)) {
|
||||
//trace("EXISTS", id, type, source);
|
||||
cachePaths.set(id, l);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
//trace("DOESNT EXISTS", id, type, source);
|
||||
cacheNonExistentPaths.set(id, sec);
|
||||
return false;
|
||||
}
|
||||
public override inline function exists(id:String, type:String):Bool
|
||||
@@ -141,6 +173,16 @@ class AssetsLibraryList extends AssetLibrary {
|
||||
public override inline function getAsset(id:String, type:String):Dynamic
|
||||
return getSpecificAsset(id, type, BOTH);
|
||||
|
||||
public override function list(type:String):Array<String> {
|
||||
// idk if there's a more efficient way tbh, correct if u find better
|
||||
var files:Map<String, Bool> = [];
|
||||
for(k=>l in libraries) {
|
||||
for(f in l.list(type))
|
||||
files.set(f, false);
|
||||
}
|
||||
return [for(k=>e in files) k];
|
||||
}
|
||||
|
||||
public override function isLocal(id:String, type:String) {
|
||||
return true;
|
||||
}
|
||||
@@ -175,6 +217,7 @@ class AssetsLibraryList extends AssetLibrary {
|
||||
public function reset() {
|
||||
unloadLibraries();
|
||||
|
||||
cachePaths.clear();
|
||||
libraries = [];
|
||||
|
||||
// adds default libraries in again
|
||||
|
||||
@@ -83,10 +83,11 @@ class ModsFolder {
|
||||
*/
|
||||
public static function loadModLib(path:String, force:Bool = false, ?modName:String) {
|
||||
#if MOD_SUPPORT
|
||||
if (FileSystem.exists('$path.zip'))
|
||||
return loadLibraryFromZip('$path'.toLowerCase(), '$path.zip', force, modName);
|
||||
else
|
||||
return loadLibraryFromFolder('$path'.toLowerCase(), '$path', force, modName);
|
||||
for (ext in Flags.ALLOWED_ZIP_EXTENSIONS) {
|
||||
if (!FileSystem.exists('$path.$ext')) continue;
|
||||
return loadLibraryFromZip('$path'.toLowerCase(), '$path.$ext', force, modName);
|
||||
}
|
||||
return loadLibraryFromFolder('$path'.toLowerCase(), '$path', force, modName);
|
||||
|
||||
#else
|
||||
return null;
|
||||
@@ -96,27 +97,16 @@ class ModsFolder {
|
||||
public static function getModsList():Array<String> {
|
||||
var mods:Array<String> = [];
|
||||
#if MOD_SUPPORT
|
||||
if (!FileSystem.exists(modsPath)) {
|
||||
// Mods directory does not exist yet, create it
|
||||
FileSystem.createDirectory(modsPath);
|
||||
}
|
||||
// Mods directory does not exist yet, create it
|
||||
if (!FileSystem.exists(modsPath)) FileSystem.createDirectory(modsPath);
|
||||
|
||||
final modsList:Array<String> = FileSystem.readDirectory(modsPath);
|
||||
|
||||
if (modsList == null || modsList.length <= 0)
|
||||
return mods;
|
||||
if (modsList == null || modsList.length <= 0) return mods;
|
||||
|
||||
for (modFolder in modsList) {
|
||||
if (FileSystem.isDirectory(modsPath + modFolder)) {
|
||||
mods.push(modFolder);
|
||||
} else {
|
||||
var ext = Path.extension(modFolder).toLowerCase();
|
||||
switch(ext) {
|
||||
case 'zip':
|
||||
// is a zip mod!!
|
||||
mods.push(Path.withoutExtension(modFolder));
|
||||
}
|
||||
}
|
||||
if (FileSystem.isDirectory(modsPath + modFolder)) mods.push(modFolder);
|
||||
else if (Flags.ALLOWED_ZIP_EXTENSIONS.contains(Path.extension(modFolder))) mods.push(Path.withoutExtension(modFolder));
|
||||
}
|
||||
#end
|
||||
return mods;
|
||||
@@ -128,7 +118,9 @@ class ModsFolder {
|
||||
#if TRANSLATIONS_SUPPORT
|
||||
if(skipTranslated && (l is TranslatedAssetLibrary)) continue;
|
||||
#end
|
||||
if (l is ScriptedAssetLibrary || l is IModsAssetLibrary) libs.push(cast(l, IModsAssetLibrary));
|
||||
// No need to check for it being a `ScriptedAssetLibrary`, if `ScriptedAssetLibrary` extends ModsFolderLibrary, which implements `IModsAssetLibrary`
|
||||
// If you have to revert this change then uhhhhh wasn't me, trust 🙏
|
||||
if (/*l is ScriptedAssetLibrary ||*/ l is IModsAssetLibrary) libs.push(cast(l, IModsAssetLibrary));
|
||||
}
|
||||
return libs;
|
||||
}
|
||||
|
||||
@@ -149,6 +149,22 @@ class ModsFolderLibrary extends AssetLibrary implements IModsAssetLibrary {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public override function list(type:String):Array<String> {
|
||||
var result = [];
|
||||
__listAppend(result, '');
|
||||
return result;
|
||||
}
|
||||
|
||||
function __listAppend(arr:Array<String>, folder:String) {
|
||||
for(file in FileSystem.readDirectory('$basePath/$folder')) {
|
||||
var fullPath = '$basePath/$folder/$file';
|
||||
if (FileSystem.isDirectory(fullPath))
|
||||
__listAppend(arr, '$folder$file/');
|
||||
else
|
||||
arr.push('$prefix$folder$file');
|
||||
}
|
||||
}
|
||||
#end
|
||||
|
||||
// Backwards compat
|
||||
|
||||
@@ -47,7 +47,7 @@ class MultiFramesCollection extends FlxFramesCollection
|
||||
public function addFrames(collection:FlxFramesCollection) {
|
||||
if (collection == null || collection.frames == null) return;
|
||||
|
||||
collection.parent.useCount++;
|
||||
collection.parent.incrementUseCount();
|
||||
parentedFrames.push(collection);
|
||||
|
||||
for(f in collection.frames) {
|
||||
@@ -63,7 +63,7 @@ class MultiFramesCollection extends FlxFramesCollection
|
||||
if(parentedFrames != null) {
|
||||
for(collection in parentedFrames) {
|
||||
if(collection != null)
|
||||
collection.parent.useCount--;
|
||||
collection.parent.decrementUseCount();
|
||||
}
|
||||
parentedFrames = null;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import funkin.backend.scripting.Script;
|
||||
import haxe.io.Path;
|
||||
import lime.utils.AssetLibrary;
|
||||
import openfl.utils.Assets as OpenFlAssets;
|
||||
import animate.FlxAnimateFrames;
|
||||
|
||||
using StringTools;
|
||||
|
||||
@@ -174,6 +175,9 @@ class Paths
|
||||
inline static public function getSparrowAtlas(key:String, ?library:String, ?ext:String)
|
||||
return FlxAtlasFrames.fromSparrow(image(key, library, ext), file('images/$key.xml', library));
|
||||
|
||||
inline static public function getAnimateAtlasAlt(key:String, ?settings:FlxAnimateSettings)
|
||||
return FlxAnimateFrames.fromAnimate(key, null, null, null, false, settings);
|
||||
|
||||
inline static public function getSparrowAtlasAlt(key:String, ?ext:String)
|
||||
return FlxAtlasFrames.fromSparrow('$key.${ext != null ? ext : Flags.IMAGE_EXT}', '$key.xml');
|
||||
|
||||
@@ -190,14 +194,14 @@ class Paths
|
||||
return FlxAtlasFrames.fromAseprite('$key.${ext != null ? ext : Flags.IMAGE_EXT}', '$key.json');
|
||||
|
||||
inline static public function getAssetsRoot():String
|
||||
return ModsFolder.currentModFolder != null ? '${ModsFolder.modsPath}${ModsFolder.currentModFolder}' : #if (sys && TEST_BUILD) './${Main.pathBack}assets/' #else './assets' #end;
|
||||
return ModsFolder.currentModFolder != null ? '${ModsFolder.modsPath}${ModsFolder.currentModFolder}' : #if (sys && TEST_BUILD) './${Main.pathBack}assets/' #else './assets' #end;
|
||||
|
||||
/**
|
||||
* Gets frames at specified path.
|
||||
* @param key Path to the frames
|
||||
* @param library (Additional) library to load the frames from.
|
||||
*/
|
||||
public static function getFrames(key:String, assetsPath:Bool = false, ?library:String, ?ext:String = null) {
|
||||
public static function getFrames(key:String, assetsPath:Bool = false, ?library:String, ?ext:String = null, ?animateSettings:FlxAnimateSettings) {
|
||||
if (tempFramesCache.exists(key)) {
|
||||
var frames = tempFramesCache[key];
|
||||
if (frames != null && frames.parent != null && frames.parent.bitmap != null && frames.parent.bitmap.readable)
|
||||
@@ -205,7 +209,7 @@ class Paths
|
||||
else
|
||||
tempFramesCache.remove(key);
|
||||
}
|
||||
return tempFramesCache[key] = loadFrames(assetsPath ? key : Paths.image(key, library, true, ext), false, null, false, ext);
|
||||
return tempFramesCache[key] = loadFrames(assetsPath ? key : Paths.image(key, library, true, ext), false, null, false, ext, animateSettings);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -242,7 +246,7 @@ class Paths
|
||||
* @param Ext Extension of the image.
|
||||
* @return FlxFramesCollection Frames
|
||||
*/
|
||||
static function loadFrames(path:String, Unique:Bool = false, Key:String = null, SkipAtlasCheck:Bool = false, SkipMultiCheck:Bool = false, ?Ext:String = null):FlxFramesCollection {
|
||||
static function loadFrames(path:String, Unique:Bool = false, Key:String = null, SkipAtlasCheck:Bool = false, SkipMultiCheck:Bool = false, ?Ext:String = null, ?animateSettings:FlxAnimateSettings):FlxFramesCollection {
|
||||
var noExt = Path.withoutExtension(path);
|
||||
var ext = Ext != null ? Ext : Flags.IMAGE_EXT;
|
||||
|
||||
@@ -263,6 +267,8 @@ class Paths
|
||||
cur++;
|
||||
}
|
||||
return finalFrames;
|
||||
} else if (Assets.exists('$noExt/Animation.json')) {
|
||||
return Paths.getAnimateAtlasAlt(noExt, animateSettings);
|
||||
} else if (Assets.exists('$noExt.xml')) {
|
||||
return Paths.getSparrowAtlasAlt(noExt, ext);
|
||||
} else if (Assets.exists('$noExt.txt')) {
|
||||
|
||||
@@ -108,6 +108,8 @@ class TranslatedAssetLibrary extends AssetLibrary implements IModsAssetLibrary {
|
||||
return null;
|
||||
}
|
||||
|
||||
// TODO: list support for TranslatedAssetLibrary (idk how it works)
|
||||
|
||||
#if MOD_SUPPORT
|
||||
public var _parsedAsset:String = null; // Theres no need to actually make this work - Nex
|
||||
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
package funkin.backend.assets;
|
||||
|
||||
import funkin.backend.system.Flags;
|
||||
|
||||
import haxe.io.Path;
|
||||
import lime.graphics.Image;
|
||||
import lime.media.AudioBuffer;
|
||||
import lime.text.Font;
|
||||
import lime.utils.Bytes;
|
||||
import openfl.utils.AssetLibrary;
|
||||
import sys.io.File;
|
||||
|
||||
#if MOD_SUPPORT
|
||||
import funkin.backend.utils.SysZip.SysZipEntry;
|
||||
@@ -15,15 +18,16 @@ class ZipFolderLibrary extends AssetLibrary implements IModsAssetLibrary {
|
||||
public var basePath:String;
|
||||
public var modName:String;
|
||||
public var libName:String;
|
||||
public var useImageCache:Bool = false;
|
||||
public var prefix = 'assets/';
|
||||
|
||||
|
||||
public var zip:SysZip;
|
||||
public var assets:Map<String, SysZipEntry> = [];
|
||||
public var lowerCaseAssets:Map<String, SysZipEntry> = [];
|
||||
public var nameMap:Map<String, String> = [];
|
||||
|
||||
public function new(basePath:String, libName:String, ?modName:String) {
|
||||
public var PRELOAD_VIDEOS:Bool = true;
|
||||
|
||||
public function new(basePath:String, libName:String, ?modName:String, ?preloadVideos:Bool = true) {
|
||||
this.libName = libName;
|
||||
|
||||
this.basePath = basePath;
|
||||
@@ -31,21 +35,59 @@ class ZipFolderLibrary extends AssetLibrary implements IModsAssetLibrary {
|
||||
this.modName = (modName == null) ? libName : modName;
|
||||
|
||||
zip = SysZip.openFromFile(basePath);
|
||||
zip.read();
|
||||
for(entry in zip.entries) {
|
||||
lowerCaseAssets[entry.fileName.toLowerCase()] = assets[entry.fileName.toLowerCase()] = assets[entry.fileName] = entry;
|
||||
nameMap.set(entry.fileName.toLowerCase(), entry.fileName);
|
||||
if (entry.fileName.length < 0 || entry.fileName.endsWith("/")) continue;
|
||||
|
||||
var name:String = entry.fileName.toLowerCase(); // calling .toLowerCase a million times is never the solution
|
||||
lowerCaseAssets[name] = assets[name] = assets[entry.fileName] = entry;
|
||||
nameMap.set(name, entry.fileName);
|
||||
}
|
||||
|
||||
super();
|
||||
|
||||
isCompressed = true;
|
||||
|
||||
// don't override default value of true if the file exists.
|
||||
// by default `PRELOAD_VIDEOS` is true so you will never need to add this file, but in the case of it being false this is a backup method.
|
||||
PRELOAD_VIDEOS = (!PRELOAD_VIDEOS) ? exists("assets/data/PRECACHE_VIDEOS", "TEXT") : PRELOAD_VIDEOS;
|
||||
|
||||
// if (PRELOAD_VIDEOS) precacheVideos(); // we do this in `MainState` now to handle for `Flags.VIDEO_EXT` :)
|
||||
}
|
||||
|
||||
public function precacheVideos() {
|
||||
_videoExtensions = [Flags.VIDEO_EXT];
|
||||
|
||||
videoCacheRemap = [];
|
||||
for (entry in zip.entries) {
|
||||
var name = entry.fileName.toLowerCase();
|
||||
if (_videoExtensions.contains(Path.extension(name))) getPath(prefix+name);
|
||||
}
|
||||
|
||||
var count:Int = 0;
|
||||
for (_ in videoCacheRemap.keys()) count++;
|
||||
if (count <= 0) return;
|
||||
trace('Precached $count video${(count == 1) ? "" : "s"}');
|
||||
}
|
||||
|
||||
// Now we have supports for videos in ZIP!!
|
||||
public var _videoExtensions:Array<String> = [Flags.VIDEO_EXT];
|
||||
public var videoCacheRemap:Map<String, String> = [];
|
||||
public function getVideoRemap(originalPath:String):String {
|
||||
if (!_videoExtensions.contains(Path.extension(_parsedAsset))) return originalPath;
|
||||
if (videoCacheRemap.exists(originalPath)) return videoCacheRemap.get(originalPath);
|
||||
|
||||
// We adding the length of the string to counteract folder in folder naming duplicates.
|
||||
var newPath = './.temp/${_parsedAsset.length}-zipvideo-${_parsedAsset.split("/").pop()}';
|
||||
File.saveBytes(newPath, unzip(assets[_parsedAsset]));
|
||||
videoCacheRemap.set(originalPath, newPath);
|
||||
return newPath;
|
||||
}
|
||||
|
||||
function toString():String {
|
||||
return '(ZipFolderLibrary: $libName/$modName)';
|
||||
return '(ZipFolderLibrary: $libName/$modName | ${zip.entries.length} entries | Detected Video Extensions: ${_videoExtensions.join(", ")})';
|
||||
}
|
||||
|
||||
public var _parsedAsset:String;
|
||||
|
||||
public override function getAudioBuffer(id:String):AudioBuffer {
|
||||
__parseAsset(id);
|
||||
return AudioBuffer.fromBytes(unzip(assets[_parsedAsset]));
|
||||
@@ -68,15 +110,12 @@ class ZipFolderLibrary extends AssetLibrary implements IModsAssetLibrary {
|
||||
return getAssetPath();
|
||||
}
|
||||
|
||||
|
||||
|
||||
public inline function unzip(f:SysZipEntry)
|
||||
return f == null ? null : zip.unzipEntry(f);
|
||||
public inline function unzip(f:SysZipEntry) return (f == null) ? null : zip.unzipEntry(f);
|
||||
|
||||
public function __parseAsset(asset:String):Bool {
|
||||
if (!asset.startsWith(prefix)) return false;
|
||||
_parsedAsset = asset.substr(prefix.length);
|
||||
if(ModsFolder.useLibFile) {
|
||||
if (ModsFolder.useLibFile) {
|
||||
var file = new haxe.io.Path(_parsedAsset);
|
||||
if(file.file.startsWith("LIB_")) {
|
||||
var library = file.file.substr(4);
|
||||
@@ -87,8 +126,7 @@ class ZipFolderLibrary extends AssetLibrary implements IModsAssetLibrary {
|
||||
}
|
||||
|
||||
_parsedAsset = _parsedAsset.toLowerCase();
|
||||
if(nameMap.exists(_parsedAsset))
|
||||
_parsedAsset = nameMap.get(_parsedAsset);
|
||||
if (nameMap.exists(_parsedAsset)) _parsedAsset = nameMap.get(_parsedAsset);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -103,9 +141,8 @@ class ZipFolderLibrary extends AssetLibrary implements IModsAssetLibrary {
|
||||
return assets[_parsedAsset] != null;
|
||||
}
|
||||
|
||||
private function getAssetPath() {
|
||||
trace('[ZIP]$basePath/$_parsedAsset');
|
||||
return '[ZIP]$basePath/$_parsedAsset';
|
||||
private inline function getAssetPath() {
|
||||
return getVideoRemap('$basePath/$_parsedAsset');
|
||||
}
|
||||
|
||||
// TODO: rewrite this to 1 function, like ModsFolderLibrary
|
||||
@@ -154,14 +191,6 @@ class ZipFolderLibrary extends AssetLibrary implements IModsAssetLibrary {
|
||||
return content;
|
||||
}
|
||||
|
||||
// Backwards compat
|
||||
|
||||
@:noCompletion public var zipPath(get, set):String;
|
||||
@:noCompletion private inline function get_zipPath():String {
|
||||
return basePath;
|
||||
}
|
||||
@:noCompletion private inline function set_zipPath(value:String):String {
|
||||
return basePath = value;
|
||||
}
|
||||
public override function list(type:String):Array<String> { return [for(k=>e in nameMap) '$prefix$e']; }
|
||||
}
|
||||
#end
|
||||
@@ -278,9 +278,13 @@ class Chart {
|
||||
var filteredChart = filterChartForSaving(chart, saveSettings.saveMetaInChart, saveSettings.saveLocalEvents, saveSettings.saveGlobalEvents && saveSettings.seperateGlobalEvents != true);
|
||||
|
||||
#if sys
|
||||
var songPath = saveSettings.songFolder == null ? 'songs/${chart.meta.name}' : saveSettings.songFolder, variantSuffix = variant != null && variant != "" ? '-$variant' : "";
|
||||
var metaPath = 'meta$variantSuffix.json', prettyPrint = saveSettings.prettyPrint == true ? Flags.JSON_PRETTY_PRINT : null, temp:String;
|
||||
if ((temp = Paths.assetsTree.getPath('assets/$songPath/$metaPath')) != null) {
|
||||
var songPath = saveSettings.songFolder == null ? 'songs/${chart.meta.name}' : saveSettings.songFolder, variantSuffix = variant != null && variant != "" ? '-$variant' : "", difficultySuffix = difficulty != null && difficulty != "" ? '-$difficulty' : "";
|
||||
var metaPath = 'meta$variantSuffix.json', altMetaPath = 'meta${variantSuffix}${difficultySuffix}.json', prettyPrint = saveSettings.prettyPrint == true ? Flags.JSON_PRETTY_PRINT : null, temp:String;
|
||||
if ((temp = Paths.assetsTree.getPath('assets/$songPath/$altMetaPath')) != null) { //check for difficulty specific
|
||||
songPath = temp.substr(0, temp.length - altMetaPath.length - 1);
|
||||
metaPath = temp;
|
||||
}
|
||||
else if ((temp = Paths.assetsTree.getPath('assets/$songPath/$metaPath')) != null) {
|
||||
songPath = temp.substr(0, temp.length - metaPath.length - 1);
|
||||
metaPath = temp;
|
||||
}
|
||||
@@ -300,6 +304,7 @@ class Chart {
|
||||
var eventsPath = '$songPath/events$variantSuffix.json', events = filterEventsForSaving(chart.events, false, true);
|
||||
|
||||
if (events.length != 0) CoolUtil.safeSaveFile(eventsPath, Json.stringify({events: events}, null, prettyPrint));
|
||||
else if (FileSystem.exists(eventsPath)) FileSystem.deleteFile(eventsPath); // If there's no events to save, then get rid of the file (if it exists already).
|
||||
}
|
||||
#end
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ class EventsData {
|
||||
defValue: "In"
|
||||
},
|
||||
{name: "Mode", type: TDropDown(['direct', 'stage']), defValue: "direct"},
|
||||
{name: "Multiplicative?", type: TBool, defValue: true}
|
||||
{name: "Multiplicative?", type: TBool, defValue: false}
|
||||
],
|
||||
"Camera Modulo Change" => [
|
||||
{name: "Modulo Interval", type: TInt(1, 9999999, 1), defValue: 4},
|
||||
@@ -179,7 +179,8 @@ class EventsData {
|
||||
finalParams.push({
|
||||
name: paramData.name,
|
||||
type: hscriptInterp.expr(hscriptParser.parseString(paramData.type)),
|
||||
defValue: paramData.defaultValue
|
||||
defValue: paramData.defaultValue,
|
||||
saveIfDefault: paramData.saveIfDefault
|
||||
});
|
||||
} catch (e) {trace('Error parsing event param ${paramData.name} - ${eventName}: $e'); finalParams.push(null);}
|
||||
}
|
||||
@@ -196,6 +197,7 @@ typedef EventInfoFile = {
|
||||
var name:String;
|
||||
var type:String;
|
||||
var defaultValue:Dynamic;
|
||||
var ?saveIfDefault:Bool;
|
||||
}>;
|
||||
}
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ class PsychParser {
|
||||
note.time, // TIME
|
||||
note.id, // DATA
|
||||
note.sLen, // SUSTAIN LENGTH
|
||||
chart.noteTypes.getDefault([""])[note.type] // NOTE TYPE
|
||||
chart.noteTypes.getDefault([""])[note.type - 1] // NOTE TYPE
|
||||
];
|
||||
|
||||
if ((swagSection.mustHitSection && strumLine.type == OPPONENT) ||
|
||||
|
||||
@@ -55,9 +55,6 @@ class GlobalScript {
|
||||
reloading = false;
|
||||
MusicBeatState.ALLOW_DEV_RELOAD = _lastAllow_Reload;
|
||||
}
|
||||
|
||||
if (PlayerSettings.solo.controls.DEV_CONSOLE)
|
||||
NativeAPI.allocConsole();
|
||||
});
|
||||
FlxG.signals.preDraw.add(function() {
|
||||
call("preDraw");
|
||||
@@ -109,12 +106,15 @@ class GlobalScript {
|
||||
public static function onModSwitch(newMod:String) {
|
||||
destroy();
|
||||
scripts = new ScriptPack("GlobalScript");
|
||||
for (i in funkin.backend.assets.ModsFolder.getLoadedMods()) {
|
||||
var path = Paths.script('data/global/LIB_$i');
|
||||
for (lib in funkin.backend.assets.ModsFolder.getLoadedModsLibs()) {
|
||||
var modName = lib.modName;
|
||||
var path = Paths.script('data/global/LIB_$modName');
|
||||
var script = Script.create(path);
|
||||
if (script is DummyScript)
|
||||
continue;
|
||||
script.remappedNames.set(script.fileName, '$i:${script.fileName}');
|
||||
if (script is DummyScript) continue;
|
||||
script.remappedNames.set(script.fileName, '$modName:${script.fileName}');
|
||||
// so you can get the current mod's library in GloablScript :)
|
||||
// you should not make this a static variable then all scripts will try to reference the 1 static variable, which will be overwritten :yoikes:
|
||||
script.set("MOD_LIBRARY", lib);
|
||||
scripts.add(script);
|
||||
script.load();
|
||||
}
|
||||
|
||||
@@ -1,14 +1,8 @@
|
||||
package funkin.backend.scripting;
|
||||
|
||||
#if ALLOW_MULTITHREADING
|
||||
import sys.thread.Thread;
|
||||
#end
|
||||
|
||||
import hscript.IHScriptCustomBehaviour;
|
||||
|
||||
class MultiThreadedScript implements IFlxDestroyable implements IHScriptCustomBehaviour {
|
||||
var thread:#if ALLOW_MULTITHREADING Thread #else Dynamic #end;
|
||||
|
||||
/**
|
||||
* Script being ran.
|
||||
*/
|
||||
@@ -46,13 +40,6 @@ class MultiThreadedScript implements IFlxDestroyable implements IHScriptCustomBe
|
||||
|
||||
script.load();
|
||||
|
||||
#if ALLOW_MULTITHREADING
|
||||
thread = Thread.createWithEventLoop(function() {
|
||||
// Prevent the thread from being auto deleted
|
||||
Thread.current().events.promise();
|
||||
});
|
||||
#end
|
||||
|
||||
__variables = Type.getInstanceFields(Type.getClass(this));
|
||||
}
|
||||
|
||||
@@ -69,7 +56,7 @@ class MultiThreadedScript implements IFlxDestroyable implements IHScriptCustomBe
|
||||
|
||||
public function call(func:String, args:Array<Dynamic>) {
|
||||
#if ALLOW_MULTITHREADING
|
||||
thread.events.run(function() {
|
||||
funkin.backend.utils.ThreadUtil.execAsync(() -> {
|
||||
callEnded = false;
|
||||
returnValue = script.call(func, args);
|
||||
callEnded = true;
|
||||
@@ -85,13 +72,5 @@ class MultiThreadedScript implements IFlxDestroyable implements IHScriptCustomBe
|
||||
script.call("destroy");
|
||||
script.destroy();
|
||||
}
|
||||
|
||||
#if ALLOW_MULTITHREADING
|
||||
if (thread != null) {
|
||||
thread.events.runPromised(function() {
|
||||
// close the thing
|
||||
});
|
||||
}
|
||||
#end
|
||||
}
|
||||
}
|
||||
@@ -89,9 +89,9 @@ class Script extends FlxBasic implements IFlxDestroyable {
|
||||
"Paths" => funkin.backend.assets.Paths,
|
||||
"Conductor" => funkin.backend.system.Conductor,
|
||||
"FunkinShader" => funkin.backend.shaders.FunkinShader,
|
||||
"CustomShader" => funkin.backend.shaders.CustomShader,
|
||||
"CustomShader" => funkin.backend.shaders.CustomShader, // deprecated
|
||||
"FunkinText" => funkin.backend.FunkinText,
|
||||
"FlxAnimate" => funkin.backend.FlxAnimate,
|
||||
"FlxAnimate" => animate.FlxAnimate,
|
||||
"FunkinSprite" => funkin.backend.FunkinSprite,
|
||||
"Alphabet" => funkin.menus.ui.Alphabet,
|
||||
"Flags" => funkin.backend.system.Flags,
|
||||
@@ -102,6 +102,7 @@ class Script extends FlxBasic implements IFlxDestroyable {
|
||||
#if sys "ZipUtil" => funkin.backend.utils.ZipUtil, #end
|
||||
"MarkdownUtil" => funkin.backend.utils.MarkdownUtil,
|
||||
"EngineUtil" => funkin.backend.utils.EngineUtil,
|
||||
"ThreadUtil" => funkin.backend.utils.ThreadUtil,
|
||||
"MemoryUtil" => funkin.backend.utils.MemoryUtil,
|
||||
"BitmapUtil" => funkin.backend.utils.BitmapUtil,
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ import flixel.util.FlxDestroyUtil.IFlxDestroyable;
|
||||
|
||||
@:allow(funkin.backend.scripting.ScriptPack)
|
||||
@:autoBuild(funkin.backend.system.macros.EventMacro.build())
|
||||
@:noCustomClass
|
||||
class CancellableEvent implements IFlxDestroyable {
|
||||
@:dox(hide) public var cancelled:Bool = false;
|
||||
@:dox(hide) private var __continueCalls:Bool = true;
|
||||
@@ -54,4 +53,4 @@ class CancellableEvent implements IFlxDestroyable {
|
||||
public function destroy() {
|
||||
data = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
package funkin.backend.scripting.events.gameplay;
|
||||
|
||||
import flixel.math.FlxPoint;
|
||||
import flixel.tweens.FlxTween;
|
||||
|
||||
final class RatingsShowEvent extends CancellableEvent
|
||||
{
|
||||
/**
|
||||
* Rating sprite (may be null)
|
||||
*/
|
||||
public var ratingSprite:Null<FlxSprite>;
|
||||
/**
|
||||
* Number sprite (may be null)
|
||||
*/
|
||||
public var numberSprite:Null<FlxSprite>;
|
||||
/**
|
||||
* Combo sprite (may be null)
|
||||
*/
|
||||
public var comboSprite:Null<FlxSprite>;
|
||||
/**
|
||||
* Scale of combo numbers. (may be null)
|
||||
*/
|
||||
public var numScale:Null<Float> = 0.5;
|
||||
/**
|
||||
* Whenever antialiasing should be enabled on combo numbers. (may be null)
|
||||
*/
|
||||
public var numAntialiasing:Null<Bool> = true;
|
||||
/**
|
||||
* Scale of the rating sprites. (may be null)
|
||||
*/
|
||||
public var ratingScale:Null<Float> = 0.7;
|
||||
/**
|
||||
* Whenever antialiasing should be enabled on ratings. (may be null)
|
||||
*/
|
||||
public var ratingAntialiasing:Null<Bool> = true;
|
||||
/**
|
||||
* Prefix of the rating sprite path. Defaults to "game/score/"
|
||||
*/
|
||||
public var ratingPrefix:String;
|
||||
/**
|
||||
* Suffix of the rating sprite path.
|
||||
*/
|
||||
public var ratingSuffix:String;
|
||||
/**
|
||||
* The sprite's acceleration.
|
||||
*/
|
||||
public var acceleration:Float;
|
||||
/**
|
||||
* A FlxPoint which x or y properties preposition the sprites current velocity.
|
||||
*/
|
||||
public var velocity:FlxPoint;
|
||||
/**
|
||||
* The duration of the sprite's alpha tween.
|
||||
*/
|
||||
public var tweenDuration:Float;
|
||||
/**
|
||||
* The start delay of the sprite's alpha tween.
|
||||
*/
|
||||
public var startDelay:Float;
|
||||
/**
|
||||
* Whenever the Rating sprites should be shown or not.
|
||||
*/
|
||||
public var displayRating:Bool;
|
||||
/**
|
||||
* Whenever the Rating sprites should be shown or not.
|
||||
*/
|
||||
public var displayNumbers:Bool;
|
||||
/**
|
||||
* Whenever the Combo sprite should be shown or not (like old Week 7 patches).
|
||||
*/
|
||||
public var displayCombo:Bool;
|
||||
/**
|
||||
* Whether the sprite should be tweened or not.
|
||||
*/
|
||||
public var playTween:Bool;
|
||||
/**
|
||||
* The amount of spacing for the combo numbers. (may be null)
|
||||
*/
|
||||
public var numSpacing:Null<Float>;
|
||||
/**
|
||||
* The position of the sprite.
|
||||
*/
|
||||
public var position:FlxPoint;
|
||||
/**
|
||||
* Whether to reset the sprite or not.
|
||||
*/
|
||||
public var resetSprite:Bool;
|
||||
/**
|
||||
* The rating name of the rating sprite. (may be null)
|
||||
*/
|
||||
public var rating:Null<String>;
|
||||
/**
|
||||
* The FlxTween instance. (null before "onPostRatingsShown")
|
||||
*/
|
||||
public var tween:Null<FlxTween>;
|
||||
}
|
||||
@@ -11,6 +11,7 @@ final class NoteHitEvent extends CancellableEvent {
|
||||
@:dox(hide) public var unmuteVocals:Bool = true;
|
||||
@:dox(hide) public var enableCamZooming:Bool = true;
|
||||
@:dox(hide) public var autoHitLastSustain:Bool = true;
|
||||
@:dox(hide) public var clipSustain:Bool = true;
|
||||
|
||||
/**
|
||||
* Whenever a miss should be added.
|
||||
@@ -33,11 +34,11 @@ final class NoteHitEvent extends CancellableEvent {
|
||||
/**
|
||||
* Whenever the Rating sprites should be shown or not.
|
||||
*/
|
||||
public var displayRating:Bool;
|
||||
public var displayRating:Null<Bool>;
|
||||
/**
|
||||
* Whenever the Combo sprite should be shown or not (like old Week 7 patches).
|
||||
*/
|
||||
public var displayCombo:Bool;
|
||||
public var displayCombo:Null<Bool>;
|
||||
/**
|
||||
* Note that has been pressed
|
||||
*/
|
||||
@@ -65,11 +66,11 @@ final class NoteHitEvent extends CancellableEvent {
|
||||
/**
|
||||
* Prefix of the rating sprite path. Defaults to "game/score/"
|
||||
*/
|
||||
public var ratingPrefix:String;
|
||||
public var ratingPrefix:Null<String>;
|
||||
/**
|
||||
* Suffix of the rating sprite path.
|
||||
*/
|
||||
public var ratingSuffix:String;
|
||||
public var ratingSuffix:Null<String>;
|
||||
/**
|
||||
* Direction of the press (0 = Left, 1 = Down, 2 = Up, 3 = Right)
|
||||
*/
|
||||
@@ -97,19 +98,19 @@ final class NoteHitEvent extends CancellableEvent {
|
||||
/**
|
||||
* Scale of combo numbers.
|
||||
*/
|
||||
public var numScale:Float = 0.5;
|
||||
public var numScale:Null<Float>;
|
||||
/**
|
||||
* Whenever antialiasing should be enabled on combo number.
|
||||
*/
|
||||
public var numAntialiasing:Bool = true;
|
||||
public var numAntialiasing:Null<Bool>;
|
||||
/**
|
||||
* Scale of ratings.
|
||||
*/
|
||||
public var ratingScale:Float = 0.7;
|
||||
public var ratingScale:Null<Float>;
|
||||
/**
|
||||
* Whenever antialiasing should be enabled on ratings.
|
||||
*/
|
||||
public var ratingAntialiasing:Bool = true;
|
||||
public var ratingAntialiasing:Null<Bool>;
|
||||
/**
|
||||
* Whenever the animation should be forced to play (if it's null it will be forced based on the sprite's data xml, if it has one).
|
||||
*/
|
||||
@@ -145,6 +146,13 @@ final class NoteHitEvent extends CancellableEvent {
|
||||
deleteNote = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevents the sustain from being cut. Only works if the note is a sustain.
|
||||
*/
|
||||
public function preventSustainClip() {
|
||||
clipSustain = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevents the vocals volume from being set to 1 after pressing the note.
|
||||
*/
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
package funkin.backend.shaders;
|
||||
|
||||
import flixel.util.FlxColor;
|
||||
import openfl.display.ShaderParameter;
|
||||
|
||||
@:dox(hide)
|
||||
typedef BlendModeShader =
|
||||
{
|
||||
var uBlendColor:ShaderParameter<Float>;
|
||||
}
|
||||
|
||||
@:dox(hide)
|
||||
class BlendModeEffect
|
||||
{
|
||||
public var shader(default, null):BlendModeShader;
|
||||
|
||||
@:isVar
|
||||
public var color(default, set):FlxColor;
|
||||
|
||||
public function new(shader:BlendModeShader, color:FlxColor):Void
|
||||
{
|
||||
shader.uBlendColor.value = [];
|
||||
this.shader = shader;
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
function set_color(color:FlxColor):FlxColor
|
||||
{
|
||||
shader.uBlendColor.value[0] = color.redFloat;
|
||||
shader.uBlendColor.value[1] = color.greenFloat;
|
||||
shader.uBlendColor.value[2] = color.blueFloat;
|
||||
shader.uBlendColor.value[3] = color.alphaFloat;
|
||||
|
||||
return this.color = color;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,766 @@
|
||||
package funkin.backend.shaders;
|
||||
|
||||
import haxe.Timer;
|
||||
import openfl.filters.BitmapFilter;
|
||||
import openfl.filters.BitmapFilterShader;
|
||||
import openfl.display.BitmapData;
|
||||
import openfl.display.DisplayObjectRenderer;
|
||||
import openfl.display.BlendMode;
|
||||
import openfl.display.Shader;
|
||||
import openfl.geom.Point;
|
||||
import openfl.geom.Rectangle;
|
||||
|
||||
/**
|
||||
This BloomEffect was modified by heihua based on openfl.filters.BlurFilter.
|
||||
The BloomEffect class applies a bloom/glow visual effect to display objects.
|
||||
A bloom effect extracts bright areas from an image, blurs them, and combines
|
||||
them back to create a glowing halo around bright objects. This effect is
|
||||
commonly used to simulate intense light, emissive materials, or to add a
|
||||
dreamy, atmospheric quality to scenes.
|
||||
|
||||
The effect consists of three stages:
|
||||
1. Extraction - Bright pixels above a threshold are extracted
|
||||
2. Blurring - The extracted bright areas are blurred horizontally and vertically
|
||||
3. Combination - The blurred result is blended back with the original image
|
||||
**/
|
||||
|
||||
@:noCustomClass
|
||||
class BloomEffect extends BitmapFilter
|
||||
{
|
||||
@:noCompletion private static var __blurShader:BlurShader;
|
||||
@:noCompletion private static var __combineShader:CombineShader;
|
||||
@:noCompletion private static var __extractShader:ExtractShader;
|
||||
@:noCompletion private static var __extractLowShader:ExtractLowShader;
|
||||
|
||||
/**
|
||||
Values that are a power of 2 (such as 2, 4, 8, 16 and 32) are optimized to render
|
||||
more quickly than other values.
|
||||
**/
|
||||
public var blurX(get, set):Float;
|
||||
|
||||
/**
|
||||
Values that are a power of 2 (such as 2, 4, 8, 16 and 32) are optimized to render
|
||||
more quickly than other values.
|
||||
**/
|
||||
public var blurY(get, set):Float;
|
||||
|
||||
/**
|
||||
The downscaling factor for bloom rendering. Higher values significantly reduce
|
||||
GPU performance cost, but setting values too high may cause noticeable flickering.
|
||||
Recommended range is 8-24.
|
||||
**/
|
||||
public var quality(get, set):Float;
|
||||
|
||||
/**
|
||||
The intensity of the bloom effect. Higher values produce more pronounced bloom.
|
||||
**/
|
||||
public var strength(get, set):Float;
|
||||
|
||||
/**
|
||||
The brightness threshold for bloom extraction. Pixels brighter than this value
|
||||
will contribute to the bloom effect. Value range is 0.0 to 1.0.
|
||||
**/
|
||||
public var threshold(get, set):Float;
|
||||
|
||||
/**
|
||||
The smoothness of the threshold transition in blur shader.
|
||||
Higher values create a smoother transition for brightness correction.
|
||||
Value range is 0.0 to 1.0. Default is 0.1.
|
||||
**/
|
||||
public var smoothness(get, set):Float;
|
||||
|
||||
/**
|
||||
Enables extended rendering area to avoid edge artifacts. Enabling this option
|
||||
will increase performance cost. Generally not required when rendering to camera.
|
||||
**/
|
||||
public var extension(get, set):Bool;
|
||||
|
||||
/**
|
||||
Low-quality pixel sampling mode. Disabling it significantly reduces screen flickering,
|
||||
with minimal performance impact on desktop platforms but a higher
|
||||
performance cost on non-desktop platforms.
|
||||
**/
|
||||
public var useLowQualityExtract(get, set):Bool;
|
||||
|
||||
/**
|
||||
The weights for calculating brightness (RGB to grayscale).
|
||||
Order: [Red, Green, Blue]. Default is [0.2126, 0.7152, 0.0722].
|
||||
**/
|
||||
public var weights(get, set):Array<Float>;
|
||||
|
||||
/**
|
||||
The blend mode used when combining the bloom with the original image.
|
||||
BlendMode currently supports: (BlendMode.ADD, BlendMode.ALPHA, BlendMode.HARDLIGHT,
|
||||
BlendMode.LIGHTEN, BlendMode.MULTIPLY, BlendMode.OVERLAY, BlendMode.SCREEN,
|
||||
BlendMode.COLORDODGE, BlendMode.SOFTLIGHT).
|
||||
Default is BlendMode.ADD.
|
||||
**/
|
||||
public var blendMode(get, set):BlendMode;
|
||||
|
||||
@:noCompletion private var __blurX:Float;
|
||||
@:noCompletion private var __blurY:Float;
|
||||
@:noCompletion private var __horizontalPasses:Int;
|
||||
@:noCompletion private var __quality:Float;
|
||||
@:noCompletion private var __verticalPasses:Int;
|
||||
@:noCompletion private var __strength:Float;
|
||||
@:noCompletion private var __threshold:Float;
|
||||
@:noCompletion private var __smoothness:Float;
|
||||
@:noCompletion private var __extension:Bool;
|
||||
@:noCompletion private var __useLowQualityExtract:Bool;
|
||||
@:noCompletion private var __weights:Array<Float>;
|
||||
@:noCompletion private var __blendMode:BlendMode;
|
||||
|
||||
#if openfljs
|
||||
@:noCompletion private static function __init__()
|
||||
{
|
||||
untyped Object.defineProperties(BloomEffect.prototype, {
|
||||
"blurX": {
|
||||
get: untyped #if haxe4 js.Syntax.code #else __js__ #end ("function () { return this.get_blurX (); }"),
|
||||
set: untyped #if haxe4 js.Syntax.code #else __js__ #end ("function (v) { return this.set_blurX (v); }")
|
||||
},
|
||||
"blurY": {
|
||||
get: untyped #if haxe4 js.Syntax.code #else __js__ #end ("function () { return this.get_blurY (); }"),
|
||||
set: untyped #if haxe4 js.Syntax.code #else __js__ #end ("function (v) { return this.set_blurY (v); }")
|
||||
},
|
||||
"quality": {
|
||||
get: untyped #if haxe4 js.Syntax.code #else __js__ #end ("function () { return this.get_quality (); }"),
|
||||
set: untyped #if haxe4 js.Syntax.code #else __js__ #end ("function (v) { return this.set_quality (v); }")
|
||||
},
|
||||
"strength": {
|
||||
get: untyped #if haxe4 js.Syntax.code #else __js__ #end ("function () { return this.get_strength (); }"),
|
||||
set: untyped #if haxe4 js.Syntax.code #else __js__ #end ("function (v) { return this.set_strength (v); }")
|
||||
},
|
||||
"threshold": {
|
||||
get: untyped #if haxe4 js.Syntax.code #else __js__ #end ("function () { return this.get_threshold (); }"),
|
||||
set: untyped #if haxe4 js.Syntax.code #else __js__ #end ("function (v) { return this.set_threshold (v); }")
|
||||
},
|
||||
"useLowQualityExtract": {
|
||||
get: untyped #if haxe4 js.Syntax.code #else __js__ #end ("function () { return this.get_useLowQualityExtract (); }"),
|
||||
set: untyped #if haxe4 js.Syntax.code #else __js__ #end ("function (v) { return this.set_useLowQualityExtract (v); }")
|
||||
},
|
||||
"weights": {
|
||||
get: untyped #if haxe4 js.Syntax.code #else __js__ #end ("function () { return this.get_weights (); }"),
|
||||
set: untyped #if haxe4 js.Syntax.code #else __js__ #end ("function (v) { return this.set_weights (v); }")
|
||||
},
|
||||
"blendMode": {
|
||||
get: untyped #if haxe4 js.Syntax.code #else __js__ #end ("function () { return this.get_blendMode (); }"),
|
||||
set: untyped #if haxe4 js.Syntax.code #else __js__ #end ("function (v) { return this.set_blendMode (v); }")
|
||||
},
|
||||
});
|
||||
}
|
||||
#end
|
||||
|
||||
/**
|
||||
Initializes the bloom filter with the specified parameters.
|
||||
|
||||
@param blurX The amount to blur horizontally.
|
||||
@param blurY The amount to blur vertically.
|
||||
@param quality The downscaling factor for bloom rendering (higher values reduce
|
||||
GPU cost but may cause flickering if too high).
|
||||
@param strength The intensity of the bloom effect.
|
||||
@param threshold The brightness threshold for bloom extraction (0.0 to 1.0).
|
||||
@param smoothness The smoothness of threshold transition in blur (0.0 to 1.0).
|
||||
@param useLowQualityExtract Enables performance-optimized extraction with
|
||||
potentially more flickering.
|
||||
**/
|
||||
public function new(blurX:Float = 50, blurY:Float = 50, quality:Float = 8, strength:Float = 0.6, threshold:Float = 0.6, smoothness:Float = 0.1, useLowQualityExtract:Bool = true)
|
||||
{
|
||||
super();
|
||||
|
||||
if (__blurShader == null) __blurShader = new BlurShader();
|
||||
if (__combineShader == null) __combineShader = new CombineShader();
|
||||
if (__extractShader == null) __extractShader = new ExtractShader();
|
||||
if (__extractLowShader == null) __extractLowShader = new ExtractLowShader();
|
||||
|
||||
this.blurX = blurX;
|
||||
this.blurY = blurY;
|
||||
this.quality = quality;
|
||||
this.strength = strength;
|
||||
this.threshold = threshold;
|
||||
this.smoothness = smoothness;
|
||||
this.extension = false;
|
||||
this.useLowQualityExtract = useLowQualityExtract;
|
||||
this.weights = [0.2126, 0.7152, 0.0722];
|
||||
this.blendMode = BlendMode.ADD;
|
||||
|
||||
__needSecondBitmapData = true;
|
||||
__preserveObject = true;
|
||||
__renderDirty = true;
|
||||
}
|
||||
|
||||
public override function clone():BitmapFilter
|
||||
{
|
||||
var cloned = new BloomEffect(__blurX, __blurY, __quality, __strength, __threshold, __smoothness, __useLowQualityExtract);
|
||||
cloned.weights = __weights != null ? __weights.copy() : [0.2126, 0.7152, 0.0722];
|
||||
cloned.blendMode = __blendMode;
|
||||
return cloned;
|
||||
}
|
||||
|
||||
@:noCompletion private override function __applyFilter(bitmapData:BitmapData, sourceBitmapData:BitmapData, sourceRect:Rectangle, destPoint:Point):BitmapData
|
||||
{
|
||||
trace("Due to technical limitations, I'm unable to implement the bitmapData rendering method. If you know how to implement it, you're welcome to contribute this feature.");
|
||||
return sourceBitmapData;
|
||||
}
|
||||
|
||||
@:noCompletion private override function __initShader(renderer:DisplayObjectRenderer, pass:Int, sourceBitmapData:BitmapData):Shader
|
||||
{
|
||||
final numBlurPasses = __horizontalPasses + __verticalPasses;
|
||||
|
||||
switch pass
|
||||
{
|
||||
case 0:
|
||||
if (__useLowQualityExtract)
|
||||
{
|
||||
__extractLowShader.uThreshold.value[0] = __threshold;
|
||||
__extractLowShader.uSmoothness.value[0] = __smoothness;
|
||||
__extractLowShader.uQuality.value[0] = __quality;
|
||||
__extractLowShader.uWeights.value = __weights;
|
||||
return __extractLowShader;
|
||||
}
|
||||
else
|
||||
{
|
||||
__extractShader.uThreshold.value[0] = __threshold;
|
||||
__extractShader.uSmoothness.value[0] = __smoothness;
|
||||
__extractShader.uQuality.value[0] = __quality;
|
||||
__extractShader.uWeights.value = __weights;
|
||||
return __extractShader;
|
||||
}
|
||||
|
||||
case _ if (pass <= numBlurPasses):
|
||||
final blurPass = pass - 1;
|
||||
final isHorizontal = blurPass < __horizontalPasses;
|
||||
|
||||
final scalePass = isHorizontal ? blurPass : blurPass - __horizontalPasses;
|
||||
|
||||
final scale = Math.pow(0.5, scalePass >> 1);
|
||||
final blurRadius = isHorizontal ? blurX * scale : blurY * scale;
|
||||
|
||||
if (isHorizontal)
|
||||
{
|
||||
__blurShader.uRadius.value[0] = blurRadius / __quality;
|
||||
__blurShader.uRadius.value[1] = 0.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
__blurShader.uRadius.value[0] = 0.0;
|
||||
__blurShader.uRadius.value[1] = blurRadius / __quality;
|
||||
}
|
||||
__blurShader.uQuality.value[0] = __quality;
|
||||
__blurShader.uStrength.value[0] = Math.pow(__strength, 1.0 / numBlurPasses);
|
||||
|
||||
return __blurShader;
|
||||
|
||||
default:
|
||||
__combineShader.sourceBitmap.input = sourceBitmapData;
|
||||
__combineShader.uThreshold.value[0] = __threshold;
|
||||
__combineShader.uQuality.value[0] = __quality;
|
||||
__combineShader.uBlendMode.value[0] = cast __blendMode;
|
||||
return __combineShader;
|
||||
}
|
||||
}
|
||||
|
||||
// Get & Set Methods
|
||||
@:noCompletion private function get_blurX():Float
|
||||
{
|
||||
return __blurX;
|
||||
}
|
||||
|
||||
@:noCompletion private function set_blurX(value:Float):Float
|
||||
{
|
||||
if (value != __blurX)
|
||||
{
|
||||
__blurX = value;
|
||||
__renderDirty = true;
|
||||
|
||||
if (!__extension)
|
||||
{
|
||||
// Setting it to 1 prevents bloom flickering at the screen edges
|
||||
__leftExtension = 1;
|
||||
__rightExtension = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
__leftExtension = (value > 0 ? Math.ceil(value) : 0);
|
||||
__rightExtension = __leftExtension;
|
||||
}
|
||||
|
||||
__horizontalPasses = (value <= 0) ? 0 : Math.ceil(value * 0.0625 / quality) + 1;
|
||||
__numShaderPasses = __horizontalPasses + __verticalPasses + 2;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@:noCompletion private function get_blurY():Float
|
||||
{
|
||||
return __blurY;
|
||||
}
|
||||
|
||||
@:noCompletion private function set_blurY(value:Float):Float
|
||||
{
|
||||
if (value != __blurY)
|
||||
{
|
||||
__blurY = value;
|
||||
__renderDirty = true;
|
||||
|
||||
if (!__extension)
|
||||
{
|
||||
// Setting it to 1 prevents bloom flickering at the screen edges
|
||||
__topExtension = 1;
|
||||
__bottomExtension = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
__topExtension = (value > 0 ? Math.ceil(value) : 0);
|
||||
__bottomExtension = __topExtension;
|
||||
}
|
||||
|
||||
__verticalPasses = (value <= 0) ? 0 : Math.ceil(value * 0.0625 / quality) + 1;
|
||||
__numShaderPasses = __horizontalPasses + __verticalPasses + 2;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@:noCompletion private function get_quality():Float
|
||||
{
|
||||
return __quality;
|
||||
}
|
||||
|
||||
@:noCompletion private function set_quality(value:Float):Float
|
||||
{
|
||||
__horizontalPasses = (__blurX <= 0) ? 0 : Math.round(__blurX * 0.125 / value) + 1;
|
||||
__verticalPasses = (__blurY <= 0) ? 0 : Math.round(__blurY * 0.125 / value) + 1;
|
||||
__numShaderPasses = __horizontalPasses + __verticalPasses + 2;
|
||||
|
||||
if (value != __quality)
|
||||
__renderDirty = true;
|
||||
return __quality = value;
|
||||
}
|
||||
|
||||
@:noCompletion private function get_strength():Float
|
||||
{
|
||||
return __strength;
|
||||
}
|
||||
|
||||
@:noCompletion private function set_strength(value:Float):Float
|
||||
{
|
||||
if (value != __strength)
|
||||
{
|
||||
__strength = value;
|
||||
__renderDirty = true;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@:noCompletion private function get_threshold():Float
|
||||
{
|
||||
return __threshold;
|
||||
}
|
||||
|
||||
@:noCompletion private function set_threshold(value:Float):Float
|
||||
{
|
||||
if (value != __threshold)
|
||||
{
|
||||
__threshold = value;
|
||||
__renderDirty = true;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@:noCompletion private function get_smoothness():Float
|
||||
{
|
||||
return __smoothness;
|
||||
}
|
||||
|
||||
@:noCompletion private function set_smoothness(value:Float):Float
|
||||
{
|
||||
if (value != __smoothness)
|
||||
{
|
||||
__smoothness = value;
|
||||
__renderDirty = true;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@:noCompletion private function get_extension():Bool
|
||||
{
|
||||
return __extension;
|
||||
}
|
||||
|
||||
@:noCompletion private function set_extension(value:Bool):Bool
|
||||
{
|
||||
if (value != __extension)
|
||||
{
|
||||
__extension = value;
|
||||
|
||||
if (!value)
|
||||
__leftExtension = __rightExtension = __topExtension = __bottomExtension = 0;
|
||||
else
|
||||
{
|
||||
__leftExtension = __rightExtension = (__blurX > 0 ? Math.ceil(__blurX) : 0);
|
||||
__topExtension = __bottomExtension = (__blurY > 0 ? Math.ceil(__blurY) : 0);
|
||||
}
|
||||
|
||||
__renderDirty = true;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@:noCompletion private function get_useLowQualityExtract():Bool
|
||||
{
|
||||
return __useLowQualityExtract;
|
||||
}
|
||||
|
||||
@:noCompletion private function set_useLowQualityExtract(value:Bool):Bool
|
||||
{
|
||||
if (value != __useLowQualityExtract)
|
||||
{
|
||||
__useLowQualityExtract = value;
|
||||
__renderDirty = true;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@:noCompletion private function get_weights():Array<Float>
|
||||
{
|
||||
return __weights;
|
||||
}
|
||||
|
||||
@:noCompletion private function set_weights(value:Array<Float>):Array<Float>
|
||||
{
|
||||
if (value != __weights)
|
||||
{
|
||||
__weights = value;
|
||||
__renderDirty = true;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@:noCompletion private function get_blendMode():BlendMode
|
||||
{
|
||||
return __blendMode;
|
||||
}
|
||||
|
||||
@:noCompletion private function set_blendMode(value:BlendMode):BlendMode
|
||||
{
|
||||
if (value != __blendMode)
|
||||
{
|
||||
__blendMode = value;
|
||||
__renderDirty = true;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
private class BlurShader extends BitmapFilterShader
|
||||
{
|
||||
@:glFragmentSource("
|
||||
uniform sampler2D openfl_Texture;
|
||||
uniform float uStrength;
|
||||
|
||||
varying mat2 vBlurCoord0;
|
||||
varying mat2 vBlurCoord1;
|
||||
varying vec2 vBlurCoord2;
|
||||
varying mat2 vBlurCoord3;
|
||||
varying mat2 vBlurCoord4;
|
||||
|
||||
varying float invQuality;
|
||||
|
||||
void main(void) {
|
||||
if ((all(greaterThanEqual(vBlurCoord2, vec2(0.0))) && all(lessThanEqual(vBlurCoord2, vec2(1.0)))) == false) return;
|
||||
|
||||
vec4 sum = texture2D(openfl_Texture, clamp(vBlurCoord0[0], 0.0, invQuality)) * 0.028532;
|
||||
sum += texture2D(openfl_Texture, clamp(vBlurCoord0[1], 0.0, invQuality)) * 0.067234;
|
||||
sum += texture2D(openfl_Texture, clamp(vBlurCoord1[0], 0.0, invQuality)) * 0.124009;
|
||||
sum += texture2D(openfl_Texture, clamp(vBlurCoord1[1], 0.0, invQuality)) * 0.179044;
|
||||
sum += texture2D(openfl_Texture, clamp(vBlurCoord2, 0.0, invQuality)) * 0.202360;
|
||||
sum += texture2D(openfl_Texture, clamp(vBlurCoord3[0], 0.0, invQuality)) * 0.179044;
|
||||
sum += texture2D(openfl_Texture, clamp(vBlurCoord3[1], 0.0, invQuality)) * 0.124009;
|
||||
sum += texture2D(openfl_Texture, clamp(vBlurCoord4[0], 0.0, invQuality)) * 0.067234;
|
||||
sum += texture2D(openfl_Texture, clamp(vBlurCoord4[1], 0.0, invQuality)) * 0.028532;
|
||||
gl_FragColor = sum * uStrength;
|
||||
}
|
||||
")
|
||||
@:glVertexSource("
|
||||
attribute vec4 openfl_Position;
|
||||
attribute vec2 openfl_TextureCoord;
|
||||
|
||||
uniform mat4 openfl_Matrix;
|
||||
|
||||
uniform vec2 uRadius;
|
||||
uniform vec2 uTextureSize;
|
||||
uniform float uQuality;
|
||||
|
||||
varying mat2 vBlurCoord0;
|
||||
varying mat2 vBlurCoord1;
|
||||
varying vec2 vBlurCoord2;
|
||||
varying mat2 vBlurCoord3;
|
||||
varying mat2 vBlurCoord4;
|
||||
|
||||
varying float invQuality;
|
||||
|
||||
void main(void) {
|
||||
vec4 pos = openfl_Position;
|
||||
invQuality = 1.0 / uQuality;
|
||||
|
||||
pos.xy *= invQuality;
|
||||
gl_Position = openfl_Matrix * pos;
|
||||
|
||||
vec2 r = uRadius / uTextureSize;
|
||||
vec2 coord = openfl_TextureCoord * invQuality;
|
||||
vBlurCoord0[0] = coord - r;
|
||||
vBlurCoord0[1] = coord - r * 0.25;
|
||||
vBlurCoord1[0] = coord - r * 0.5;
|
||||
vBlurCoord1[1] = coord - r * 0.75;
|
||||
vBlurCoord2 = coord;
|
||||
vBlurCoord3[0] = coord + r * 0.25;
|
||||
vBlurCoord3[1] = coord + r * 0.5;
|
||||
vBlurCoord4[0] = coord + r * 0.75;
|
||||
vBlurCoord4[1] = coord + r;
|
||||
}
|
||||
")
|
||||
public function new()
|
||||
{
|
||||
super();
|
||||
|
||||
uStrength.value = [1.0];
|
||||
uRadius.value = [0, 0];
|
||||
uQuality.value = [8];
|
||||
uTextureSize.value = [1, 1];
|
||||
}
|
||||
|
||||
@:noCompletion private override function __update():Void
|
||||
{
|
||||
#if !macro
|
||||
uTextureSize.value[0] = __texture.input.width;
|
||||
uTextureSize.value[1] = __texture.input.height;
|
||||
#end
|
||||
|
||||
super.__update();
|
||||
}
|
||||
}
|
||||
|
||||
private class ExtractLowShader extends BitmapFilterShader
|
||||
{
|
||||
@:glFragmentSource("
|
||||
uniform sampler2D openfl_Texture;
|
||||
uniform float uThreshold;
|
||||
uniform float uSmoothness;
|
||||
uniform vec3 uWeights;
|
||||
varying vec2 vTexCoord;
|
||||
|
||||
void main(void) {
|
||||
if ((all(greaterThanEqual(vTexCoord, vec2(0.0))) && all(lessThanEqual(vTexCoord, vec2(1.0)))) == false) return;
|
||||
|
||||
vec4 texel = texture2D(openfl_Texture, vTexCoord);
|
||||
float brightness = min(dot(texel.rgb, uWeights), 1.0);
|
||||
float mask = smoothstep(uThreshold, uThreshold + uSmoothness, brightness);
|
||||
gl_FragColor = texel * mask;
|
||||
}
|
||||
")
|
||||
@:glVertexSource("
|
||||
attribute vec4 openfl_Position;
|
||||
attribute vec2 openfl_TextureCoord;
|
||||
uniform mat4 openfl_Matrix;
|
||||
uniform vec2 openfl_TextureSize;
|
||||
uniform float uQuality;
|
||||
varying vec2 vTexCoord;
|
||||
|
||||
void main(void) {
|
||||
vec4 pos = openfl_Position;
|
||||
pos.xy /= uQuality;
|
||||
gl_Position = openfl_Matrix * pos;
|
||||
vTexCoord = openfl_TextureCoord;
|
||||
}
|
||||
")
|
||||
public function new()
|
||||
{
|
||||
super();
|
||||
|
||||
uThreshold.value = [0.6];
|
||||
uSmoothness.value = [0.1];
|
||||
uQuality.value = [8];
|
||||
uWeights.value = [0.2126, 0.7152, 0.0722];
|
||||
}
|
||||
}
|
||||
|
||||
private class ExtractShader extends BitmapFilterShader
|
||||
{
|
||||
@:glFragmentSource("
|
||||
uniform sampler2D openfl_Texture;
|
||||
uniform vec2 openfl_TextureSize;
|
||||
uniform float uThreshold;
|
||||
uniform float uSmoothness;
|
||||
uniform float uQuality;
|
||||
uniform vec3 uWeights;
|
||||
varying vec2 vTexCoord;
|
||||
varying vec4 border;
|
||||
|
||||
void main(void) {
|
||||
if ((all(greaterThanEqual(vTexCoord, border.xy)) && all(lessThanEqual(vTexCoord, border.zw))) == false) return;
|
||||
|
||||
float quality = floor(uQuality) / 2.0;
|
||||
vec2 texelSize = 1.0 / openfl_TextureSize;
|
||||
|
||||
vec4 accumulated = vec4(0.0);
|
||||
int sampleCount = 0;
|
||||
|
||||
|
||||
for (float dx = -quality; dx <= quality; dx += 2.0) {
|
||||
for (float dy = -quality; dy <= quality; dy += 2.0) {
|
||||
vec2 sampleCoord = vTexCoord + vec2(dx, dy) * texelSize;
|
||||
|
||||
vec4 texel = texture2D(openfl_Texture, sampleCoord);
|
||||
float brightness = min(dot(texel.rgb, uWeights), 1.0);
|
||||
float mask = smoothstep(uThreshold, uThreshold + uSmoothness, brightness);
|
||||
accumulated += texel * mask;
|
||||
sampleCount++;
|
||||
}
|
||||
}
|
||||
|
||||
gl_FragColor = accumulated / float(sampleCount);
|
||||
}
|
||||
")
|
||||
@:glVertexSource("
|
||||
attribute vec4 openfl_Position;
|
||||
attribute vec2 openfl_TextureCoord;
|
||||
uniform mat4 openfl_Matrix;
|
||||
uniform vec2 openfl_TextureSize;
|
||||
uniform float uQuality;
|
||||
varying vec2 vTexCoord;
|
||||
varying vec4 border;
|
||||
|
||||
void main(void) {
|
||||
vec4 pos = openfl_Position;
|
||||
pos.xy /= uQuality;
|
||||
|
||||
vec2 size = 1.0 / openfl_TextureSize * uQuality;
|
||||
border = vec4(size, vec2(1.0) - size);
|
||||
|
||||
gl_Position = openfl_Matrix * pos;
|
||||
vTexCoord = openfl_TextureCoord;
|
||||
}
|
||||
")
|
||||
public function new()
|
||||
{
|
||||
super();
|
||||
|
||||
uThreshold.value = [0.6];
|
||||
uSmoothness.value = [0.1];
|
||||
uQuality.value = [8];
|
||||
uWeights.value = [0.2126, 0.7152, 0.0722];
|
||||
}
|
||||
}
|
||||
|
||||
private class CombineShader extends BitmapFilterShader
|
||||
{
|
||||
@:glFragmentSource("
|
||||
uniform sampler2D openfl_Texture;
|
||||
uniform sampler2D sourceBitmap;
|
||||
uniform float uThreshold;
|
||||
uniform int uBlendMode;
|
||||
varying vec4 textureCoords;
|
||||
|
||||
vec4 blendScreen(vec4 src, vec4 bloom) {
|
||||
return vec4(1.0) - (vec4(1.0) - src) * (vec4(1.0) - bloom);
|
||||
}
|
||||
|
||||
vec4 blendMultiply(vec4 src, vec4 bloom) {
|
||||
return src * bloom;
|
||||
}
|
||||
|
||||
vec4 blendLighten(vec4 src, vec4 bloom) {
|
||||
return max(src, bloom);
|
||||
}
|
||||
|
||||
vec4 blendOverlay(vec4 src, vec4 bloom) {
|
||||
vec4 result = vec4(0.0);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (src[i] < 0.5) {
|
||||
result[i] = 2.0 * src[i] * bloom[i];
|
||||
} else {
|
||||
result[i] = 1.0 - 2.0 * (1.0 - src[i]) * (1.0 - bloom[i]);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
vec4 blendColorDodge(vec4 src, vec4 bloom) {
|
||||
vec4 result = vec4(0.0);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (bloom[i] < 1.0) {
|
||||
result[i] = min(1.0, src[i] / (1.0 - bloom[i]));
|
||||
} else {
|
||||
result[i] = 1.0;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
vec4 blendSoftLight(vec4 src, vec4 bloom) {
|
||||
vec4 result = vec4(0.0);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (bloom[i] < 0.5) {
|
||||
result[i] = src[i] - (1.0 - 2.0 * bloom[i]) * src[i] * (1.0 - src[i]);
|
||||
} else {
|
||||
float d = (src[i] <= 0.25) ? ((16.0 * src[i] - 12.0) * src[i] + 4.0) * src[i] : sqrt(src[i]);
|
||||
result[i] = src[i] + (2.0 * bloom[i] - 1.0) * (d - src[i]);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
vec4 blendAlpha(vec4 src, vec4 bloom) {
|
||||
return src + bloom * (1.0 - src.a);
|
||||
}
|
||||
|
||||
void main(void) {
|
||||
vec4 src = texture2D(sourceBitmap, textureCoords.xy);
|
||||
vec4 bloom = texture2D(openfl_Texture, textureCoords.zw);
|
||||
|
||||
vec4 result;
|
||||
if(uBlendMode == 0)
|
||||
result = src + bloom;
|
||||
else if(uBlendMode == 1)
|
||||
result = blendAlpha(src, bloom);
|
||||
else if(uBlendMode == 5)
|
||||
result = blendOverlay(src, bloom);
|
||||
else if(uBlendMode == 8)
|
||||
result = blendLighten(src, bloom);
|
||||
else if(uBlendMode == 9)
|
||||
result = blendMultiply(src, bloom);
|
||||
else if(uBlendMode == 11)
|
||||
result = blendOverlay(src, bloom);
|
||||
else if(uBlendMode == 12)
|
||||
result = blendScreen(src, bloom);
|
||||
else if(uBlendMode == 15)
|
||||
result = blendColorDodge(src, bloom);
|
||||
else if(uBlendMode == 17)
|
||||
result = blendSoftLight(src, bloom);
|
||||
else
|
||||
result = src + bloom;
|
||||
|
||||
gl_FragColor = result;
|
||||
}
|
||||
")
|
||||
@:glVertexSource("
|
||||
attribute vec4 openfl_Position;
|
||||
attribute vec2 openfl_TextureCoord;
|
||||
uniform mat4 openfl_Matrix;
|
||||
uniform vec2 openfl_TextureSize;
|
||||
uniform float uQuality;
|
||||
varying vec4 textureCoords;
|
||||
|
||||
void main(void) {
|
||||
gl_Position = openfl_Matrix * openfl_Position;
|
||||
textureCoords = vec4(openfl_TextureCoord, openfl_TextureCoord / uQuality);
|
||||
}
|
||||
")
|
||||
public function new()
|
||||
{
|
||||
super();
|
||||
|
||||
uQuality.value = [8];
|
||||
uThreshold.value = [0.6];
|
||||
uBlendMode.value = [0];
|
||||
}
|
||||
}
|
||||
@@ -2,39 +2,15 @@ package funkin.backend.shaders;
|
||||
|
||||
import openfl.Assets;
|
||||
|
||||
/**
|
||||
* Class for custom shaders.
|
||||
*
|
||||
* To create one, create a `shaders` folder in your assets/mod folder, then add a file named `my-shader.frag` or/and `my-shader.vert`.
|
||||
*
|
||||
* Non-existent shaders will only load the default one, and throw a warning in the console.
|
||||
*
|
||||
* To access the shader's uniform variables, use `shader.variable`
|
||||
*/
|
||||
@:deprecated("Use funkin.backend.shaders.FunkinShader.fromFile instead.")
|
||||
class CustomShader extends FunkinShader {
|
||||
public var path:String = "";
|
||||
@:isVar
|
||||
public var path(get, set):String;
|
||||
inline function get_path():String return path != null ? path : _fragmentFilePath + _vertexFilePath;
|
||||
inline function set_path(v:Null<String>):String return path = cast v;
|
||||
|
||||
/**
|
||||
* Creates a new custom shader
|
||||
* @param name Name of the frag and vert files.
|
||||
* @param glslVersion GLSL version to use. Defaults to `120`.
|
||||
*/
|
||||
public function new(name:String, glslVersion:String = null) {
|
||||
if (glslVersion == null) glslVersion = Flags.DEFAULT_GLSL_VERSION;
|
||||
var fragShaderPath = Paths.fragShader(name);
|
||||
var vertShaderPath = Paths.vertShader(name);
|
||||
var fragCode = Assets.exists(fragShaderPath) ? Assets.getText(fragShaderPath) : null;
|
||||
var vertCode = Assets.exists(vertShaderPath) ? Assets.getText(vertShaderPath) : null;
|
||||
|
||||
fileName = name;
|
||||
fragFileName = fragShaderPath;
|
||||
vertFileName = vertShaderPath;
|
||||
|
||||
path = fragShaderPath+vertShaderPath;
|
||||
|
||||
if (fragCode == null && vertCode == null)
|
||||
Logs.error('Shader "$name" couldn\'t be found.');
|
||||
|
||||
super(fragCode, vertCode, glslVersion);
|
||||
public function new(name:String, ?glslVersion:String) {
|
||||
super();
|
||||
loadShaderFile(Paths.fragShader(name), Paths.vertShader(name), glslVersion);
|
||||
}
|
||||
}
|
||||
@@ -1,533 +1,65 @@
|
||||
package funkin.backend.shaders;
|
||||
|
||||
import flixel.graphics.FlxGraphic;
|
||||
import flixel.system.FlxAssets.FlxShader;
|
||||
import flixel.util.FlxSignal.FlxTypedSignal;
|
||||
import haxe.io.Path;
|
||||
import haxe.Exception;
|
||||
|
||||
import hscript.IHScriptCustomBehaviour;
|
||||
import lime.utils.Float32Array;
|
||||
|
||||
import openfl.display.BitmapData;
|
||||
import openfl.display.ShaderInput;
|
||||
import openfl.display.Shader;
|
||||
import openfl.display.ShaderParameter;
|
||||
import openfl.display.ShaderParameterType;
|
||||
import openfl.display.ShaderPrecision;
|
||||
import openfl.display.ShaderInput;
|
||||
import openfl.display3D._internal.GLProgram;
|
||||
import openfl.display3D._internal.GLShader;
|
||||
import openfl.display3D.Program3D;
|
||||
import openfl.utils._internal.Log;
|
||||
import openfl.utils.GLSLSourceAssembler;
|
||||
|
||||
import flixel.addons.display.FlxRuntimeShader;
|
||||
import flixel.graphics.FlxGraphic;
|
||||
import flixel.util.FlxSignal.FlxTypedSignal;
|
||||
import flixel.util.FlxStringUtil;
|
||||
|
||||
using StringTools;
|
||||
@:access(openfl.display3D.Context3D)
|
||||
@:access(openfl.display3D.Program3D)
|
||||
@:access(openfl.display.ShaderInput)
|
||||
@:access(openfl.display.ShaderParameter)
|
||||
class FunkinShader extends FlxShader implements IHScriptCustomBehaviour {
|
||||
private static var __instanceFields = Type.getInstanceFields(FunkinShader);
|
||||
private static var FRAGMENT_SHADER = 0;
|
||||
private static var VERTEX_SHADER = 1;
|
||||
|
||||
class FunkinShader extends FlxRuntimeShader implements IHScriptCustomBehaviour {
|
||||
public var onGLUpdate:FlxTypedSignal<Void->Void> = new FlxTypedSignal<Void->Void>();
|
||||
public var onProcessGLData:FlxTypedSignal<(String, String)->Void> = new FlxTypedSignal<(String, String)->Void>();
|
||||
|
||||
public var glslVer:String = Flags.DEFAULT_GLSL_VERSION;
|
||||
public var fileName:String = "FunkinShader";
|
||||
public var fragFileName:String = "FunkinShader";
|
||||
public var vertFileName:String = "FunkinShader";
|
||||
|
||||
public var shaderPrefix:String = "";
|
||||
public var fragmentPrefix:String = "";
|
||||
public var vertexPrefix:String = "";
|
||||
|
||||
/**
|
||||
* Creates a new shader from the specified fragment and vertex source.
|
||||
* Accepts `#pragma header`.
|
||||
* @param frag Fragment source (pass `null` to use default)
|
||||
* @param vert Vertex source (pass `null` to use default)
|
||||
* @param glslVer Version of GLSL to use (defaults to 120)
|
||||
*/
|
||||
public override function new(frag:String, vert:String, glslVer:String = null) {
|
||||
if (glslVer == null) glslVer = Flags.DEFAULT_GLSL_VERSION;
|
||||
if (frag == null) frag = ShaderTemplates.defaultFragmentSource;
|
||||
if (vert == null) vert = ShaderTemplates.defaultVertexSource;
|
||||
this.glFragmentSource = frag;
|
||||
this.glVertexSource = vert;
|
||||
|
||||
this.glslVer = glslVer;
|
||||
super();
|
||||
public function new(?fragmentSource:String, ?vertexSource:String, ?version:String) {
|
||||
super(fragmentSource, vertexSource, version ?? (fragmentSource != null || vertexSource != null ? Flags.DEFAULT_GLSL_VERSION : null));
|
||||
}
|
||||
|
||||
static var IMPORT_REGEX = ~/#import\s+<(.*)>/;
|
||||
|
||||
private function processImports(value:String, type:Int):String
|
||||
{
|
||||
while(IMPORT_REGEX.match(value))
|
||||
{
|
||||
var importPath = IMPORT_REGEX.matched(1);
|
||||
var importSource = Assets.getText("assets/shaders/" + importPath);
|
||||
if(importSource == null) {
|
||||
var fileName = type == FRAGMENT_SHADER ? fragFileName : vertFileName;
|
||||
Logs.traceColored([
|
||||
Logs.logText('[Shader] ', RED),
|
||||
Logs.logText('Failed to import shader ${importPath} in ${fileName}', RED),
|
||||
]);
|
||||
} else {
|
||||
value = value.replace(IMPORT_REGEX.matched(0), importSource);
|
||||
}
|
||||
}
|
||||
return value;
|
||||
public static function fromFile(fragmentPath:String, ?vertexPath:String, ?version:String):FunkinShader {
|
||||
return new FunkinShader().loadShaderFile(fragmentPath, vertexPath, version);
|
||||
}
|
||||
|
||||
static var ERROR_POS_REGEX = ~/(\d+):(\d+): (.*)/g;
|
||||
static var ERROR_REGEX = ~/ERROR: (\d+):(\d+): (.*)/g;
|
||||
static var ERROR_REGEX_2 = ~/(\d+)\((\d+)\) : error ([^:]+): (.*)/g;
|
||||
@:noCompletion private override function __createGLShader(source:String, type:Int):GLShader
|
||||
{
|
||||
var gl = __context.gl;
|
||||
|
||||
var shader = gl.createShader(type);
|
||||
gl.shaderSource(shader, source);
|
||||
gl.compileShader(shader);
|
||||
var shaderInfoLog = gl.getShaderInfoLog(shader);
|
||||
var hasInfoLog = shaderInfoLog != null && StringTools.trim(shaderInfoLog) != "";
|
||||
var compileStatus = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
|
||||
|
||||
if (hasInfoLog || compileStatus == 0)
|
||||
{
|
||||
var isVertexShader = type == gl.VERTEX_SHADER;
|
||||
var messageBuf = new StringBuf();
|
||||
messageBuf.add((compileStatus == 0) ? "Error" : "Info");
|
||||
if(isVertexShader) {
|
||||
messageBuf.add(" compiling vertex shader");
|
||||
if(vertFileName != null && vertFileName.length > 0) {
|
||||
messageBuf.add(" (" + vertFileName + ")");
|
||||
}
|
||||
} else {
|
||||
messageBuf.add(" compiling fragment shader");
|
||||
if(fragFileName != null && fragFileName.length > 0) {
|
||||
messageBuf.add(" (" + fragFileName + ")");
|
||||
}
|
||||
}
|
||||
messageBuf.add("\n");
|
||||
var errorPositions = [];
|
||||
var regex = null;
|
||||
var tmp = shaderInfoLog;
|
||||
if(shaderInfoLog.contains(" : error ")) {
|
||||
regex = ERROR_REGEX_2;
|
||||
|
||||
while(regex.match(tmp)) {
|
||||
errorPositions.push(new ShaderErrorPosition(regex.matched(2), regex.matched(1), regex.matched(4)));
|
||||
tmp = regex.matchedRight();
|
||||
}
|
||||
} else if(shaderInfoLog.contains("ERROR: ")) {
|
||||
regex = ERROR_REGEX;
|
||||
|
||||
while(regex.match(tmp)) {
|
||||
errorPositions.push(new ShaderErrorPosition(regex.matched(2), regex.matched(1), regex.matched(3)));
|
||||
tmp = regex.matchedRight();
|
||||
}
|
||||
} else {
|
||||
regex = ERROR_POS_REGEX;
|
||||
|
||||
while(regex.match(tmp)) {
|
||||
errorPositions.push(new ShaderErrorPosition(regex.matched(2), regex.matched(1), regex.matched(3)));
|
||||
tmp = regex.matchedRight();
|
||||
}
|
||||
}
|
||||
var splitSource = source.split("\n");
|
||||
for(error in errorPositions) {
|
||||
messageBuf.add("ERROR: Line: " + error.line);
|
||||
if(error.column > 0) {
|
||||
messageBuf.add(", Column: " + error.column);
|
||||
}
|
||||
messageBuf.add(", " + error.message);
|
||||
if(error.line < splitSource.length) {
|
||||
messageBuf.add("\nLine: ");
|
||||
messageBuf.add(splitSource[error.line-1].trim());
|
||||
}
|
||||
messageBuf.add("\n\n");
|
||||
}
|
||||
var hasErrorPosition = errorPositions.length > 0;
|
||||
if(hasErrorPosition) {
|
||||
messageBuf.add("Raw shader info log:\n");
|
||||
}
|
||||
messageBuf.add(shaderInfoLog);
|
||||
messageBuf.add("\n");
|
||||
messageBuf.add(source);
|
||||
|
||||
var message = messageBuf.toString();
|
||||
if (compileStatus == 0) Log.error(message);
|
||||
else if (hasInfoLog) Log.debug(message);
|
||||
public function loadShaderFile(fragmentPath:String, ?vertexPath:String, ?version:String):FunkinShader {
|
||||
if (vertexPath == null) {
|
||||
final idx = fragmentPath.lastIndexOf(".");
|
||||
if (idx == -1) vertexPath = fragmentPath;
|
||||
else vertexPath = fragmentPath.substr(0, idx);
|
||||
}
|
||||
|
||||
return shader;
|
||||
}
|
||||
fragmentPath = FlxRuntimeShader._getPath(fragmentPath, false);
|
||||
vertexPath = FlxRuntimeShader._getPath(vertexPath, true);
|
||||
_fromFile(fragmentPath, vertexPath, version ?? (fragmentPath != null || vertexPath != null ? Flags.DEFAULT_GLSL_VERSION : null));
|
||||
|
||||
@:noCompletion private override function __createGLProgram(vertexSource:String, fragmentSource:String):GLProgram
|
||||
{
|
||||
var program:GLProgram = null;
|
||||
try
|
||||
{
|
||||
var gl = __context.gl;
|
||||
|
||||
var vertexShader = __createGLShader(vertexSource, gl.VERTEX_SHADER);
|
||||
var fragmentShader = __createGLShader(fragmentSource, gl.FRAGMENT_SHADER);
|
||||
|
||||
program = gl.createProgram();
|
||||
|
||||
// Fix support for drivers that don't draw if attribute 0 is disabled
|
||||
for (param in __paramFloat)
|
||||
{
|
||||
if (param.name.indexOf("Position") > -1 && StringTools.startsWith(param.name, "openfl_"))
|
||||
{
|
||||
gl.bindAttribLocation(program, 0, param.name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
gl.attachShader(program, vertexShader);
|
||||
gl.attachShader(program, fragmentShader);
|
||||
gl.linkProgram(program);
|
||||
|
||||
if (gl.getProgramParameter(program, gl.LINK_STATUS) == 0)
|
||||
{
|
||||
var messageBuf = new StringBuf();
|
||||
messageBuf.add("Unable to initialize the shader program");
|
||||
messageBuf.add("\n");
|
||||
messageBuf.add(gl.getProgramInfoLog(program));
|
||||
var message = messageBuf.toString();
|
||||
Log.error(message);
|
||||
}
|
||||
}
|
||||
catch (error:Dynamic)
|
||||
{
|
||||
Logs.traceColored([
|
||||
Logs.logText('[Shader] ', BLUE),
|
||||
Logs.logText('Failed to compile shader ${fileName}: ', RED),
|
||||
Logs.logText(Std.string(error))
|
||||
], TRACE);
|
||||
}
|
||||
return program;
|
||||
|
||||
return program;
|
||||
}
|
||||
|
||||
var glRawFragmentSource:String;
|
||||
var glRawVertexSource:String;
|
||||
|
||||
@:noCompletion override private function set_glFragmentSource(value:String):String
|
||||
{
|
||||
if(value == null)
|
||||
value = ShaderTemplates.defaultFragmentSource;
|
||||
glRawFragmentSource = value;
|
||||
value = processImports(value, FRAGMENT_SHADER);
|
||||
value = value.replace("#pragma header", ShaderTemplates.fragHeader).replace("#pragma body", ShaderTemplates.fragBody);
|
||||
if (value != __glFragmentSource)
|
||||
{
|
||||
__glSourceDirty = true;
|
||||
}
|
||||
|
||||
return __glFragmentSource = value;
|
||||
}
|
||||
|
||||
@:noCompletion override private function set_glVertexSource(value:String):String
|
||||
{
|
||||
if(value == null)
|
||||
value = ShaderTemplates.defaultVertexSource;
|
||||
glRawVertexSource = value;
|
||||
value = processImports(value, VERTEX_SHADER);
|
||||
|
||||
var useBackCompat:Bool = true;
|
||||
for (regex in ShaderTemplates.vertBackCompatVarList) if (!regex.match(value)) {
|
||||
useBackCompat = false;
|
||||
break;
|
||||
}
|
||||
|
||||
var header = useBackCompat ? ShaderTemplates.vertHeaderBackCompat : ShaderTemplates.vertHeader;
|
||||
var body = useBackCompat ? ShaderTemplates.vertBodyBackCompat : ShaderTemplates.vertBody;
|
||||
|
||||
value = value.replace("#pragma header", header).replace("#pragma body", body);
|
||||
|
||||
if (value != __glVertexSource)
|
||||
{
|
||||
__glSourceDirty = true;
|
||||
}
|
||||
|
||||
return __glVertexSource = value;
|
||||
}
|
||||
|
||||
override function __updateGL():Void {
|
||||
onGLUpdate.dispatch();
|
||||
super.__updateGL();
|
||||
}
|
||||
|
||||
@:noCompletion private override function __initGL():Void
|
||||
{
|
||||
if (__glSourceDirty || __paramBool == null)
|
||||
{
|
||||
__glSourceDirty = false;
|
||||
program = null;
|
||||
|
||||
__inputBitmapData = new Array();
|
||||
__paramBool = new Array();
|
||||
__paramFloat = new Array();
|
||||
__paramInt = new Array();
|
||||
|
||||
__processGLData(glVertexSource, "attribute");
|
||||
__processGLData(glVertexSource, "uniform");
|
||||
__processGLData(glFragmentSource, "uniform");
|
||||
}
|
||||
|
||||
if (__context != null && program == null)
|
||||
{
|
||||
var prefixBuf = new StringBuf();
|
||||
prefixBuf.add('#version ${glslVer}\n');
|
||||
prefixBuf.add(shaderPrefix);
|
||||
|
||||
var gl = __context.gl;
|
||||
|
||||
prefixBuf.add("#ifdef GL_ES\n");
|
||||
if (precisionHint == FULL) {
|
||||
prefixBuf.add("#ifdef GL_FRAGMENT_PRECISION_HIGH\n");
|
||||
prefixBuf.add("precision highp float;\n");
|
||||
prefixBuf.add("#else\n");
|
||||
prefixBuf.add("precision mediump float;\n");
|
||||
prefixBuf.add("#endif\n");
|
||||
} else {
|
||||
prefixBuf.add("precision lowp float;\n");
|
||||
}
|
||||
prefixBuf.add("#endif\n");
|
||||
|
||||
var prefix = prefixBuf.toString();
|
||||
|
||||
var vertex = prefix + vertexPrefix + glVertexSource;
|
||||
var fragment = prefix + fragmentPrefix + glFragmentSource;
|
||||
|
||||
var id = vertex + fragment;
|
||||
|
||||
if (__context.__programs.exists(id))
|
||||
{
|
||||
program = __context.__programs.get(id);
|
||||
}
|
||||
else
|
||||
{
|
||||
program = __context.createProgram(GLSL);
|
||||
program.__glProgram = __createGLProgram(vertex, fragment);
|
||||
__context.__programs.set(id, program);
|
||||
}
|
||||
|
||||
if (program != null)
|
||||
{
|
||||
glProgram = program.__glProgram;
|
||||
|
||||
for (input in __inputBitmapData) {
|
||||
|
||||
if (input.__isUniform) {
|
||||
input.index = gl.getUniformLocation(glProgram, input.name);
|
||||
} else {
|
||||
input.index = gl.getAttribLocation(glProgram, input.name);
|
||||
}
|
||||
}
|
||||
|
||||
for (parameter in __paramBool) {
|
||||
if (parameter.__isUniform) {
|
||||
parameter.index = gl.getUniformLocation(glProgram, parameter.name);
|
||||
} else {
|
||||
parameter.index = gl.getAttribLocation(glProgram, parameter.name);
|
||||
}
|
||||
}
|
||||
|
||||
for (parameter in __paramFloat) {
|
||||
if (parameter.__isUniform) {
|
||||
parameter.index = gl.getUniformLocation(glProgram, parameter.name);
|
||||
} else {
|
||||
parameter.index = gl.getAttribLocation(glProgram, parameter.name);
|
||||
}
|
||||
}
|
||||
|
||||
for (parameter in __paramInt) {
|
||||
if (parameter.__isUniform) {
|
||||
parameter.index = gl.getUniformLocation(glProgram, parameter.name);
|
||||
} else {
|
||||
parameter.index = gl.getAttribLocation(glProgram, parameter.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
// initInstance(vertex, fragment); // btw make sure to disable the prefixes for ._isInstance
|
||||
}
|
||||
}
|
||||
|
||||
var __cancelNextProcessGLData:Bool = false;
|
||||
@:noCompletion private override function __processGLData(source:String, storageType:String):Void
|
||||
{
|
||||
onProcessGLData.dispatch(source, storageType);
|
||||
if (__cancelNextProcessGLData != (__cancelNextProcessGLData = false))
|
||||
return;
|
||||
var lastMatch = 0, position, regex, name, type;
|
||||
|
||||
if (storageType == "uniform")
|
||||
{
|
||||
regex = ~/uniform ([A-Za-z0-9]+) ([A-Za-z0-9_]+)/;
|
||||
}
|
||||
else
|
||||
{
|
||||
regex = ~/attribute ([A-Za-z0-9]+) ([A-Za-z0-9_]+)/;
|
||||
}
|
||||
|
||||
while (regex.matchSub(source, lastMatch))
|
||||
{
|
||||
type = regex.matched(1);
|
||||
name = regex.matched(2);
|
||||
|
||||
if (StringTools.startsWith(name, "gl_"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var isUniform = (storageType == "uniform");
|
||||
registerParameter(name, type, isUniform);
|
||||
|
||||
position = regex.matchedPos();
|
||||
lastMatch = position.pos + position.len;
|
||||
}
|
||||
}
|
||||
|
||||
function registerParameter(name:String, type:String, isUniform:Bool):Void
|
||||
{
|
||||
if (StringTools.startsWith(type, "sampler"))
|
||||
{
|
||||
var input = new ShaderInput<BitmapData>();
|
||||
input.name = name;
|
||||
input.__isUniform = isUniform;
|
||||
__inputBitmapData.push(input);
|
||||
|
||||
switch (name)
|
||||
{
|
||||
case "openfl_Texture":
|
||||
__texture = input;
|
||||
case "bitmap":
|
||||
__bitmap = input;
|
||||
default:
|
||||
}
|
||||
|
||||
Reflect.setField(__data, name, input);
|
||||
try{Reflect.setField(this, name, input);} catch(e) {}
|
||||
}
|
||||
else if (!Reflect.hasField(__data, name) || Reflect.field(__data, name) == null)
|
||||
{
|
||||
var parameterType:ShaderParameterType = switch (type)
|
||||
{
|
||||
case "bool": BOOL;
|
||||
case "double", "float": FLOAT;
|
||||
case "int", "uint": INT;
|
||||
case "bvec2": BOOL2;
|
||||
case "bvec3": BOOL3;
|
||||
case "bvec4": BOOL4;
|
||||
case "ivec2", "uvec2": INT2;
|
||||
case "ivec3", "uvec3": INT3;
|
||||
case "ivec4", "uvec4": INT4;
|
||||
case "vec2", "dvec2": FLOAT2;
|
||||
case "vec3", "dvec3": FLOAT3;
|
||||
case "vec4", "dvec4": FLOAT4;
|
||||
case "mat2", "mat2x2": MATRIX2X2;
|
||||
case "mat2x3": MATRIX2X3;
|
||||
case "mat2x4": MATRIX2X4;
|
||||
case "mat3x2": MATRIX3X2;
|
||||
case "mat3", "mat3x3": MATRIX3X3;
|
||||
case "mat3x4": MATRIX3X4;
|
||||
case "mat4x2": MATRIX4X2;
|
||||
case "mat4x3": MATRIX4X3;
|
||||
case "mat4", "mat4x4": MATRIX4X4;
|
||||
default: null;
|
||||
}
|
||||
|
||||
var length = switch (parameterType)
|
||||
{
|
||||
case BOOL2, INT2, FLOAT2: 2;
|
||||
case BOOL3, INT3, FLOAT3: 3;
|
||||
case BOOL4, INT4, FLOAT4, MATRIX2X2: 4;
|
||||
case MATRIX3X3: 9;
|
||||
case MATRIX4X4: 16;
|
||||
default: 1;
|
||||
}
|
||||
|
||||
var arrayLength = switch (parameterType)
|
||||
{
|
||||
case MATRIX2X2: 2;
|
||||
case MATRIX3X3: 3;
|
||||
case MATRIX4X4: 4;
|
||||
default: 1;
|
||||
}
|
||||
|
||||
switch (parameterType)
|
||||
{
|
||||
case BOOL, BOOL2, BOOL3, BOOL4:
|
||||
var parameter = new ShaderParameter<Bool>();
|
||||
parameter.name = name;
|
||||
parameter.type = parameterType;
|
||||
parameter.__arrayLength = arrayLength;
|
||||
parameter.__isBool = true;
|
||||
parameter.__isUniform = isUniform;
|
||||
parameter.__length = length;
|
||||
__paramBool.push(parameter);
|
||||
|
||||
if (name == "openfl_HasColorTransform")
|
||||
{
|
||||
__hasColorTransform = parameter;
|
||||
}
|
||||
|
||||
Reflect.setField(__data, name, parameter);
|
||||
try{Reflect.setField(this, name, parameter);} catch(e) {}
|
||||
|
||||
case INT, INT2, INT3, INT4:
|
||||
var parameter = new ShaderParameter<Int>();
|
||||
parameter.name = name;
|
||||
parameter.type = parameterType;
|
||||
parameter.__arrayLength = arrayLength;
|
||||
parameter.__isInt = true;
|
||||
parameter.__isUniform = isUniform;
|
||||
parameter.__length = length;
|
||||
__paramInt.push(parameter);
|
||||
Reflect.setField(__data, name, parameter);
|
||||
try{Reflect.setField(this, name, parameter);} catch(e) {}
|
||||
|
||||
default:
|
||||
var parameter = new ShaderParameter<Float>();
|
||||
parameter.name = name;
|
||||
parameter.type = parameterType;
|
||||
parameter.__arrayLength = arrayLength;
|
||||
#if lime
|
||||
if (arrayLength > 0) parameter.__uniformMatrix = new Float32Array(arrayLength * arrayLength);
|
||||
#end
|
||||
parameter.__isFloat = true;
|
||||
parameter.__isUniform = isUniform;
|
||||
parameter.__length = length;
|
||||
__paramFloat.push(parameter);
|
||||
|
||||
if (StringTools.startsWith(name, "openfl_"))
|
||||
{
|
||||
switch (name)
|
||||
{
|
||||
case "openfl_Alpha": __alpha = parameter;
|
||||
case "openfl_ColorMultiplier": __colorMultiplier = parameter;
|
||||
case "openfl_ColorOffset": __colorOffset = parameter;
|
||||
case "openfl_Matrix": __matrix = parameter;
|
||||
case "openfl_Position": __position = parameter;
|
||||
case "openfl_TextureCoord": __textureCoord = parameter;
|
||||
case "openfl_TextureSize": __textureSize = parameter;
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
Reflect.setField(__data, name, parameter);
|
||||
try{Reflect.setField(this, name, parameter);} catch(e) {}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
#if REGION /* IHScriptCustomBehaviour */
|
||||
public function hget(name:String):Dynamic {
|
||||
if (__instanceFields.contains(name) || __instanceFields.contains('get_${name}'))
|
||||
return Reflect.getProperty(this, name);
|
||||
if (!Reflect.hasField(data, name))
|
||||
return null;
|
||||
var field:Dynamic = Reflect.field(data, name);
|
||||
if (__glSourceDirty) __init();
|
||||
|
||||
if (__thisHasField(name) || __thisHasField('get_${name}')) return Reflect.getProperty(this, name);
|
||||
else if (!Reflect.hasField(__data, name)) return null;
|
||||
|
||||
final field:Dynamic = Reflect.field(__data, name);
|
||||
|
||||
var cl:String = Type.getClassName(Type.getClass(field));
|
||||
|
||||
// little problem we are facing boys...
|
||||
@@ -546,17 +78,19 @@ class FunkinShader extends FlxShader implements IHScriptCustomBehaviour {
|
||||
}
|
||||
|
||||
public function hset(name:String, val:Dynamic):Dynamic {
|
||||
if (__instanceFields.contains(name) || __instanceFields.contains('set_${name}')) {
|
||||
if (__glSourceDirty) __init();
|
||||
|
||||
if (__thisHasField(name) || __thisHasField('set_${name}')) {
|
||||
Reflect.setProperty(this, name, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
if (!Reflect.hasField(data, name)) {
|
||||
Reflect.setField(data, name, val);
|
||||
else if (!Reflect.hasField(__data, name)) {
|
||||
// ??? huh
|
||||
Reflect.setField(__data, name, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
var field = Reflect.field(data, name);
|
||||
var field = Reflect.field(__data, name);
|
||||
var cl = Type.getClassName(Type.getClass(field));
|
||||
var isNotNull = val != null;
|
||||
// cant do "field is ShaderInput" for some reason
|
||||
@@ -598,67 +132,142 @@ class FunkinShader extends FlxShader implements IHScriptCustomBehaviour {
|
||||
|
||||
return val;
|
||||
}
|
||||
#end
|
||||
|
||||
override function __updateGL():Void {
|
||||
onGLUpdate.dispatch();
|
||||
super.__updateGL();
|
||||
}
|
||||
|
||||
override function __createAssembler():Void {
|
||||
__glSourceAssembler = new FunkinShaderSourceAssembler(this);
|
||||
}
|
||||
|
||||
override function toString():String {
|
||||
return __cacheProgramId != null ? 'FunkinShader(${__cacheProgramId})' : 'FunkinShader';
|
||||
}
|
||||
|
||||
#if REGION /* Deprecated */
|
||||
public var shaderPrefix:String = "";
|
||||
public var fragmentPrefix:String = "";
|
||||
public var vertexPrefix:String = "";
|
||||
#end
|
||||
|
||||
#if REGION /* Backward Compatibility */
|
||||
private static var __instanceFields = Type.getInstanceFields(FunkinShader);
|
||||
private static var FRAGMENT_SHADER = 0;
|
||||
private static var VERTEX_SHADER = 1;
|
||||
|
||||
public var fileName(get, set):String;
|
||||
inline function get_fileName():String return _fragmentFilePath ?? _vertexFilePath ?? "FunkinShader";
|
||||
inline function set_fileName(v:String):String return _fragmentFilePath = _vertexFilePath = v;
|
||||
|
||||
public var fragFileName(get, set):String;
|
||||
inline function get_fragFileName():String return _fragmentFilePath ?? "FunkinShader";
|
||||
inline function set_fragFileName(v:String):String return _fragmentFilePath = v;
|
||||
|
||||
public var vertFileName(get, set):String;
|
||||
inline function get_vertFileName():String return _vertexFilePath ?? "FunkinShader";
|
||||
inline function set_vertFileName(v:String):String return _vertexFilePath = v;
|
||||
|
||||
public var glslVer(get, set):String;
|
||||
inline function get_glslVer():String return glVersion;
|
||||
inline function set_glslVer(v:String):String return glVersion = v;
|
||||
|
||||
public var glRawFragmentSource(get, set):String;
|
||||
inline function get_glRawFragmentSource():String return __glFragmentSourceRaw;
|
||||
inline function set_glRawFragmentSource(v:String):String return __glFragmentSourceRaw = v;
|
||||
|
||||
public var glRawVertexSource(get, set):String;
|
||||
inline function get_glRawVertexSource():String return __glVertexSourceRaw;
|
||||
inline function set_glRawVertexSource(v:String):String return __glVertexSourceRaw = v;
|
||||
|
||||
function thisHasField(v:String):Bool return __thisHasField(v);
|
||||
|
||||
function registerParameter(name:String, type:String, isUniform:Bool) {
|
||||
__registerParameter(name, Shader.getParameterTypeFromGLSL(type, false), StringTools.startsWith(type, "sampler"), 1, null, isUniform, null);
|
||||
}
|
||||
|
||||
// Unused... cne-openfl uses a different system
|
||||
var __cancelNextProcessGLData:Bool = false;
|
||||
public var onProcessGLData:FlxTypedSignal<(String, String)->Void> = new FlxTypedSignal<(String, String)->Void>();
|
||||
#end
|
||||
}
|
||||
|
||||
class FunkinShaderSourceAssembler extends FlxRuntimeShader.FlxShaderSourceAssembler {
|
||||
final funkinParent:FunkinShader;
|
||||
|
||||
public function new(parent:FunkinShader) {
|
||||
super(funkinParent = parent);
|
||||
}
|
||||
|
||||
override function __appendIncludes(source:String, isVertex:Bool, ?includedKeys:Map<String, Bool>):String
|
||||
{
|
||||
if (includedKeys == null) includedKeys = [];
|
||||
|
||||
source = GLSLSourceAssembler.__getIncludeFinder().map(source, (regex:EReg) ->
|
||||
{
|
||||
var key = regex.matched(1);
|
||||
if (includedKeys.get(key)) return '/*Recursive include $key*/\n';
|
||||
|
||||
var include = __getIncludeSource(key, isVertex);
|
||||
if (include == null) return '/*Unknown include $key*/\n';
|
||||
|
||||
includedKeys.set(key, true);
|
||||
return '/*include $key*/\n' + __appendIncludes(include, isVertex, includedKeys);
|
||||
});
|
||||
|
||||
return __getImportCompatibilityFinder().map(source, (regex:EReg) ->
|
||||
{
|
||||
var key = regex.matched(1);
|
||||
if (includedKeys.get(key)) return '/*Recursive import $key*/\n';
|
||||
|
||||
var include = __getIncludeSource(key, isVertex);
|
||||
if (include == null) return '/*Unknown import $key*/\n';
|
||||
|
||||
includedKeys.set(key, true);
|
||||
return '/*import $key*/\n' + __appendIncludes(include, isVertex, includedKeys);
|
||||
});
|
||||
}
|
||||
|
||||
override function __getIncludeSource(include:String, fromVertex:Bool):Null<String> {
|
||||
final path = Paths.getPath('shaders/' + include);
|
||||
if (Assets.exists(path)) return Assets.getText(path);
|
||||
|
||||
final fallback = __getIncludeSource(include, fromVertex);
|
||||
if (fallback != null) return fallback;
|
||||
|
||||
Logs.traceColored([
|
||||
Logs.logText('[Shader] ', RED),
|
||||
Logs.logText('Failed to import shader $include', RED),
|
||||
]);
|
||||
return null;
|
||||
}
|
||||
|
||||
override function __appendPrefix(source:String, versionNumber:Int, versionProfile:String, extensions:Map<String, String>, isVertex:Bool,
|
||||
precisionHint:Null<ShaderPrecision>):String
|
||||
{
|
||||
var result = super.__appendPrefix(null, versionNumber, versionProfile, extensions, isVertex, precisionHint) + "\n";
|
||||
|
||||
result += funkinParent.shaderPrefix + "\n" + (isVertex ? funkinParent.vertexPrefix : funkinParent.fragmentPrefix) + "\n";
|
||||
|
||||
if (source != null) {
|
||||
if (!isVertex && versionNumber >= 300 && versionProfile != "compatibility" && !StringTools.contains(source, "out vec4")) {
|
||||
result += "out vec4 openfl_FragColor;\n";
|
||||
}
|
||||
result += source;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static inline function __getImportCompatibilityFinder():EReg {
|
||||
return ~/#import\s+(?|"([^"]+)"|'([^']+)'|<(.*)>|([^\s]+))/g;
|
||||
}
|
||||
}
|
||||
|
||||
#if REGION /* Backward Compatibility */
|
||||
class ShaderTemplates {
|
||||
public static final fragHeader:String = "varying float openfl_Alphav;
|
||||
varying vec4 openfl_ColorMultiplierv;
|
||||
varying vec4 openfl_ColorOffsetv;
|
||||
varying vec2 openfl_TextureCoordv;
|
||||
|
||||
uniform bool openfl_HasColorTransform;
|
||||
uniform vec2 openfl_TextureSize;
|
||||
uniform sampler2D bitmap;
|
||||
|
||||
uniform bool hasTransform;
|
||||
uniform bool hasColorTransform;
|
||||
|
||||
vec4 applyFlixelEffects(vec4 color) {
|
||||
if(!hasTransform) {
|
||||
return color;
|
||||
}
|
||||
|
||||
if(color.a == 0.0) {
|
||||
return vec4(0.0, 0.0, 0.0, 0.0);
|
||||
}
|
||||
|
||||
if(!hasColorTransform) {
|
||||
return color * openfl_Alphav;
|
||||
}
|
||||
|
||||
color.rgb = color.rgb / color.a;
|
||||
color = clamp(openfl_ColorOffsetv + (color * openfl_ColorMultiplierv), 0.0, 1.0);
|
||||
|
||||
if(color.a > 0.0) {
|
||||
return vec4(color.rgb * color.a * openfl_Alphav, color.a * openfl_Alphav);
|
||||
}
|
||||
return vec4(0.0, 0.0, 0.0, 0.0);
|
||||
}
|
||||
|
||||
vec4 flixel_texture2D(sampler2D bitmap, vec2 coord) {
|
||||
vec4 color = texture2D(bitmap, coord);
|
||||
return applyFlixelEffects(color);
|
||||
}
|
||||
|
||||
uniform vec4 _camSize;
|
||||
|
||||
float map(float value, float min1, float max1, float min2, float max2) {
|
||||
return min2 + (value - min1) * (max2 - min2) / (max1 - min1);
|
||||
}
|
||||
|
||||
vec2 getCamPos(vec2 pos) {
|
||||
vec4 size = _camSize / vec4(openfl_TextureSize, openfl_TextureSize);
|
||||
return vec2(map(pos.x, size.x, size.x + size.z, 0.0, 1.0), map(pos.y, size.y, size.y + size.w, 0.0, 1.0));
|
||||
}
|
||||
vec2 camToOg(vec2 pos) {
|
||||
vec4 size = _camSize / vec4(openfl_TextureSize, openfl_TextureSize);
|
||||
return vec2(map(pos.x, 0.0, 1.0, size.x, size.x + size.z), map(pos.y, 0.0, 1.0, size.y, size.y + size.w));
|
||||
}
|
||||
vec4 textureCam(sampler2D bitmap, vec2 pos) {
|
||||
return flixel_texture2D(bitmap, camToOg(pos));
|
||||
}";
|
||||
|
||||
public static final fragBody:String = "gl_FragColor = flixel_texture2D(bitmap, openfl_TextureCoordv);";
|
||||
public static final vertHeader:String = "attribute float openfl_Alpha;
|
||||
attribute vec4 openfl_ColorMultiplier;
|
||||
attribute vec4 openfl_ColorOffset;
|
||||
@@ -679,32 +288,97 @@ attribute vec4 colorMultiplier;
|
||||
attribute vec4 colorOffset;
|
||||
uniform bool hasColorTransform;";
|
||||
|
||||
public static final vertBody:String = "openfl_Alphav = openfl_Alpha;
|
||||
openfl_TextureCoordv = openfl_TextureCoord;
|
||||
public static final vertBody:String = "openfl_TextureCoordv = openfl_TextureCoord;
|
||||
|
||||
if(openfl_HasColorTransform) {
|
||||
openfl_ColorMultiplierv = openfl_ColorMultiplier;
|
||||
openfl_ColorOffsetv = openfl_ColorOffset / 255.0;
|
||||
if (hasColorTransform)
|
||||
{
|
||||
openfl_Alphav = openfl_Alpha * colorMultiplier.a;
|
||||
if (openfl_HasColorTransform)
|
||||
{
|
||||
openfl_ColorOffsetv = (openfl_ColorOffset / 255.0 * colorMultiplier) + (colorOffset / 255.0);
|
||||
openfl_ColorMultiplierv = openfl_ColorMultiplier * vec4(colorMultiplier.rgb, 1.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
openfl_ColorOffsetv = colorOffset / 255.0;
|
||||
openfl_ColorMultiplierv = vec4(colorMultiplier.rgb, 1.0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
openfl_Alphav = openfl_Alpha * alpha;
|
||||
if (openfl_HasColorTransform)
|
||||
{
|
||||
openfl_ColorOffsetv = (openfl_ColorOffset + colorOffset) / 255.0;
|
||||
openfl_ColorMultiplierv = openfl_ColorMultiplier;
|
||||
}
|
||||
else
|
||||
{
|
||||
openfl_ColorOffsetv = colorOffset / 255.0;
|
||||
openfl_ColorMultiplierv = vec4(1.0);
|
||||
}
|
||||
}";
|
||||
|
||||
public static final fragHeader:String = "varying float openfl_Alphav;
|
||||
varying vec4 openfl_ColorMultiplierv;
|
||||
varying vec4 openfl_ColorOffsetv;
|
||||
varying vec2 openfl_TextureCoordv;
|
||||
|
||||
uniform bool openfl_HasColorTransform;
|
||||
uniform vec2 openfl_TextureSize;
|
||||
uniform sampler2D bitmap;
|
||||
uniform bool hasTransform;
|
||||
uniform bool hasColorTransform;
|
||||
uniform bool premultiplyAlpha;
|
||||
|
||||
vec4 apply_flixel_transform(vec4 color)
|
||||
{
|
||||
if (!hasTransform) return color;
|
||||
else if (color.a <= 0.0 || openfl_Alphav == 0.0) return vec4(0.0);
|
||||
|
||||
// this is just solely for ASTC compressed textures.
|
||||
// ...also in flixel_texture2D, it also converts to linear alpha anyway.
|
||||
if (!premultiplyAlpha) color.rgb /= color.a;
|
||||
|
||||
color = clamp(openfl_ColorOffsetv + (color * openfl_ColorMultiplierv), 0.0, 1.0);
|
||||
return vec4(color.rgb * color.a * openfl_Alphav, color.a * openfl_Alphav);
|
||||
}
|
||||
#define applyFlixelEffects(color) apply_flixel_transform(color)
|
||||
|
||||
vec4 flixel_texture2D(sampler2D bitmap, vec2 coord)
|
||||
{
|
||||
return apply_flixel_transform(texture2D(bitmap, coord));
|
||||
}
|
||||
|
||||
openfl_Alphav = openfl_Alpha * alpha;
|
||||
uniform vec4 _camSize;
|
||||
|
||||
if(hasColorTransform) {
|
||||
openfl_ColorOffsetv = colorOffset / 255.0;
|
||||
openfl_ColorMultiplierv = colorMultiplier;
|
||||
float map(float value, float min1, float max1, float min2, float max2) {
|
||||
return min2 + (value - min1) * (max2 - min2) / (max1 - min1);
|
||||
}
|
||||
|
||||
gl_Position = openfl_Matrix * openfl_Position;";
|
||||
vec2 getCamPos(vec2 pos) {
|
||||
vec4 size = _camSize / vec4(openfl_TextureSize, openfl_TextureSize);
|
||||
return vec2(map(pos.x, size.x, size.x + size.z, 0.0, 1.0), map(pos.y, size.y, size.y + size.w, 0.0, 1.0));
|
||||
}
|
||||
vec2 camToOg(vec2 pos) {
|
||||
vec4 size = _camSize / vec4(openfl_TextureSize, openfl_TextureSize);
|
||||
return vec2(map(pos.x, 0.0, 1.0, size.x, size.x + size.z), map(pos.y, 0.0, 1.0, size.y, size.y + size.w));
|
||||
}
|
||||
vec4 textureCam(sampler2D bitmap, vec2 pos) {
|
||||
return flixel_texture2D(bitmap, camToOg(pos));
|
||||
}";
|
||||
|
||||
// TODO: make this ignore comments
|
||||
public static final vertBackCompatVarList:Array<EReg> = [
|
||||
~/attribute float alpha/,
|
||||
~/attribute vec4 colorMultiplier/,
|
||||
~/attribute vec4 colorOffset/,
|
||||
~/uniform bool hasColorTransform/
|
||||
];
|
||||
public static final fragBody:String = "gl_FragColor = flixel_texture2D(bitmap, openfl_TextureCoordv);
|
||||
if (gl_FragColor.a == 0.0) discard;";
|
||||
|
||||
public static final vertHeaderBackCompat:String = "attribute float openfl_Alpha;
|
||||
public static final vertBackCompatVarList:Array<EReg> = [
|
||||
~/attribute float alpha/,
|
||||
~/attribute vec4 colorMultiplier/,
|
||||
~/attribute vec4 colorOffset/,
|
||||
~/uniform bool hasColorTransform/
|
||||
];
|
||||
|
||||
public static final vertHeaderBackCompat:String = "attribute float openfl_Alpha;
|
||||
attribute vec4 openfl_ColorMultiplier;
|
||||
attribute vec4 openfl_ColorOffset;
|
||||
attribute vec4 openfl_Position;
|
||||
@@ -719,7 +393,7 @@ uniform mat4 openfl_Matrix;
|
||||
uniform bool openfl_HasColorTransform;
|
||||
uniform vec2 openfl_TextureSize;";
|
||||
|
||||
public static final vertBodyBackCompat:String = "openfl_Alphav = openfl_Alpha;
|
||||
public static final vertBodyBackCompat:String = "openfl_Alphav = openfl_Alpha;
|
||||
openfl_TextureCoordv = openfl_TextureCoord;
|
||||
|
||||
if(openfl_HasColorTransform) {
|
||||
@@ -728,19 +402,8 @@ if(openfl_HasColorTransform) {
|
||||
}
|
||||
|
||||
gl_Position = openfl_Matrix * openfl_Position;";
|
||||
|
||||
public static final defaultVertexSource:String = "#pragma header
|
||||
|
||||
void main(void) {
|
||||
#pragma body
|
||||
}";
|
||||
|
||||
public static final defaultFragmentSource:String = "#pragma header
|
||||
|
||||
void main(void) {
|
||||
#pragma body
|
||||
}";
|
||||
}
|
||||
#end
|
||||
|
||||
class ShaderTypeException extends Exception {
|
||||
var has:Class<Dynamic>;
|
||||
@@ -753,16 +416,4 @@ class ShaderTypeException extends Exception {
|
||||
this.name = name;
|
||||
super('ShaderTypeException - Tried to set the shader uniform "${name}" as a ${Type.getClassName(has)}, but the shader uniform is a ${Std.string(want)}.');
|
||||
}
|
||||
}
|
||||
|
||||
class ShaderErrorPosition {
|
||||
public var column:Int;
|
||||
public var line:Int;
|
||||
public var message:String;
|
||||
|
||||
public function new(line:String, column:String, message:String) {
|
||||
this.line = Std.parseInt(line);
|
||||
this.column = Std.parseInt(column);
|
||||
this.message = message;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,471 @@
|
||||
package funkin.backend.shaders;
|
||||
|
||||
import haxe.Exception;
|
||||
import haxe.io.Path;
|
||||
import flixel.graphics.FlxGraphic;
|
||||
import flixel.system.FlxAssets.FlxShader;
|
||||
import flixel.util.FlxSignal.FlxTypedSignal;
|
||||
import flixel.util.FlxStringUtil;
|
||||
import hscript.IHScriptCustomBehaviour;
|
||||
import openfl.display.BitmapData;
|
||||
import openfl.display.ShaderInput;
|
||||
import openfl.display.ShaderParameter;
|
||||
import openfl.display.ShaderParameterType;
|
||||
import openfl.display.Shader;
|
||||
import openfl.display3D._internal.GLProgram;
|
||||
import openfl.display3D._internal.GLShader;
|
||||
import openfl.display3D.Program3D;
|
||||
import openfl.utils._internal.Log;
|
||||
|
||||
using StringTools;
|
||||
@:access(openfl.display3D.Context3D)
|
||||
@:access(openfl.display3D.Program3D)
|
||||
@:access(openfl.display.ShaderInput)
|
||||
@:access(openfl.display.ShaderParameter)
|
||||
class FunkinShader extends FlxShader implements IHScriptCustomBehaviour {
|
||||
#if REGION /* Backward Compatibility */
|
||||
private static var __instanceFields = Type.getInstanceFields(FunkinShader);
|
||||
private static var FRAGMENT_SHADER = 0;
|
||||
private static var VERTEX_SHADER = 1;
|
||||
|
||||
public var glslVer(get, set):String;
|
||||
inline function get_glslVer():String return glVersion;
|
||||
inline function set_glslVer(v:String):String return glVersion = v;
|
||||
|
||||
public var glRawFragmentSource(get, set):String;
|
||||
inline function get_glRawFragmentSource():String return __glFragmentSourceRaw;
|
||||
inline function set_glRawFragmentSource(v:String):String return __glFragmentSourceRaw = v;
|
||||
|
||||
public var glRawVertexSource(get, set):String;
|
||||
inline function get_glRawVertexSource():String return __glVertexSourceRaw;
|
||||
inline function set_glRawVertexSource(v:String):String return __glVertexSourceRaw = v;
|
||||
|
||||
// Unused... cne-openfl uses a different system
|
||||
var __cancelNextProcessGLData:Bool = false;
|
||||
public var onProcessGLData:FlxTypedSignal<(String, String)->Void> = new FlxTypedSignal<(String, String)->Void>();
|
||||
#end
|
||||
|
||||
public static function getShaderCode(key:String, isFragment = true):Null<String> {
|
||||
var path = "shaders/" + key;
|
||||
key = Path.withoutExtension(key);
|
||||
|
||||
final ext = Path.extension(path);
|
||||
if (ext == "") path = path + (isFragment ? ".frag" : ".vert");
|
||||
else isFragment = ext != "vert";
|
||||
|
||||
path = Paths.getPath(path);
|
||||
return Assets.exists(path) ? Assets.getText(path) : null;
|
||||
}
|
||||
|
||||
private static function processGLSLText(source:String, glVersion:String, isFragment:Bool, ?pragmas:Map<String, String>):String
|
||||
return Shader.processGLSLText(_processGLSLText(source, glVersion, isFragment, pragmas), glVersion, isFragment);
|
||||
|
||||
private static function _processGLSLText(source:String, glVersion:String, isFragment:Bool, ?pragmas:Map<String, String>):String {
|
||||
if (pragmas != null) {
|
||||
final pragmaKeyword = ~/#pragma\s+(\w+)/g;
|
||||
source = pragmaKeyword.map(source, (_) -> {
|
||||
var name = pragmaKeyword.matched(1), pragma:String;
|
||||
if (pragmas.exists(name)) pragma = pragmas.get(name);
|
||||
else {
|
||||
if (name != "header" && name != "body") return '#pragma $name';
|
||||
pragma = "";
|
||||
}
|
||||
return _processGLSLText(pragma, glVersion, isFragment, pragmas);
|
||||
});
|
||||
}
|
||||
|
||||
inline function tryGetShaderCode(key:String) {
|
||||
final s = getShaderCode(key, isFragment);
|
||||
if (s == null) {
|
||||
Logs.traceColored([
|
||||
Logs.logText('[Shader] ', RED),
|
||||
Logs.logText('Failed to import shader $key', RED),
|
||||
]);
|
||||
return "";
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
final includeKeyword = ~/#include ['"](.+)['"]/g;
|
||||
final importKeyword = ~/#import\s+<(.*)>/g;
|
||||
source = importKeyword.map(source, (_) ->
|
||||
return _processGLSLText(tryGetShaderCode(importKeyword.matched(1)), glVersion, isFragment, pragmas) ?? "");
|
||||
|
||||
return source = includeKeyword.map(source, (_) ->
|
||||
return _processGLSLText(tryGetShaderCode(includeKeyword.matched(1)), glVersion, isFragment, pragmas) ?? "");
|
||||
}
|
||||
|
||||
private static var __defaultsAvailable:Bool;
|
||||
private static var __glFragmentSourceDefault:String;
|
||||
private static var __glVertexSourceDefault:String;
|
||||
private static var __glFragmentPragmasDefault:Map<String, String>;
|
||||
private static var __glVertexPragmasDefault:Map<String, String>;
|
||||
private static var __glFragmentExtensionsDefault:Array<ShaderExtension>;
|
||||
private static var __glVertexExtensionsDefault:Array<ShaderExtension>;
|
||||
|
||||
public var onGLUpdate:FlxTypedSignal<Void->Void> = new FlxTypedSignal<Void->Void>();
|
||||
|
||||
public var fileName:String = "FunkinShader";
|
||||
public var fragFileName:String = "FunkinShader";
|
||||
public var vertFileName:String = "FunkinShader";
|
||||
|
||||
public var shaderPrefix:String = "";
|
||||
public var fragmentPrefix:String = "";
|
||||
public var vertexPrefix:String = "";
|
||||
|
||||
private var __immediate:Bool;
|
||||
|
||||
public function new(?fragmentSource:String, ?vertexSource:String, ?version:String,
|
||||
?fragmentExtensions:Array<ShaderExtension>, ?vertexExtensions:Array<ShaderExtension>, immediate = false
|
||||
) {
|
||||
if (!__defaultsAvailable) {
|
||||
__glFragmentSourceDefault = __glFragmentSourceRaw;
|
||||
__glVertexSourceDefault = __glVertexSourceRaw;
|
||||
__glFragmentPragmasDefault = __glFragmentPragmas.copy();
|
||||
__glVertexPragmasDefault = __glVertexPragmas.copy();
|
||||
__glFragmentExtensionsDefault = __glFragmentExtensions ?? [];
|
||||
__glVertexExtensionsDefault = __glVertexExtensions ?? [];
|
||||
__defaultsAvailable = true;
|
||||
}
|
||||
|
||||
__immediate = immediate;
|
||||
|
||||
if (version != null) glVersion = version;
|
||||
if (vertexExtensions != null) glVertexExtensions = vertexExtensions;
|
||||
if (fragmentExtensions != null) glFragmentExtensions = fragmentExtensions;
|
||||
if (vertexSource != null) glVertexSource = vertexSource;
|
||||
if (fragmentSource != null) glFragmentSource = fragmentSource;
|
||||
|
||||
super();
|
||||
|
||||
if (!__isGenerated) {
|
||||
__isGenerated = true;
|
||||
__init();
|
||||
}
|
||||
}
|
||||
|
||||
public function loadShader(name:String, ?version:String, immediate = false):FunkinShader {
|
||||
final fragment = getShaderCode(name, true), vertex = getShaderCode(name, false);
|
||||
|
||||
glVersion = version;
|
||||
glVertexSource = vertex ?? __glVertexSourceDefault;
|
||||
glFragmentSource = fragment ?? __glFragmentSourceDefault;
|
||||
|
||||
if (immediate) __init();
|
||||
return this;
|
||||
}
|
||||
|
||||
override function __initGL():Void {
|
||||
if (__immediate) {
|
||||
__context = FlxG.stage.context3D;
|
||||
__enable();
|
||||
}
|
||||
super.__initGL();
|
||||
}
|
||||
|
||||
override function __updateGL():Void {
|
||||
onGLUpdate.dispatch();
|
||||
super.__updateGL();
|
||||
}
|
||||
|
||||
public function hget(name:String):Dynamic {
|
||||
if (__glSourceDirty || __data == null) __init();
|
||||
|
||||
if (thisHasField(name) || thisHasField('get_${name}')) return Reflect.getProperty(this, name);
|
||||
else if (!Reflect.hasField(__data, name)) return null;
|
||||
|
||||
final field:Dynamic = Reflect.field(__data, name);
|
||||
|
||||
var cl:String = Type.getClassName(Type.getClass(field));
|
||||
|
||||
// little problem we are facing boys...
|
||||
|
||||
// cant do "field is ShaderInput" because ShaderInput has the @:generic metadata
|
||||
// aka instead of ShaderInput<Float> it gets built as ShaderInput_Float
|
||||
// this should be fine tho because we check the class, and the fields don't vary based on the type
|
||||
|
||||
// thanks for looking in the code cne fans :D!! -lunar
|
||||
|
||||
if (cl.startsWith("openfl.display.ShaderParameter"))
|
||||
return (field.__length > 1) ? field.value : field.value[0];
|
||||
else if (cl.startsWith("openfl.display.ShaderInput"))
|
||||
return field.input;
|
||||
return field;
|
||||
}
|
||||
|
||||
public function hset(name:String, val:Dynamic):Dynamic {
|
||||
if (__glSourceDirty || __data == null) __init();
|
||||
|
||||
if (thisHasField(name) || thisHasField('set_${name}')) {
|
||||
Reflect.setProperty(this, name, val);
|
||||
return val;
|
||||
}
|
||||
else if (!Reflect.hasField(__data, name)) {
|
||||
// ??? huh
|
||||
Reflect.setField(__data, name, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
var field = Reflect.field(__data, name);
|
||||
var cl = Type.getClassName(Type.getClass(field));
|
||||
var isNotNull = val != null;
|
||||
// cant do "field is ShaderInput" for some reason
|
||||
if (cl.startsWith("openfl.display.ShaderParameter")) {
|
||||
if (field.__length <= 1) {
|
||||
// that means we wait for a single number, instead of an array
|
||||
if (field.__isInt && isNotNull && !(val is Int)) {
|
||||
throw new ShaderTypeException(name, Type.getClass(val), 'Int');
|
||||
return null;
|
||||
} else
|
||||
if (field.__isBool && isNotNull && !(val is Bool)) {
|
||||
throw new ShaderTypeException(name, Type.getClass(val), 'Bool');
|
||||
return null;
|
||||
} else
|
||||
if (field.__isFloat && isNotNull && !(val is Float)) {
|
||||
throw new ShaderTypeException(name, Type.getClass(val), 'Float');
|
||||
return null;
|
||||
}
|
||||
return field.value = isNotNull ? [val] : null;
|
||||
} else {
|
||||
if (isNotNull && !(val is Array)) {
|
||||
throw new ShaderTypeException(name, Type.getClass(val), Array);
|
||||
return null;
|
||||
}
|
||||
return field.value = val;
|
||||
}
|
||||
} else if (cl.startsWith("openfl.display.ShaderInput")) {
|
||||
// shader input!!
|
||||
var bitmap:BitmapData;
|
||||
if (!isNotNull) bitmap = null;
|
||||
else if (val is BitmapData) bitmap = val;
|
||||
else if (val is FlxGraphic) bitmap = val.bitmap;
|
||||
else {
|
||||
throw new ShaderTypeException(name, Type.getClass(val), BitmapData);
|
||||
return null;
|
||||
}
|
||||
field.input = bitmap;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
override function __buildSourcePrefix(isFragment:Bool):String {
|
||||
var result = super.__buildSourcePrefix(isFragment) + '\n$shaderPrefix';
|
||||
return isFragment ? result + '\n$fragmentPrefix' : result + '\n$vertexPrefix';
|
||||
}
|
||||
|
||||
override function set_glFragmentExtensions(value:Array<ShaderExtension>):Array<ShaderExtension> {
|
||||
if (value == null) value = __glFragmentExtensionsDefault;
|
||||
if (value != __glFragmentExtensions) __glSourceDirty = true;
|
||||
return __glFragmentExtensions = value;
|
||||
}
|
||||
|
||||
override function set_glVertexExtensions(value:Array<ShaderExtension>):Array<ShaderExtension> {
|
||||
if (value == null) value = __glVertexExtensionsDefault;
|
||||
if (value != __glVertexExtensions) __glSourceDirty = true;
|
||||
return __glVertexExtensions = value;
|
||||
}
|
||||
|
||||
override function set_glVersion(value:Null<String>):String {
|
||||
if (value == null || value == "") value = Flags.DEFAULT_GLSL_VERSION;
|
||||
if ((__glVersionRaw = value) != __glVersion) {
|
||||
__glSourceDirty = true;
|
||||
if (__glVertexSourceRaw != null) __glVertexSource = processGLSLText(__glVertexSourceRaw, value, false, __glVertexPragmas);
|
||||
if (__glFragmentSourceRaw != null) __glFragmentSource = processGLSLText(__glFragmentSourceRaw, value, true, __glFragmentPragmas);
|
||||
}
|
||||
|
||||
return __glVersion = value;
|
||||
}
|
||||
|
||||
override function set_glFragmentSource(value:String):String {
|
||||
if (value == null || value == "") value = __glFragmentSourceDefault;
|
||||
if ((__glFragmentSourceRaw = value) != null) {
|
||||
if (__glVersion != (__glVersion = Shader.getGLSLTextVersion(value, __glVersionRaw)))
|
||||
__glSourceDirty = true;
|
||||
|
||||
value = processGLSLText(value, __glVersion, true, __glFragmentPragmas);
|
||||
}
|
||||
|
||||
if (value != __glFragmentSource) __glSourceDirty = true;
|
||||
return __glFragmentSource = value;
|
||||
}
|
||||
|
||||
override function set_glVertexSource(value:String):String {
|
||||
if (value == null || value == "") value = __glVertexSourceDefault;
|
||||
if ((__glVertexSourceRaw = value) != null) {
|
||||
if (__glVersion != (__glVersion = Shader.getGLSLTextVersion(value, __glVersionRaw)))
|
||||
__glSourceDirty = true;
|
||||
|
||||
value = processGLSLText(value, __glVersion, false, __glVertexPragmas);
|
||||
}
|
||||
|
||||
if (value != __glVertexSource) __glSourceDirty = true;
|
||||
return __glVertexSource = value;
|
||||
}
|
||||
|
||||
override function set_glFragmentPragmas(value:Map<String, String>):Map<String, String> {
|
||||
if (value == null) value = __glFragmentPragmasDefault;
|
||||
if (value != __glFragmentPragmas)
|
||||
__glSourceDirty = true;
|
||||
|
||||
return __glFragmentPragmas = value;
|
||||
}
|
||||
|
||||
override function set_glVertexPragmas(value:Map<String, String>):Map<String, String> {
|
||||
if (value == null) value = __glVertexPragmasDefault;
|
||||
if (value != __glVertexPragmas)
|
||||
__glSourceDirty = true;
|
||||
|
||||
return __glVertexPragmas = value;
|
||||
}
|
||||
|
||||
function registerParameter(name:String, type:String, isUniform:Bool):Void {
|
||||
__registerParameter(name, Program3D.getParameterTypeFromGLString(type, 1), 1, -1, isUniform, false, null);
|
||||
}
|
||||
|
||||
public function toString():String
|
||||
return FlxStringUtil.getDebugString([for (field in Reflect.fields(data)) LabelValuePair.weak(field, Reflect.field(data, field))]);
|
||||
}
|
||||
|
||||
class ShaderTemplates {
|
||||
#if REGION /* Backward Compatibility */
|
||||
public static final vertHeader:String = "attribute float openfl_Alpha;
|
||||
attribute vec4 openfl_ColorMultiplier;
|
||||
attribute vec4 openfl_ColorOffset;
|
||||
attribute vec4 openfl_Position;
|
||||
attribute vec2 openfl_TextureCoord;
|
||||
|
||||
varying float openfl_Alphav;
|
||||
varying vec4 openfl_ColorMultiplierv;
|
||||
varying vec4 openfl_ColorOffsetv;
|
||||
varying vec2 openfl_TextureCoordv;
|
||||
|
||||
uniform mat4 openfl_Matrix;
|
||||
uniform bool openfl_HasColorTransform;
|
||||
uniform vec2 openfl_TextureSize;
|
||||
|
||||
attribute float alpha;
|
||||
attribute vec4 colorMultiplier;
|
||||
attribute vec4 colorOffset;
|
||||
|
||||
uniform bool hasColorTransform;";
|
||||
|
||||
public static final vertBody:String = "openfl_TextureCoordv = openfl_TextureCoord;
|
||||
|
||||
if (hasColorTransform) {
|
||||
openfl_Alphav = openfl_Alpha * colorMultiplier.a;
|
||||
if (openfl_HasColorTransform) {
|
||||
openfl_ColorOffsetv = (openfl_ColorOffset / 255.0 * colorMultiplier) + (colorOffset / 255.0);
|
||||
openfl_ColorMultiplierv = openfl_ColorMultiplier * vec4(colorMultiplier.rgb, 1.0);
|
||||
}
|
||||
else {
|
||||
openfl_ColorOffsetv = colorOffset / 255.0;
|
||||
openfl_ColorMultiplierv = vec4(colorMultiplier.rgb, 1.0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
openfl_Alphav = openfl_Alpha * alpha;
|
||||
if (openfl_HasColorTransform) {
|
||||
openfl_ColorOffsetv = (openfl_ColorOffset + colorOffset) / 255.0;
|
||||
openfl_ColorMultiplierv = openfl_ColorMultiplier;
|
||||
}
|
||||
else {
|
||||
openfl_ColorOffsetv = colorOffset / 255.0;
|
||||
openfl_ColorMultiplierv = vec4(1.0);
|
||||
}
|
||||
}";
|
||||
|
||||
public static final fragHeader:String = "varying float openfl_Alphav;
|
||||
varying vec4 openfl_ColorMultiplierv;
|
||||
varying vec4 openfl_ColorOffsetv;
|
||||
varying vec2 openfl_TextureCoordv;
|
||||
|
||||
uniform bool openfl_HasColorTransform;
|
||||
uniform vec2 openfl_TextureSize;
|
||||
uniform sampler2D bitmap;
|
||||
|
||||
uniform bool hasTransform;
|
||||
uniform bool hasColorTransform;
|
||||
|
||||
vec4 apply_flixel_transform(vec4 color) {
|
||||
if (!hasTransform) return color;
|
||||
else if (color.a <= 0.0 || openfl_Alphav == 0.0) return vec4(0.0);
|
||||
|
||||
color.rgb /= color.a;
|
||||
color = clamp(openfl_ColorOffsetv + (color * openfl_ColorMultiplierv), 0.0, 1.0);
|
||||
return vec4(color.rgb * color.a * openfl_Alphav, color.a * openfl_Alphav);
|
||||
}
|
||||
|
||||
#define applyFlixelEffects(color) apply_flixel_transform(color)
|
||||
|
||||
vec4 flixel_texture2D(sampler2D bitmap, vec2 coord) {
|
||||
return apply_flixel_transform(texture2D(bitmap, coord));
|
||||
}
|
||||
|
||||
uniform vec4 _camSize;
|
||||
|
||||
float map(float value, float min1, float max1, float min2, float max2) {
|
||||
return min2 + (value - min1) * (max2 - min2) / (max1 - min1);
|
||||
}
|
||||
|
||||
vec2 getCamPos(vec2 pos) {
|
||||
vec4 size = _camSize / vec4(openfl_TextureSize, openfl_TextureSize);
|
||||
return vec2(map(pos.x, size.x, size.x + size.z, 0.0, 1.0), map(pos.y, size.y, size.y + size.w, 0.0, 1.0));
|
||||
}
|
||||
vec2 camToOg(vec2 pos) {
|
||||
vec4 size = _camSize / vec4(openfl_TextureSize, openfl_TextureSize);
|
||||
return vec2(map(pos.x, 0.0, 1.0, size.x, size.x + size.z), map(pos.y, 0.0, 1.0, size.y, size.y + size.w));
|
||||
}
|
||||
vec4 textureCam(sampler2D bitmap, vec2 pos) {
|
||||
return flixel_texture2D(bitmap, camToOg(pos));
|
||||
}";
|
||||
|
||||
public static final fragBody:String = "gl_FragColor = flixel_texture2D(bitmap, openfl_TextureCoordv);
|
||||
if (gl_FragColor.a == 0.0) discard;";
|
||||
|
||||
public static final vertBackCompatVarList:Array<EReg> = [
|
||||
~/attribute float alpha/,
|
||||
~/attribute vec4 colorMultiplier/,
|
||||
~/attribute vec4 colorOffset/,
|
||||
~/uniform bool hasColorTransform/
|
||||
];
|
||||
|
||||
public static final vertHeaderBackCompat:String = "attribute float openfl_Alpha;
|
||||
attribute vec4 openfl_ColorMultiplier;
|
||||
attribute vec4 openfl_ColorOffset;
|
||||
attribute vec4 openfl_Position;
|
||||
attribute vec2 openfl_TextureCoord;
|
||||
|
||||
varying float openfl_Alphav;
|
||||
varying vec4 openfl_ColorMultiplierv;
|
||||
varying vec4 openfl_ColorOffsetv;
|
||||
varying vec2 openfl_TextureCoordv;
|
||||
|
||||
uniform mat4 openfl_Matrix;
|
||||
uniform bool openfl_HasColorTransform;
|
||||
uniform vec2 openfl_TextureSize;";
|
||||
|
||||
public static final vertBodyBackCompat:String = "openfl_Alphav = openfl_Alpha;
|
||||
openfl_TextureCoordv = openfl_TextureCoord;
|
||||
|
||||
if(openfl_HasColorTransform) {
|
||||
openfl_ColorMultiplierv = openfl_ColorMultiplier;
|
||||
openfl_ColorOffsetv = openfl_ColorOffset / 255.0;
|
||||
}
|
||||
|
||||
gl_Position = openfl_Matrix * openfl_Position;";
|
||||
#end
|
||||
}
|
||||
|
||||
class ShaderTypeException extends Exception {
|
||||
var has:Class<Dynamic>;
|
||||
var want:Class<Dynamic>;
|
||||
var name:String;
|
||||
|
||||
public function new(name:String, has:Class<Dynamic>, want:Dynamic) {
|
||||
this.has = has;
|
||||
this.want = want;
|
||||
this.name = name;
|
||||
super('ShaderTypeException - Tried to set the shader uniform "${name}" as a ${Type.getClassName(has)}, but the shader uniform is a ${Std.string(want)}.');
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,8 @@ class ScriptableShader extends FlxBasic implements IHScriptCustomBehaviour {
|
||||
if((shader is CustomShader)) scriptName = cast(shader, CustomShader).fileName;
|
||||
else throw "Missing name for shader script, please provide a scriptName, or use CustomShader";
|
||||
|
||||
this.shader = shader;
|
||||
|
||||
script = Script.create(Paths.script('shaders/$scriptName'));
|
||||
script.setParent(shader);
|
||||
script.set("shader", shader);
|
||||
|
||||
@@ -25,6 +25,7 @@ enum Control
|
||||
CHANGE_MODE;
|
||||
//CHEAT;
|
||||
SWITCHMOD;
|
||||
FPS_COUNTER;
|
||||
|
||||
// Debugs
|
||||
DEV_ACCESS;
|
||||
@@ -161,6 +162,11 @@ class Controls extends FlxActionSet
|
||||
@:pressed("switchmod") public var SWITCHMOD_HOLD(get, set): Bool;
|
||||
@:justReleased("switchmod") public var SWITCHMOD_R(get, set): Bool;
|
||||
|
||||
@:gamepad([])
|
||||
@:justPressed("fps-counter") public var FPS_COUNTER(get, set): Bool;
|
||||
@:pressed("fps-counter") public var FPS_COUNTER_HOLD(get, set): Bool;
|
||||
@:justReleased("fps-counter") public var FPS_COUNTER_R(get, set): Bool;
|
||||
|
||||
@:devModeOnly
|
||||
@:gamepad([])
|
||||
@:justPressed("dev-access") public var DEV_ACCESS(get, set): Bool;
|
||||
|
||||
@@ -11,6 +11,11 @@ import openfl.display.BlendMode;
|
||||
import openfl.geom.ColorTransform;
|
||||
import openfl.geom.Point;
|
||||
import openfl.geom.Rectangle;
|
||||
import openfl.display.TriangleCulling;
|
||||
import openfl.display3D.Context3DWrapMode;
|
||||
import openfl.display3D.Context3DCompareMode;
|
||||
import openfl.filters.BitmapFilter;
|
||||
import openfl.filters.ShaderFilter;
|
||||
|
||||
class FakeCamera extends FlxCamera {
|
||||
public static final instance = new FakeCamera();
|
||||
@@ -21,14 +26,14 @@ class FakeCamera extends FlxCamera {
|
||||
visible = false;
|
||||
}
|
||||
|
||||
override function startTrianglesBatch(graphic:FlxGraphic, smoothing:Bool = false, isColored:Bool = false, ?blend:BlendMode, ?hasColorOffsets:Bool, ?shader:FlxShader) { return null;}
|
||||
override function startQuadBatch(graphic:FlxGraphic, colored:Bool, hasColorOffsets:Bool = false, ?blend:BlendMode, smooth:Bool = false, ?shader:FlxShader) { return null;}
|
||||
override function startTrianglesBatch(graphic:FlxGraphic, smoothing:Bool = false, isColored:Bool = false, ?blend:BlendMode, ?hasColorOffsets:Bool, ?shader:FlxShader, ?wrapMode:Context3DWrapMode, ?depthCompareMode:Context3DCompareMode, ?culling:TriangleCulling) { return null;}
|
||||
override function startQuadBatch(graphic:FlxGraphic, colored:Bool, hasColorOffsets:Bool = false, ?blend:BlendMode, smooth:Bool = false, ?shader:FlxShader, ?wrapMode:Context3DWrapMode, ?depthCompareMode:Context3DCompareMode) { return null;}
|
||||
override function clearDrawStack() {}
|
||||
override function render() {}
|
||||
|
||||
public override function drawPixels(?frame:FlxFrame, ?pixels:BitmapData, matrix:FlxMatrix, ?transform:ColorTransform, ?blend:BlendMode, ?smoothing:Bool = false, ?shader:FlxShader) {}
|
||||
public override function copyPixels(?frame:FlxFrame, ?pixels:BitmapData, ?sourceRect:Rectangle, destPoint:Point, ?transform:ColorTransform, ?blend:BlendMode, ?smoothing:Bool = false, ?shader:FlxShader) {}
|
||||
public override function drawTriangles(graphic:FlxGraphic, vertices:DrawData<Float>, indices:DrawData<Int>, uvtData:DrawData<Float>, ?colors:DrawData<Int>, ?position:FlxPoint, ?blend:BlendMode, repeat:Bool = false, smoothing:Bool = false, ?transform:ColorTransform, ?shader:FlxShader):Void {}
|
||||
public override function drawPixels(?frame:FlxFrame, ?pixels:BitmapData, matrix:FlxMatrix, ?transform:ColorTransform, ?blend:BlendMode, ?smoothing:Bool = false, ?shader:FlxShader, ?wrapMode:Context3DWrapMode, ?depthCompareMode:Context3DCompareMode) {}
|
||||
public override function copyPixels(?frame:FlxFrame, ?pixels:BitmapData, ?sourceRect:Rectangle, destPoint:Point, ?transform:ColorTransform, ?blend:BlendMode, ?smoothing:Bool = false, ?shader:FlxShader, ?wrapMode:Context3DWrapMode, ?depthCompareMode:Context3DCompareMode) {}
|
||||
public override function drawTriangles(graphic:FlxGraphic, vertices:DrawData<Float>, indices:DrawData<Int>, uvtData:DrawData<Float>, ?colors:DrawData<Int>, ?position:FlxPoint, ?blend:BlendMode, repeat:Bool = false, smoothing:Bool = false, ?transform:ColorTransform, ?shader:FlxShader, ?wrapMode:Context3DWrapMode, ?depthCompareMode:Context3DCompareMode, ?culling:TriangleCulling):Void {}
|
||||
|
||||
public override function update(elapsed:Float) {}
|
||||
|
||||
@@ -41,10 +46,10 @@ class FakeCallCamera extends FakeCamera {
|
||||
public static final instance = new FakeCallCamera();
|
||||
public var ignoreDraws:Bool = false;
|
||||
|
||||
public dynamic function onDraw(?frame:FlxFrame, ?pixels:BitmapData, matrix:FlxMatrix, ?transform:ColorTransform, ?blend:BlendMode, ?smoothing:Bool = false, ?shader:FlxShader) {
|
||||
public dynamic function onDraw(?frame:FlxFrame, ?pixels:BitmapData, matrix:FlxMatrix, ?transform:ColorTransform, ?blend:BlendMode, ?smoothing:Bool = false, ?shader:FlxShader, ?wrapMode:Context3DWrapMode, ?depthCompareMode:Context3DCompareMode) {
|
||||
}
|
||||
|
||||
override function drawPixels(?frame:FlxFrame, ?pixels:BitmapData, matrix:FlxMatrix, ?transform:ColorTransform, ?blend:BlendMode, ?smoothing:Bool = false, ?shader:FlxShader) {
|
||||
if (!ignoreDraws) onDraw(frame, pixels, matrix, transform, blend, smoothing, shader);
|
||||
override function drawPixels(?frame:FlxFrame, ?pixels:BitmapData, matrix:FlxMatrix, ?transform:ColorTransform, ?blend:BlendMode, ?smoothing:Bool = false, ?shader:FlxShader, ?wrapMode:Context3DWrapMode, ?depthCompareMode:Context3DCompareMode) {
|
||||
if (!ignoreDraws) onDraw(frame, pixels, matrix, transform, blend, smoothing, shader, wrapMode, depthCompareMode);
|
||||
}
|
||||
}
|
||||
@@ -15,14 +15,20 @@ import lime.utils.AssetType;
|
||||
*/
|
||||
@:build(funkin.backend.system.macros.FlagMacro.build())
|
||||
class Flags {
|
||||
public static var overridenFlags:Map<String, Bool> = [];
|
||||
|
||||
// -- Codename's Addon Config --
|
||||
@:bypass public static var addonFlags:Map<String, Dynamic> = [];
|
||||
public static var CURRENT_API_VERSION:Int = 2;
|
||||
|
||||
// -- Codename's ZipFolderLibrary Config --
|
||||
public static var ALLOWED_ZIP_EXTENSIONS:Array<String> = ["zip"];
|
||||
|
||||
// -- Codename's Mod Config --
|
||||
public static var MOD_NAME:String = "";
|
||||
public static var MOD_DESCRIPTION:String = "";
|
||||
public static var MOD_AUTHOR:String = "";
|
||||
public static var MOD_API_VERSION:Int = 1;
|
||||
@:lazy public static var MOD_API_VERSION:Null<Int> = null;
|
||||
public static var MOD_DOWNLOAD_LINK:String = "";
|
||||
public static var MOD_DEPENDENCIES:Array<String> = [];
|
||||
|
||||
@@ -41,12 +47,11 @@ class Flags {
|
||||
@:lazy public static var SAVE_PATH:String = haxe.macro.Compiler.getDefine("SAVE_PATH");
|
||||
@:lazy public static var SAVE_NAME:String = haxe.macro.Compiler.getDefine("SAVE_NAME");
|
||||
|
||||
public static var CURRENT_API_VERSION:Int = 1;
|
||||
public static var COMMIT_NUMBER:Int = GitCommitMacro.commitNumber;
|
||||
public static var COMMIT_HASH:String = GitCommitMacro.commitHash;
|
||||
public static var COMMIT_MESSAGE:String = 'Commit $COMMIT_NUMBER ($COMMIT_HASH)';
|
||||
|
||||
@:bypass public static var WINDOW_TITLE_USE_MOD_NAME:Bool = false;
|
||||
@:lazy public static var WINDOW_TITLE_USE_MOD_NAME:Null<Bool> = null;
|
||||
@:lazy public static var TITLE:String = Application.current.meta.get('name');
|
||||
@:lazy public static var VERSION:String = Application.current.meta.get('version');
|
||||
|
||||
@@ -101,6 +106,10 @@ class Flags {
|
||||
public static var DEFAULT_BEATS_PER_MEASURE:Int = 4;
|
||||
public static var DEFAULT_STEPS_PER_BEAT:Int = 4;
|
||||
public static var DEFAULT_LOOP_TIME:Float = 0.0;
|
||||
public static var ICONS_AUTOPOSITION:Bool = true;
|
||||
|
||||
@:lazy public static var DEFAULT_SOUND_TIME_SCALED_PITCH:Null<Bool> = null;
|
||||
@:lazy public static var USE_FLXTRAIL_FRAMES:Null<Bool> = null;
|
||||
|
||||
public static var SUPPORTED_CHART_RUNTIME_FORMATS:Array<String> = ["Legacy", "Psych Engine"];
|
||||
public static var SUPPORTED_CHART_FORMATS:Array<String> = ["BaseGame"];
|
||||
@@ -125,12 +134,19 @@ class Flags {
|
||||
@:also(funkin.game.PlayState.opponentMode)
|
||||
public static var DEFAULT_OPPONENT_MODE:Bool = false;
|
||||
|
||||
public static var EARLY_HIT_WINDOW_RANGE:Float = 1.0; // was 0.5 for easier early hitting, but now 1 to demotivate mashing and getting away with it.
|
||||
public static var LATE_HIT_WINDOW_RANGE:Float = 1.0;
|
||||
public static var SHITS_BREAK_COMBO:Bool = true;
|
||||
public static var USE_LEGACY_TIMING:Null<Bool> = null;
|
||||
|
||||
public static var DEFAULT_NOTE_MS_LIMIT:Float = 1500;
|
||||
public static var DEFAULT_NOTE_SCALE:Float = 0.7;
|
||||
#if MODCHARTING_FEATURES
|
||||
public static var DEFAULT_MODCHART_HOLD_SUBDIVISIONS:Int = 4;
|
||||
#end
|
||||
|
||||
public static var SUSTAINS_AS_ONE_NOTE:Null<Bool> = null;
|
||||
|
||||
@:also(funkin.game.Character.FALLBACK_DEAD_CHARACTER)
|
||||
public static var DEFAULT_GAMEOVER_CHARACTER:String = "bf-dead";
|
||||
|
||||
@@ -148,10 +164,14 @@ class Flags {
|
||||
public static var DEFAULT_HUD_ZOOM_MULT:Float = 0.03;
|
||||
public static var DEFAULT_CAM_ZOOM_LERP:Float = 0.05;
|
||||
public static var DEFAULT_HUD_ZOOM_LERP:Float = 0.05;
|
||||
|
||||
public static var USE_LEGACY_ZOOM_FACTOR:Null<Bool> = null;
|
||||
|
||||
// Font configuration
|
||||
public static var DEFAULT_FONT:String = "vcr.ttf";
|
||||
public static var DEFAULT_FONT_SIZE:Int = 16;
|
||||
|
||||
public static var DEFAULT_ALT_ANIM_SUFFIX:String = "-alt";
|
||||
|
||||
// to translate these you need to convert them into ids
|
||||
// Resume -> pause.resume
|
||||
@@ -266,7 +286,7 @@ class Flags {
|
||||
public static var DEFAULT_CHARACTER_GHOSTDISABLE_SOUND:String = "editors/character/ghostDisable";
|
||||
public static var DEFAULT_CHARACTER_GHOSTENABLE_SOUND:String = "editors/character/ghostEnable";
|
||||
|
||||
public static var DEFAULT_GLSL_VERSION:String = "120";
|
||||
@:lazy public static var DEFAULT_GLSL_VERSION:String = null;
|
||||
@:also(funkin.backend.utils.HttpUtil.userAgent)
|
||||
public static var USER_AGENT:String = 'request';
|
||||
// -- End of Codename's Default Flags --
|
||||
@@ -277,8 +297,6 @@ class Flags {
|
||||
@:bypass public static var customFlags:Map<String, String> = [];
|
||||
|
||||
public static function loadFromData(flags:Map<String, String>, data:String) {
|
||||
WINDOW_TITLE_USE_MOD_NAME = false;
|
||||
|
||||
if (!(data.length > 0)) return;
|
||||
var res = IniUtil.parseString(data);
|
||||
|
||||
@@ -295,28 +313,53 @@ class Flags {
|
||||
else trace('Invalid section $name');
|
||||
}
|
||||
}
|
||||
|
||||
if (!flags.exists("WINDOW_TITLE_USE_MOD_NAME")) WINDOW_TITLE_USE_MOD_NAME = !flags.exists('TITLE') && flags.exists('MOD_NAME');
|
||||
else WINDOW_TITLE_USE_MOD_NAME = parseBool(flags.get("WINDOW_TITLE_USE_MOD_NAME"));
|
||||
|
||||
flags.remove("WINDOW_TITLE_USE_MOD_NAME");
|
||||
}
|
||||
|
||||
public static function loadFromDatas(datas:Array<String>) {
|
||||
private static function loadPost() {
|
||||
if (MOD_API_VERSION == null) MOD_API_VERSION = CURRENT_API_VERSION;
|
||||
if (WINDOW_TITLE_USE_MOD_NAME == null) WINDOW_TITLE_USE_MOD_NAME = !overridenFlags.exists('TITLE') && overridenFlags.exists('MOD_NAME');
|
||||
if (USE_LEGACY_TIMING == null) USE_LEGACY_TIMING = MOD_API_VERSION < 2;
|
||||
if (USE_LEGACY_ZOOM_FACTOR == null) USE_LEGACY_ZOOM_FACTOR = MOD_API_VERSION < 2;
|
||||
if (SUSTAINS_AS_ONE_NOTE == null) SUSTAINS_AS_ONE_NOTE = MOD_API_VERSION >= 2;
|
||||
if (DEFAULT_GLSL_VERSION == null) {
|
||||
if (MOD_API_VERSION < 2) {
|
||||
DEFAULT_GLSL_VERSION = #if (android || mac || web) "100" #else "120" #end;
|
||||
Logs.warn("Blend Mode Extensions won't work in MOD_API_VERSION below than 2");
|
||||
}
|
||||
else {
|
||||
DEFAULT_GLSL_VERSION = openfl.utils.GLSLSourceAssembler.getDefaultVersion();
|
||||
}
|
||||
}
|
||||
if (DEFAULT_SOUND_TIME_SCALED_PITCH == null) DEFAULT_SOUND_TIME_SCALED_PITCH = MOD_API_VERSION >= 2;
|
||||
if (USE_FLXTRAIL_FRAMES == null) USE_FLXTRAIL_FRAMES = MOD_API_VERSION < 2;
|
||||
|
||||
flixel.sound.FlxSound.defaultTimeScaledPitch = cast DEFAULT_SOUND_TIME_SCALED_PITCH;
|
||||
flixel.addons.effects.FlxTrail.defaultDelayBackwardCompatibility = cast USE_FLXTRAIL_FRAMES;
|
||||
}
|
||||
|
||||
public static function loadFromDatas(datas:Array<String>):Map<String, String> {
|
||||
var flags:Map<String, String> = [];
|
||||
for(data in datas) {
|
||||
if(data != null)
|
||||
for (data in datas) {
|
||||
if (data != null)
|
||||
loadFromData(flags, data);
|
||||
}
|
||||
loadPost();
|
||||
return flags;
|
||||
}
|
||||
|
||||
public static function parseFlags(flags:Map<String, String>) {
|
||||
for(name=>value in flags)
|
||||
if(!parse(name, value))
|
||||
customFlags.set(name, value);
|
||||
|
||||
var parsed:Bool;
|
||||
for (name => value in flags) switch (name) {
|
||||
case "MOD_API_VERSION":
|
||||
var version = Std.parseInt(value) ?? CURRENT_API_VERSION;
|
||||
if (version > MOD_API_VERSION || MOD_API_VERSION == null) MOD_API_VERSION = version;
|
||||
default:
|
||||
if (!(parsed = parse(name, value))) customFlags.set(name, value);
|
||||
if (!overridenFlags.exists(name)) overridenFlags.set(name, parsed);
|
||||
}
|
||||
#if MODCHARTING_FEATURES
|
||||
Options.modchartingHoldSubdivisions = DEFAULT_MODCHART_HOLD_SUBDIVISIONS;
|
||||
#end
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -365,5 +408,6 @@ class Flags {
|
||||
parseFlags(flags);
|
||||
}
|
||||
}
|
||||
loadPost();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,13 +8,12 @@ class FunkinGame extends FlxGame {
|
||||
super.switchState();
|
||||
// draw once to put all images in gpu then put the last update time to now to prevent lag spikes or whatever
|
||||
draw();
|
||||
_total = ticks = getTicks();
|
||||
ticks = getTicks();
|
||||
skipNextTickUpdate = true;
|
||||
}
|
||||
|
||||
public override function onEnterFrame(t) {
|
||||
if (skipNextTickUpdate != (skipNextTickUpdate = false))
|
||||
_total = ticks = getTicks();
|
||||
super.onEnterFrame(t);
|
||||
override function __enterFrame(deltaTime:Float) {
|
||||
if (skipNextTickUpdate != (skipNextTickUpdate = false)) ticks = getTicks();
|
||||
super.__enterFrame(deltaTime);
|
||||
}
|
||||
}
|
||||
@@ -36,7 +36,7 @@ class GraphicCacheSprite extends FlxSprite {
|
||||
if (graphic == null) return;
|
||||
|
||||
// make their useCount one time higher to prevent them from auto being cleared from cache
|
||||
graphic.useCount++;
|
||||
graphic.incrementUseCount();
|
||||
graphic.destroyOnNoUse = false;
|
||||
cachedGraphics.push(graphic);
|
||||
nonRenderedCachedGraphics.push(graphic);
|
||||
@@ -45,7 +45,7 @@ class GraphicCacheSprite extends FlxSprite {
|
||||
public override function destroy() {
|
||||
for(g in cachedGraphics) {
|
||||
g.destroyOnNoUse = true;
|
||||
g.useCount--;
|
||||
g.decrementUseCount();
|
||||
}
|
||||
graphic = null;
|
||||
super.destroy();
|
||||
|
||||
@@ -115,7 +115,7 @@ final class Logs {
|
||||
Sys.print(t.text);
|
||||
}
|
||||
NativeAPI.setConsoleColors();
|
||||
Sys.print("\r\n");
|
||||
Sys.println("\r");
|
||||
__showing = false;
|
||||
#elseif mobile
|
||||
while(__showing) {
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package funkin.backend.system;
|
||||
|
||||
import sys.io.File;
|
||||
import sys.FileSystem;
|
||||
import flixel.addons.transition.FlxTransitionSprite.GraphicTransTileDiamond;
|
||||
import flixel.addons.transition.FlxTransitionableState;
|
||||
import flixel.addons.transition.TransitionData;
|
||||
@@ -9,24 +7,25 @@ import flixel.graphics.FlxGraphic;
|
||||
import flixel.math.FlxPoint;
|
||||
import flixel.math.FlxRect;
|
||||
import flixel.system.ui.FlxSoundTray;
|
||||
import funkin.backend.assets.AssetSource;
|
||||
import funkin.backend.assets.AssetsLibraryList;
|
||||
import funkin.backend.assets.ModsFolder;
|
||||
import funkin.backend.assets.AssetSource;
|
||||
import funkin.backend.system.framerate.Framerate;
|
||||
import funkin.backend.system.framerate.SystemInfo;
|
||||
import funkin.backend.system.modules.*;
|
||||
import funkin.backend.utils.ThreadUtil;
|
||||
import funkin.editors.SaveWarning;
|
||||
import funkin.options.PlayerSettings;
|
||||
import openfl.Assets;
|
||||
import openfl.Lib;
|
||||
import openfl.display.Sprite;
|
||||
import openfl.text.TextFormat;
|
||||
import openfl.utils.AssetLibrary;
|
||||
|
||||
#if ALLOW_MULTITHREADING
|
||||
import sys.thread.Thread;
|
||||
#end
|
||||
import sys.FileSystem;
|
||||
import sys.io.File;
|
||||
#if android
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import extension.androidtools.content.Context;
|
||||
import extension.androidtools.os.Build;
|
||||
#end
|
||||
|
||||
class Main extends Sprite
|
||||
@@ -34,13 +33,13 @@ class Main extends Sprite
|
||||
public static var instance:Main;
|
||||
|
||||
public static var modToLoad:String = null;
|
||||
public static var forceGPUOnlyBitmapsOff:Bool = #if desktop false #else true #end;
|
||||
public static var forceGPUOnlyBitmapsOff:Bool = false;
|
||||
public static var noTerminalColor:Bool = false;
|
||||
public static var verbose:Bool = false;
|
||||
|
||||
public static var scaleMode:FunkinRatioScaleMode;
|
||||
#if !mobile
|
||||
public static var framerateSprite:funkin.backend.system.framerate.Framerate;
|
||||
public static var framerateSprite:Framerate;
|
||||
#end
|
||||
|
||||
var gameWidth:Int = 1280; // Width of the game in pixels (might be less / more in actual pixels).
|
||||
@@ -58,14 +57,12 @@ class Main extends Sprite
|
||||
|
||||
// You can pretty much ignore everything from here on - your code should go in your states.
|
||||
|
||||
#if ALLOW_MULTITHREADING
|
||||
public static var gameThreads:Array<Thread> = [];
|
||||
#end
|
||||
|
||||
public static function preInit() {
|
||||
#if sys
|
||||
funkin.backend.utils.NativeAPI.registerAsDPICompatible();
|
||||
funkin.backend.system.CommandLineHandler.parseCommandLine(Sys.args());
|
||||
funkin.backend.system.Main.fixWorkingDirectory();
|
||||
#end
|
||||
}
|
||||
|
||||
public function new()
|
||||
@@ -79,7 +76,7 @@ class Main extends Sprite
|
||||
addChild(game = new FunkinGame(gameWidth, gameHeight, MainState, Options.framerate, Options.framerate, skipSplash, startFullscreen));
|
||||
|
||||
#if (!mobile && !web)
|
||||
addChild(framerateSprite = new funkin.backend.system.framerate.Framerate());
|
||||
addChild(framerateSprite = new Framerate());
|
||||
SystemInfo.init();
|
||||
#end
|
||||
}
|
||||
@@ -97,31 +94,13 @@ class Main extends Sprite
|
||||
#end;
|
||||
public static var startedFromSource:Bool = #if TEST_BUILD true #else false #end;
|
||||
|
||||
|
||||
private static var __threadCycle:Int = 0;
|
||||
public static function execAsync(func:Void->Void) {
|
||||
#if ALLOW_MULTITHREADING
|
||||
var thread = gameThreads[(__threadCycle++) % gameThreads.length];
|
||||
thread.events.run(func);
|
||||
#else
|
||||
func();
|
||||
#end
|
||||
}
|
||||
|
||||
private static function getTimer():Int {
|
||||
return time = Lib.getTimer();
|
||||
}
|
||||
// DEPRECATED
|
||||
@:dox(hide) public static function execAsync(func:Void->Void) ThreadUtil.execAsync(func);
|
||||
|
||||
public static function loadGameSettings() {
|
||||
WindowUtils.init();
|
||||
SaveWarning.init();
|
||||
MemoryUtil.init();
|
||||
@:privateAccess
|
||||
FlxG.game.getTimer = getTimer;
|
||||
#if ALLOW_MULTITHREADING
|
||||
for(i in 0...4)
|
||||
gameThreads.push(Thread.createWithEventLoop(function() {Thread.current().events.promise();}));
|
||||
#end
|
||||
FunkinCache.init();
|
||||
Paths.assetsTree = new AssetsLibraryList();
|
||||
|
||||
@@ -146,16 +125,16 @@ class Main extends Sprite
|
||||
funkin.options.PlayerSettings.init();
|
||||
Options.load();
|
||||
|
||||
game.focusLostFramerate = 30;
|
||||
FlxG.fixedTimestep = false;
|
||||
|
||||
FlxG.scaleMode = scaleMode = new FunkinRatioScaleMode();
|
||||
|
||||
Conductor.init();
|
||||
AudioSwitchFix.init();
|
||||
EventManager.init();
|
||||
FlxG.signals.focusGained.add(onFocus);
|
||||
FlxG.signals.preStateSwitch.add(onStateSwitch);
|
||||
FlxG.signals.postStateSwitch.add(onStateSwitchPost);
|
||||
FlxG.signals.postUpdate.add(onUpdate);
|
||||
|
||||
FlxG.mouse.useSystemCursor = true;
|
||||
#if DARK_MODE_WINDOW
|
||||
@@ -210,20 +189,18 @@ class Main extends Sprite
|
||||
scaleMode.resetSize();
|
||||
}
|
||||
|
||||
public static function onUpdate() {
|
||||
if (PlayerSettings.solo.controls.DEV_CONSOLE)
|
||||
NativeAPI.allocConsole();
|
||||
|
||||
if (PlayerSettings.solo.controls.FPS_COUNTER)
|
||||
Framerate.debugMode = (Framerate.debugMode + 1) % 3;
|
||||
}
|
||||
|
||||
private static function onStateSwitchPost() {
|
||||
// manual asset clearing since base openfl one does'nt clear lime one
|
||||
// does'nt clear bitmaps since flixel fork does it auto
|
||||
|
||||
@:privateAccess {
|
||||
// clear uint8 pools
|
||||
for(length=>pool in openfl.display3D.utils.UInt8Buff._pools) {
|
||||
for(b in pool.clear())
|
||||
b.destroy();
|
||||
}
|
||||
|
||||
openfl.display3D.utils.UInt8Buff._pools.clear();
|
||||
}
|
||||
|
||||
MemoryUtil.clearMajor();
|
||||
}
|
||||
|
||||
|
||||
@@ -7,12 +7,14 @@ import flixel.FlxState;
|
||||
import funkin.backend.assets.AssetsLibraryList;
|
||||
import funkin.backend.assets.ModsFolder;
|
||||
import funkin.backend.assets.ModsFolderLibrary;
|
||||
import funkin.backend.assets.ZipFolderLibrary;
|
||||
import funkin.backend.chart.EventsData;
|
||||
import funkin.backend.system.framerate.Framerate;
|
||||
import funkin.editors.ModConfigWarning;
|
||||
import funkin.menus.TitleState;
|
||||
import haxe.io.Path;
|
||||
|
||||
|
||||
@dox(hide)
|
||||
typedef AddonInfo = {
|
||||
var name:String;
|
||||
@@ -40,6 +42,7 @@ class MainState extends FlxState {
|
||||
ControlsUtil.resetCustomControls();
|
||||
FlxG.bitmap.reset();
|
||||
FlxG.sound.destroy(true);
|
||||
FlxG.sound.resetCache();
|
||||
|
||||
Paths.assetsTree.reset();
|
||||
|
||||
@@ -57,12 +60,32 @@ class MainState extends FlxState {
|
||||
var _highPriorityAddons:Array<AddonInfo> = [];
|
||||
var _noPriorityAddons:Array<AddonInfo> = [];
|
||||
|
||||
var quick_modsPath = ModsFolder.modsPath + ModsFolder.currentModFolder;
|
||||
|
||||
// handing if the loading mod (before it's properly loaded) is a compressed mod
|
||||
// we just need to use `Paths.assetsTree.hasCompressedLibrary` to complete valid checks for actual loaded compressed mods
|
||||
var isZipMod = false;
|
||||
|
||||
// If we know it's a compressed mod, then we can check if it's using the `cnemod` folder path.
|
||||
// All it is really is a folder with the mod's name, then a compressed file called "cnemod.[zip|7z|rar|etc]"
|
||||
var isCneMod = false;
|
||||
|
||||
// We are doing it like this because think about it: it's 1 for loop lol
|
||||
// We just need to know if any of these values is true, so if only one is true and we are not close to being done in the loop, that's fine.
|
||||
//
|
||||
for (ext in Flags.ALLOWED_ZIP_EXTENSIONS) {
|
||||
if (FileSystem.exists(quick_modsPath+"."+ext)) isZipMod = true;
|
||||
if (FileSystem.exists(quick_modsPath+"/cnemod."+ext)) isCneMod = true;
|
||||
if (isZipMod && isCneMod) break;
|
||||
}
|
||||
|
||||
// We get the addons folder from relative space (`./`) and then our mod's addons.
|
||||
var addonPaths = [
|
||||
ModsFolder.addonsPath,
|
||||
(
|
||||
ModsFolder.currentModFolder != null ?
|
||||
ModsFolder.modsPath + ModsFolder.currentModFolder + "/addons/" :
|
||||
null
|
||||
// So to check the mod's addons folder, we need to decompress it. Which is impossible* in this stage of the loading library process.
|
||||
// TODO: Write a function when the library is loaded to decompress the contents and then load the libraries :)
|
||||
( (ModsFolder.currentModFolder != null && !isZipMod) ?
|
||||
quick_modsPath + "/addons/" : null
|
||||
)
|
||||
];
|
||||
|
||||
@@ -72,12 +95,8 @@ class MainState extends FlxState {
|
||||
|
||||
for (addon in FileSystem.readDirectory(path)) {
|
||||
if (!FileSystem.isDirectory(path + addon)) {
|
||||
switch(Path.extension(addon).toLowerCase()) {
|
||||
case 'zip':
|
||||
addon = Path.withoutExtension(addon);
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
if (Flags.ALLOWED_ZIP_EXTENSIONS.contains(Path.extension(addon))) addon = Path.withoutExtension(addon);
|
||||
else continue;
|
||||
}
|
||||
|
||||
var data:AddonInfo = {
|
||||
@@ -100,9 +119,14 @@ class MainState extends FlxState {
|
||||
#if MOD_SUPPORT
|
||||
for (addon in _lowPriorityAddons)
|
||||
loadLib(addon.path, ltrim(addon.name, "[LOW]"));
|
||||
|
||||
if (ModsFolder.currentModFolder != null)
|
||||
loadLib(ModsFolder.modsPath + ModsFolder.currentModFolder, ModsFolder.currentModFolder);
|
||||
|
||||
if (ModsFolder.currentModFolder != null) {
|
||||
// isCneMod is a guarentee to be a zip mod because we just checked for it, so this will always load as a CompressedLibrary
|
||||
if (isCneMod)
|
||||
loadLib(quick_modsPath + "/cnemod", ModsFolder.currentModFolder);
|
||||
else
|
||||
loadLib(quick_modsPath, ModsFolder.currentModFolder);
|
||||
}
|
||||
|
||||
for (addon in _noPriorityAddons)
|
||||
loadLib(addon.path, addon.name);
|
||||
@@ -134,9 +158,15 @@ class MainState extends FlxState {
|
||||
CoolUtil.safeAddAttributes('./.temp/', NativeAPI.FileAttribute.HIDDEN);
|
||||
#end
|
||||
|
||||
for (lib in ModsFolder.getLoadedModsLibs()) {
|
||||
if (!(lib is ZipFolderLibrary)) continue;
|
||||
if (cast(lib, ZipFolderLibrary).PRELOAD_VIDEOS) cast(lib, ZipFolderLibrary).precacheVideos();
|
||||
}
|
||||
|
||||
var startState:Class<FlxState> = Flags.DISABLE_WARNING_SCREEN ? TitleState : funkin.menus.WarningState;
|
||||
|
||||
if (Options.devMode && Options.allowConfigWarning) {
|
||||
// In this case if the mod we just loaded a compressed modpack, we can't edit or modify files without decompressing it.
|
||||
if (Options.devMode && Options.allowConfigWarning && !isZipMod) {
|
||||
var lib:ModsFolderLibrary;
|
||||
for (e in Paths.assetsTree.libraries) if ((lib = cast AssetsLibraryList.getCleanLibrary(e)) is ModsFolderLibrary
|
||||
&& lib.modName == ModsFolder.currentModFolder)
|
||||
|
||||
@@ -1,62 +1,14 @@
|
||||
package funkin.backend.system;
|
||||
|
||||
import lime.graphics.Image;
|
||||
import lime.graphics.cairo.CairoImageSurface;
|
||||
import openfl.display.BitmapData;
|
||||
import openfl.geom.Rectangle;
|
||||
|
||||
@:deprecated("Use openfl.display.BitmapData.toHardware instead.")
|
||||
class OptimizedBitmapData extends BitmapData {
|
||||
@SuppressWarnings("checkstyle:Dynamic")
|
||||
@:noCompletion private override function __fromImage(image:#if lime Image #else Dynamic #end):Void
|
||||
{
|
||||
#if lime
|
||||
if (image != null && image.buffer != null)
|
||||
{
|
||||
this.image = image;
|
||||
|
||||
width = image.width;
|
||||
height = image.height;
|
||||
rect = new Rectangle(0, 0, image.width, image.height);
|
||||
|
||||
__textureWidth = width;
|
||||
__textureHeight = height;
|
||||
|
||||
#if sys
|
||||
image.format = BGRA32;
|
||||
image.premultiplied = true;
|
||||
#end
|
||||
|
||||
__isValid = true;
|
||||
readable = true;
|
||||
|
||||
if(FlxG.stage.context3D != null) {
|
||||
lock();
|
||||
getTexture(FlxG.stage.context3D);
|
||||
getSurface();
|
||||
|
||||
readable = true;
|
||||
this.image = null;
|
||||
|
||||
// @:privateAccess
|
||||
// if (FlxG.bitmap.__doNotDelete)
|
||||
// MemoryUtil.clearMinor();
|
||||
}
|
||||
}
|
||||
#end
|
||||
}
|
||||
|
||||
@SuppressWarnings("checkstyle:Dynamic")
|
||||
@:dox(hide) public override function getSurface():#if lime CairoImageSurface #else Dynamic #end
|
||||
{
|
||||
#if lime
|
||||
if (__surface == null)
|
||||
{
|
||||
__surface = CairoImageSurface.fromImage(image);
|
||||
}
|
||||
|
||||
return __surface;
|
||||
#else
|
||||
return null;
|
||||
#end
|
||||
super.__fromImage(image);
|
||||
toHardware();
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,12 @@ class RotatingSpriteGroup extends FlxSpriteGroup {
|
||||
if (maxSize <= 0)
|
||||
return super.recycle(ObjectClass, ObjectFactory, Force, Revive);
|
||||
if (group.members.length < maxSize)
|
||||
return group.recycleCreateObject(ObjectClass, ObjectFactory);
|
||||
{
|
||||
if (ObjectFactory != null) return add(ObjectFactory());
|
||||
if (ObjectClass != null) return add(Type.createInstance(ObjectClass, []));
|
||||
|
||||
return null;
|
||||
}
|
||||
var spr = group.members.shift();
|
||||
group.members.push(spr);
|
||||
if (Revive)
|
||||
|
||||
@@ -8,12 +8,20 @@ import funkin.backend.assets.IModsAssetLibrary;
|
||||
import funkin.backend.assets.ScriptedAssetLibrary;
|
||||
|
||||
class AssetTreeInfo extends FramerateCategory {
|
||||
private var lastUpdateTime:Float = 1;
|
||||
|
||||
public function new() {
|
||||
super("Asset Libraries Tree Info");
|
||||
}
|
||||
|
||||
public override function __enterFrame(t:Int) {
|
||||
public override function __enterFrame(t:Float) {
|
||||
if (alpha <= 0.05) return;
|
||||
|
||||
if ((lastUpdateTime += FlxG.rawElapsed) < 1)
|
||||
return;
|
||||
|
||||
lastUpdateTime = 0;
|
||||
|
||||
var text = 'Not initialized yet\n';
|
||||
if (Paths.assetsTree != null){
|
||||
text = "";
|
||||
|
||||
@@ -6,15 +6,23 @@ import openfl.text.TextField;
|
||||
class CodenameBuildField extends TextField {
|
||||
public function new() {
|
||||
super();
|
||||
defaultTextFormat = Framerate.textFormat;
|
||||
autoSize = LEFT;
|
||||
multiline = wordWrap = false;
|
||||
reload();
|
||||
}
|
||||
|
||||
public function reload() {
|
||||
defaultTextFormat = Framerate.textFormat;
|
||||
|
||||
#if TEST_BUILD
|
||||
text = '${Flags.VERSION_MESSAGE} (Test Build)';
|
||||
#elseif COMPILE_EXPERIMENTAL
|
||||
text = '${Flags.VERSION_MESSAGE} (Experimental Build)';
|
||||
#else
|
||||
text = '${Flags.VERSION_MESSAGE}';
|
||||
#if debug
|
||||
#end
|
||||
|
||||
#if (debug || COMPILE_EXPERIMENTAL)
|
||||
text += '\n${Flags.COMMIT_MESSAGE}';
|
||||
#end
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ class ConductorInfo extends FramerateCategory {
|
||||
super("Conductor Info");
|
||||
}
|
||||
|
||||
public override function __enterFrame(t:Int) {
|
||||
public override function __enterFrame(t:Float) {
|
||||
if (alpha <= 0.05) return;
|
||||
_text = 'Current Song Position: ${Math.floor(Conductor.songPosition * 1000) / 1000}';
|
||||
_text += '\n - ${Conductor.curBeat} beats';
|
||||
|
||||
@@ -7,7 +7,7 @@ class FlixelInfo extends FramerateCategory {
|
||||
super("Flixel Info");
|
||||
}
|
||||
|
||||
public override function __enterFrame(t:Int) {
|
||||
public override function __enterFrame(t:Float) {
|
||||
if (alpha <= 0.05) return;
|
||||
|
||||
|
||||
|
||||