Author SHA1 Message Date
Furo e540cb454b Changes project.xml to project.hxp 2025-10-20 20:17:45 +02:00
204 changed files with 242548 additions and 29114 deletions
+1 -4
View File
@@ -37,7 +37,4 @@ f8b20774e3f035eeddb9211a28a391b20db74456
# Revert a revert (scripted cutscene path)
d73f86d26ec2dbf031c01f588ba4be11842db09c
fe0ab0aa454f4ae12ced9502db8a01e7bca3e04c
# Forgot the # in the commit message
484bbcb22aa8f28b62912abb6d8c89fb58e63889
fe0ab0aa454f4ae12ced9502db8a01e7bca3e04c
+3 -2
View File
@@ -5,9 +5,10 @@
pages/** linguist-vendored
# Include HScript files as Haxe
*.hxs linguist-language=Haxe
*.hsc linguist-language=Haxe
*.hscript linguist-language=Haxe
*.hsc linguist-language=Haxe
*.hxs linguist-language=Haxe
*.hxp linguist-language=Haxe
# Include Shader files as GLSL
*.frag linguist-language=GLSL
+45 -113
View File
@@ -1,33 +1,31 @@
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 new commit
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Pulling the source
uses: actions/checkout@v2
- 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@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: 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: Installing LibVLC
run: |
sudo apt-get install libvlc-dev libvlccore-dev
@@ -36,112 +34,46 @@ jobs:
haxe -cp commandline -D analyzer-optimize --run Main setup -s
- name: Building the game
run: |
haxelib run lime rebuild linux -nocolor -nocffi -release
haxelib run lime build linux -DCOMPILE_EXPERIMENTAL
haxelib run lime build linux
# - name: Tar files
# run: tar -zcvf CodenameEngine.tar.gz -C export/release/linux/bin .
- name: Uploading artifact (executable)
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@v4
with:
name: Codename Engine (Executable Only)
path: export/release/linux/bin/CodenameEngine
- name: Uploading artifact (entire build)
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@v4
with:
name: Codename Engine
path: export/release/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") {
# 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
- name: Clearing already existing cache
uses: actions/github-script@v6
with:
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
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
with:
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/
# 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
+45 -110
View File
@@ -1,141 +1,76 @@
name: Mac OS Builds
name: Mac OS Build
on:
push:
workflow_dispatch:
jobs:
build:
name: Mac OS Build
permissions: write-all
runs-on: macos-26
runs-on: macos-13
steps:
- name: Pulling the new commit
uses: actions/checkout@v6
with:
fetch-depth: 0
uses: actions/checkout@v2
- 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@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: 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: 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 -release
haxelib run lime build mac -DCOMPILE_EXPERIMENTAL
haxelib run lime build mac
- name: Tar files
run: tar -zcvf CodenameEngine.tar.gz -C export/release/macos/bin .
- name: Uploading artifact (executable)
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@v4
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@v7
uses: actions/upload-artifact@v4
with:
name: Codename Engine
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") {
# 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
- name: Clearing already existing cache
uses: actions/github-script@v6
with:
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
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
with:
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/
# 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
+8 -10
View File
@@ -21,12 +21,10 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v6
with:
fetch-depth: 0
uses: actions/checkout@v4
- name: Download Windows Full Build
uses: dawidd6/action-download-artifact@v8
uses: dawidd6/action-download-artifact@v6
with:
workflow: windows.yml
name: Codename Engine
@@ -34,7 +32,7 @@ jobs:
allow_forks: false
- name: Download Windows Executable
uses: dawidd6/action-download-artifact@v8
uses: dawidd6/action-download-artifact@v6
with:
workflow: windows.yml
name: Codename Engine (Executable Only)
@@ -42,7 +40,7 @@ jobs:
allow_forks: false
- name: Download Mac OS Full Build
uses: dawidd6/action-download-artifact@v8
uses: dawidd6/action-download-artifact@v6
with:
workflow: macos.yml
name: Codename Engine
@@ -50,7 +48,7 @@ jobs:
allow_forks: false
- name: Download Mac OS Executable
uses: dawidd6/action-download-artifact@v8
uses: dawidd6/action-download-artifact@v6
with:
workflow: macos.yml
name: Codename Engine (Executable Only)
@@ -58,7 +56,7 @@ jobs:
allow_forks: false
- name: Download Linux Full Build
uses: dawidd6/action-download-artifact@v8
uses: dawidd6/action-download-artifact@v6
with:
workflow: linux.yml
name: Codename Engine
@@ -66,7 +64,7 @@ jobs:
allow_forks: false
- name: Download Linux Executable
uses: dawidd6/action-download-artifact@v8
uses: dawidd6/action-download-artifact@v6
with:
workflow: linux.yml
name: Codename Engine (Executable Only)
@@ -186,7 +184,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
+45 -111
View File
@@ -1,9 +1,8 @@
name: Windows Builds
name: Windows Build
on:
push:
workflow_dispatch:
jobs:
build:
name: Windows Build
@@ -11,130 +10,65 @@ jobs:
runs-on: windows-latest
steps:
- name: Pulling the new commit
uses: actions/checkout@v6
with:
fetch-depth: 0
uses: actions/checkout@v2
- 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@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: 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: 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 -release
haxelib run lime build windows -DCOMPILE_EXPERIMENTAL
haxelib run lime build windows
- name: Uploading artifact (executable)
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@v4
with:
name: Codename Engine (Executable Only)
path: |
export/release/windows/bin/CodenameEngine.exe
export/release/windows/bin/lime.ndll
path: export/release/windows/bin/CodenameEngine.exe
- name: Uploading artifact (entire build)
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@v4
with:
name: Codename Engine
path: export/release/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") {
# 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
- name: Clearing already existing cache
uses: actions/github-script@v6
with:
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
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
with:
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/
# 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
+4 -1
View File
@@ -1,12 +1,15 @@
{
"editor.detectIndentation": false,
"editor.insertSpaces": false,
"editor.tabSize": 4,
"files.associations": {
"*.hx": "haxe",
"*.hscript": "haxe",
"*.hsc": "haxe",
"*.hxs": "haxe"
"*.hxs": "haxe",
"*.hxp": "haxe"
},
"lime.projectFile": "project.hxp",
"lime.targetConfigurations": [
{
"label": "Windows (Test Build)",
+1 -1
View File
@@ -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!
+2 -2
View File
@@ -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 Universal** and **Linux x64**.<br>
> Codename Engine as for now supports **Windows x64**, **Mac OS x64** 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 the engine and its documentation</h2></summary>
<summary><h2>How to setup and build</h2></summary>
Check out our guide [HERE](building/README.md)
</details>
+10
View File
@@ -0,0 +1,10 @@
## 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.
+8
View File
@@ -0,0 +1,8 @@
@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
+7
View File
@@ -2,6 +2,13 @@
<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>
+12 -12
View File
@@ -1,14 +1,14 @@
<!DOCTYPE codename-engine-character>
<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 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>
+1 -1
View File
@@ -75,7 +75,7 @@ function onCountdown(event) {
};
}
function onRatingsShown(event:RatingsShowEvent) {
function onPlayerHit(event:NoteHitEvent) {
if (!enablePixelUI) return;
event.ratingPrefix = "stages/school/ui/";
event.ratingScale = daPixelZoom * 0.7;
+1 -1
View File
@@ -11,7 +11,7 @@
<sprite name="fgSnow" x="-600" y="680" sprite="fgSnow"/>
<girlfriend x="440" y="110"/>
<girlfriend x="540" y="110"/>
<dad/>
<boyfriend x="1030" camyoffset="-150" camxoffset="-150"/>
File diff suppressed because it is too large Load Diff
+27 -27
View File
@@ -1,28 +1,28 @@
{"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"
{"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"
}
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 134 KiB

After

Width:  |  Height:  |  Size: 74 KiB

File diff suppressed because it is too large Load Diff
@@ -1,40 +1,58 @@
{"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"
{"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"
}
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 453 KiB

After

Width:  |  Height:  |  Size: 228 KiB

File diff suppressed because it is too large Load Diff
+56 -54
View File
@@ -1,55 +1,57 @@
{"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"
{"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"
}
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 265 KiB

After

Width:  |  Height:  |  Size: 165 KiB

File diff suppressed because it is too large Load Diff
@@ -1,60 +1,60 @@
{"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"
{"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"
}
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 535 KiB

After

Width:  |  Height:  |  Size: 344 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 804 B

File diff suppressed because it is too large Load Diff
@@ -1,241 +1,145 @@
{"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"
{"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"
}
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 642 KiB

+3 -11
View File
@@ -203,7 +203,6 @@
<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>
@@ -224,7 +223,6 @@
<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>
@@ -238,9 +236,8 @@
<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="inst">Instrumental</str>
<str id="voices">Voices</str>
<str id="hitsounds">Hitsounds</str>
<str id="muteInst">Mute instrumental</str>
<str id="muteVoices">Mute voices</str>
</group>
<group name="BookmarkMenu" prefix="bookmarks.">
@@ -253,7 +250,6 @@
<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>
@@ -262,7 +258,6 @@
<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>
@@ -313,9 +308,8 @@
<group name="StrumlineOptions" prefix="strumLine.">
<str id="button-name">Options ↓</str>
<str id="waveforms">Waveforms</str>
<str id="hitsounds">Hitsounds</str>
<str id="vocals">Vocals</str>
<str id="muteVocals">Mute Vocals</str>
<str id="edit">Edit</str>
<str id="delete">Delete</str>
@@ -439,8 +433,6 @@
<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.">
-1
View File
@@ -48,7 +48,6 @@
<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>
+1 -2
View File
@@ -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,7 +188,6 @@
<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>
+1 -2
View File
@@ -46,9 +46,8 @@
<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>
-1
View File
@@ -194,7 +194,6 @@
<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>
-1
View File
@@ -46,7 +46,6 @@
<group name="engine" prefix="engine.">
<str id="switchMod">Cambia Mod</str>
<str id="fpsCounter">Contatore FPS</str>
</group>
<str id="volume.up">Su</str>
+3 -4
View File
@@ -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,7 +197,6 @@
<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>
@@ -224,7 +223,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>
+1 -2
View File
@@ -44,9 +44,8 @@
<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>
-1
View File
@@ -203,7 +203,6 @@
<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>
-1
View File
@@ -48,7 +48,6 @@
<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>
+2 -16
View File
@@ -1,5 +1,6 @@
#pragma header
#version 120 // this shader doesnt require expensive calculations
// Used in charter by waveforms
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);
@@ -17,21 +18,6 @@ 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);
+2 -2
View File
@@ -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.addAnim('tank', 'TANK TALK 2', 0, false);
tankman.animateAtlas.anim.addBySymbol('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});
}
}
+9 -13
View File
@@ -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.addAnim('p1', 'TANK TALK 3 P1 UNCUT', 0, false);
tankman.addAnim('p2', 'TANK TALK 3 P2 UNCUT', 0, false);
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.playAnim('p1');
pico = new FunkinSprite(game.gf.x + game.gf.globalOffset.x - 615, game.gf.y + game.gf.globalOffset.y - 130);
pico = new FunkinSprite(game.gf.x + game.gf.globalOffset.x + 150, game.gf.y + game.gf.globalOffset.y + 395);
pico.antialiasing = true;
pico.loadSprite(Paths.image('game/cutscenes/tank/stress-pico'));
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.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.scrollFactor.set(0.95, 0.95);
pico.playAnim("idle");
pico.visible = false;
game.insert(game.members.indexOf(game.gf) + 2, pico);
game.insert(game.members.indexOf(game.gf) + 1, pico);
game.insert(game.members.indexOf(game.dad) + 1, tankman);
game.dad.visible = false;
@@ -59,11 +59,7 @@ function update(elapsed) {
lipSync(tankman, 0, 16750);
if (stressCutscene.time > 15100) {
step = 1;
//focusOn(game.gf);
game.camFollow.x += 350;
game.camFollow.y -= 200;
focusOn(game.gf);
pico.visible = true;
pico.playAnim('die', true);
@@ -122,7 +118,7 @@ function update(elapsed) {
}
function lipSync(char:FunkinSprite, begin:Float, end:Float) {
char.anim.curAnim.curFrame = Std.int(FlxMath.remapToRange(stressCutscene.time, begin, end, 0, char.anim.curAnim.numFrames - 1));
char.animateAtlas.anim.curFrame = Std.int(FlxMath.remapToRange(stressCutscene.time, begin, end, 0, char.animateAtlas.anim.length-1));
}
function focusOn(char, snap:Bool = false) {
+3 -3
View File
@@ -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.addAnim('1', 'TANK TALK 1 P1', 0, false);
tankman.addAnim('2', 'TANK TALK 1 P2', 0, false);
tankman.animateAtlas.anim.addBySymbol('1', 'TANK TALK 1 P1', 0, false);
tankman.animateAtlas.anim.addBySymbol('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();
}
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+3 -22
View File
@@ -1,6 +1,6 @@
# 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.**
Here's the full guide on how to setup and compile Codename Engine!<br>
> **Open the instructions for your platform**
<details>
<summary>Windows</summary>
@@ -38,22 +38,3 @@ Do you want to turn your source code into a playable build to play? Then you wan
> 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.
+14
View File
@@ -0,0 +1,14 @@
[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
-13
View File
@@ -1,13 +0,0 @@
#!/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."
-8
View File
@@ -1,8 +0,0 @@
@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.
+28 -26
View File
@@ -3,32 +3,35 @@
<if cond="update || all">
<print pretty="true">Preparing installation...</print>
<!-- 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"/>
<!-- OpenFL & Lime (Required for Flixel) -->
<git name="openfl" url="https://github.com/CodenameCrew/cne-openfl" />
<lib name="lime" version="8.2.0" />
<!-- <git name="lime" url="https://github.com/CodenameCrew/cne-lime" /> disabled for now until fixed -->
<!-- Flixel -->
<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"/>
<git name="flixel" url="https://github.com/CodenameCrew/cne-flixel" />
<git name="flixel-addons" url="https://github.com/CodenameCrew/cne-flixel-addons" />
<!-- Other Libraries -->
<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"/>
<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" />
<!-- For building lime -->
<!-- <lib global="true" name="hxp"/> <lib name="hxp"/> -->
<!-- <lib global="true" name="format"/> <lib name="format"/> -->
<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" />
</if>
<!-- Hxcpp Building -->
@@ -37,16 +40,15 @@
<!-- 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">
<!-- <if cond="build-lime || all">
<print pretty="true">Rebuilding Lime...</print>
<!-- Build lime -->
<cmd inLib="lime" dir="tools" cmd="haxe tools.hxml"/>
<cmd inLib="lime" cmd="haxelib run lime rebuild $PLATFORM -nocolor -nocffi -release"/>
</if>
<!- - Build lime - ->
<cmd inLib="lime" cmd="haxelib run lime rebuild . $PLATFORM -release -clean" />
<cmd inLib="lime" dir="tools" cmd="haxe tools.hxml" />
</if> -->
</libraries>
+237
View File
@@ -0,0 +1,237 @@
<?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" />
<!--
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" />
<!-- DO NOT REMOVE!! ALLOWS ME TO DO REGIONS LIKE IN C# AND KEEP CODE ORGANIZED. REMOVING IT WOULD BREAK THE ENGINE -->
<haxedef name="REGION" />
<!--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" />
<!--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"/>
</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" />
<!-- 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" />
<!-- 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" />
<!-- Comment this out to disable multithreading !-->
<haxedef name="ALLOW_MULTITHREADING" unless="web || flash" />
<!-- Comment this out to disable mods folder !-->
<haxedef name="MOD_SUPPORT" unless="web"/>
<!-- Comment this out to disable translations folders !-->
<haxedef name="TRANSLATIONS_SUPPORT"/>
<!-- Comment this out to disable global scripts !-->
<haxedef name="GLOBAL_SCRIPT" />
<!-- Comment this out to disable softcoded states and state scripting !-->
<haxedef name="SOFTCODED_STATES" />
<!-- Comment this out to disable support for custom ndlls. !-->
<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" />
<!-- Comment this out to disable support for Away3D Flixel Integration (reduces compile times) !-->
<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"/>
<!-- Disable a optimization, to allow reflection to use more functions -->
<define name="FLX_NO_GENERIC" />
<!-- _______________________________ Libraries ______________________________ -->
<!-- KEEP BOTH OF THESE AS THERE ARE SOME PARTICULAR CASES! -->
<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-addons" />
<haxelib name="hxvlc" if="VIDEO_CUTSCENES" />
<haxelib name="away3d" if="THREE_D_SUPPORT" />
<haxelib name="format" />
<haxelib name="flxanimate" />
<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" />
<!-- _____________________________ Path 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" />
<source name="source" />
<define name="PRELOAD_ALL" unless="web" />
<define name="NO_PRELOAD_ALL" unless="PRELOAD_ALL"/>
<library name="assets" preload="true" if="PRELOAD_ALL"/>
<library name="assets" preload="false" if="NO_PRELOAD_ALL" />
<section unless="TEST_BUILD">
<assets path="assets/" rename="assets" exclude="*.ogg" if="web"/>
<assets path="assets/" rename="assets" exclude="*.mp3" unless="web"/>
<!-- TODO: make it copy this manually, instead of using assets node, so it doesn't manually check for fonts -->
<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>
<!-- ______________________________ Haxedefines _____________________________ -->
<haxedef name="FLX_NO_FOCUS_LOST_SCREEN" />
<!--Disable the Flixel core debugger. Automatically gets set whenever you compile in release mode!-->
<haxedef name="FLX_NO_DEBUG" unless="debug" />
<haxedef name="analyzer-optimize" 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" />
<!-- _________________________________ 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()" />
<!-- 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" />
<haxedef name="hscriptPos" /> <!-- for logging -->
<!-- EXPERMENTAL FEATURES -->
<haxedef name="EXPERIMENTAL_FLXGRAPHIC_DESTROY_FIX" />
</project>
+494
View File
@@ -0,0 +1,494 @@
// funkin source classes cannot be imported here
import haxe.io.Path;
import hxp.*;
import lime.tools.*;
import sys.FileSystem;
import sys.io.Process;
using StringTools;
class Project extends HXProject
{
static final TITLE:String = "Friday Night Funkin' - Codename Engine";
static final EXECUTABLE:String = "CodenameEngine";
static final VERSION:String = "1.0.1";
static final COMPANY:String = "Yoshman29";
static final PACKAGE:String = "com.codenamecrew.codenameengine";
static final MAIN_CLASS:String = "funkin.backend.system.MainApplication";
static final PRELOADER:String = "flixel.system.FlxPreloader";
static final SOURCE_FOLDERS:Array<String> = ["source"];
// Compile Flags
static final EMBED_ASSETS:CompileFlag = CompileFlag.get("EMBED_ASSETS");
static final PRELOAD_ALL:CompileFlag = CompileFlag.get("PRELOAD_ALL");
static final STRIPPED_COMPILE:CompileFlag = CompileFlag.get("STRIPPED_COMPILE");
static final UPDATE_CHECKING:CompileFlag = CompileFlag.get("UPDATE_CHECKING");
static final DISCORD_RPC:CompileFlag = CompileFlag.get("DISCORD_RPC");
static final MODCHARTING_FEATURES:CompileFlag = CompileFlag.get("MODCHARTING_FEATURES");
static final GITHUB_API:CompileFlag = CompileFlag.get("GITHUB_API");
static final COMPILE_ALL_CLASSES:CompileFlag = CompileFlag.get("COMPILE_ALL_CLASSES");
static final CUSTOM_CLASSES:CompileFlag = CompileFlag.get("CUSTOM_CLASSES");
static final ALLOW_MULTITHREADING:CompileFlag = CompileFlag.get("ALLOW_MULTITHREADING");
static final MOD_SUPPORT:CompileFlag = CompileFlag.get("MOD_SUPPORT");
static final TRANSLATIONS_SUPPORT:CompileFlag = CompileFlag.get("TRANSLATIONS_SUPPORT");
static final GLOBAL_SCRIPT:CompileFlag = CompileFlag.get("GLOBAL_SCRIPT");
static final SOFTCODED_STATES:CompileFlag = CompileFlag.get("SOFTCODED_STATES");
static final NDLLS_SUPPORTED:CompileFlag = CompileFlag.get("NDLLS_SUPPORTED");
static final USE_ADAPTED_ASSETS:CompileFlag = CompileFlag.get("USE_ADAPTED_ASSETS");
static final THREE_D_SUPPORT:CompileFlag = CompileFlag.get("THREE_D_SUPPORT");
static final NAPE_ENABLED:CompileFlag = CompileFlag.get("NAPE_ENABLED");
static final VIDEO_CUTSCENES:CompileFlag = CompileFlag.get("VIDEO_CUTSCENES");
static final SHOW_BUILD_ON_FPS:CompileFlag = CompileFlag.get("SHOW_BUILD_ON_FPS");
static final DARK_MODE_WINDOW:CompileFlag = CompileFlag.get("DARK_MODE_WINDOW");
public function new():Void
{
super();
CompileFlag.project = this;
haxe.Log.trace = (v:Dynamic, ?info:haxe.PosInfos) ->
{
if (!isDisplay())
Sys.println(v);
};
doWelcomeHeader();
trace("Configuring project...");
trace("");
configureApp();
configureCompileFlags();
configureAssets();
configureLibs();
configureIcons();
trace("");
trace("Configured project");
trace("Starting build...");
trace("");
}
function getHaxeVersion():String {
var process = new Process("haxe", ["-version"]);
var version:String = "";
try {
version = process.stdout.readAll().toString().trim();
} catch (e) {}
process.close();
return version;
}
function doWelcomeHeader() {
var haxeVersion = getHaxeVersion().trim();
var sleepChangeVersion = false;
var width = 60; // total banner width
inline function centerText(text:String, width:Int):String {
var innerWidth = width - 2;
var padding = Std.int(Math.max(0, Std.int((innerWidth - text.length) / 2)));
var left = StringTools.lpad("", " ", padding);
var right = StringTools.lpad("", " ", innerWidth - text.length - padding);
return "=" + left + text + right + "=";
}
inline function infoLine(label:String, value:String):String {
var innerWidth = width - 2;
if (label.length == 0) {
// no label: center the value
var padding = Std.int(Math.max(0, (innerWidth - value.length) / 2));
var left = StringTools.lpad("", " ", padding);
var right = StringTools.lpad("", " ", innerWidth - value.length - padding);
return "=" + left + value + right + "=";
} else {
var colonPos = Std.int(innerWidth / 2);
var labelPart = StringTools.lpad(label, " ", Std.int(Math.max(0, colonPos - 2)));
var valuePart = value;
var remainingSpace = Std.int(Math.max(0, innerWidth - (labelPart.length + 3 + valuePart.length)));
var rightPad = StringTools.lpad("", " ", remainingSpace);
return "=" + labelPart + " : " + valuePart + rightPad + "=";
}
}
var unicode = #if (target.unicode) true #else false #end;
trace('');
trace(StringTools.lpad("", "=", width));
trace(centerText(TITLE, width));
trace(StringTools.lpad("", "=", width));
trace(infoLine("Engine Version", 'v${VERSION}'));
trace(infoLine("Haxe Version", 'v${haxeVersion}'));
trace(StringTools.lpad("", "=", width));
try {
var lastBuiltWith:Null<String> = null;
var compiling = isDebug() ? "debug" : "release";
var target = isWeb() ? "html5" : (isIOS() ? "ios" : (isAndroid() ? "android" : (isWindows() ? "windows" : (isMac() ? "macos" : (isLinux() ? "linux" : "")))));
if (target == "") throw "Unknown target";
var exportPath = Sys.getCwd() + "/export/" + compiling + "/" + target + "/obj/Options.txt";
var options = sys.io.File.getContent(exportPath);
for (option in options.split("\n")) {
if (option.startsWith("haxe=")) {
lastBuiltWith = option.substr(5).trim();
break;
}
}
if (lastBuiltWith != null && lastBuiltWith.length > 0 && lastBuiltWith != haxeVersion) {
trace(infoLine("", unicode ? "⚠️ Haxe version mismatch!" : "[WARNING] Haxe version mismatch!"));
trace(infoLine("Last Built With", lastBuiltWith));
trace(infoLine("Current Version", haxeVersion));
trace(StringTools.lpad("", "=", width));
trace(infoLine("", "!!! Make sure to DELETE your EXPORT folders !!!"));
trace(StringTools.lpad("", "=", width));
sleepChangeVersion = true;
}
} catch (e) {}
var targetPlatform = isWeb() ? "Web (HTML5)" : (isIOS() ? "iOS" : (isAndroid() ? "Android" : (isWindows() ? "Windows" : (isMac() ? "Mac" : (isLinux() ? "Linux" : "Unknown")))));
if (isHashLink())
targetPlatform = "Hashlink (" + targetPlatform + ")";
trace(infoLine("Target Platform", targetPlatform));
trace(infoLine("Build Type", isDebug() ? "Debug" : "Release"));
trace(infoLine("Build Date", Date.now().toString()));
trace(StringTools.lpad("", "=", width));
trace('');
if (sleepChangeVersion)
Sys.sleep(5);
}
function configureApp():Void
{
trace("Configuring game...");
meta.title = TITLE;
meta.version = VERSION;
meta.company = COMPANY;
meta.packageName = PACKAGE;
app.main = MAIN_CLASS;
app.file = EXECUTABLE;
app.preloader = PRELOADER;
var buildDir = 'export/${isDebug() ? 'debug' : 'release'}/';
trace('Output directory: $buildDir');
app.path = buildDir;
sources = SOURCE_FOLDERS;
templatePaths.push(Path.combine(Haxelib.getPath(new Haxelib(#if lime "lime" #else "hxp" #end)), #if lime "templates" #else "" #end));
window.hardware = true;
window.vsync = false;
window.allowHighDPI = true;
if (isWeb())
window.resizable = true;
if (isDesktop())
{
window.orientation = Orientation.LANDSCAPE;
window.fullscreen = false;
window.resizable = true;
window.vsync = false;
} else if (isMobile())
{
window.orientation = Orientation.LANDSCAPE;
window.fullscreen = true;
window.resizable = false;
window.borderless = true;
window.width = 0;
window.height = 0;
}
}
function configureCompileFlags()
{
trace("Configuring compile flags...");
setDefine("disable-version-check");
setHaxedef("disable-version-check");
setHaxedef("no-deprecation-warnings");
// DO NOT REMOVE!! ALLOWS ME TO DO REGIONS LIKE IN C# AND KEEP CODE ORGANIZED. REMOVING IT WOULD BREAK THE ENGINE
setHaxedef("REGION");
setHaxedef("SAVE_PATH", EXECUTABLE);
setHaxedef("SAVE_NAME", "save-default");
setHaxedef("SAVE_OPTIONS_PATH", EXECUTABLE);
setHaxedef("SAVE_OPTIONS_NAME", "options");
PRELOAD_ALL.integrate(!isWeb());
EMBED_ASSETS.integrate(false);
UPDATE_CHECKING.integrate(!isWeb() && !isHashLink());
DISCORD_RPC.integrate(isCPP() && isDesktop());
STRIPPED_COMPILE.integrate(false); //should be isRelease() if you want to use it
MODCHARTING_FEATURES.integrate(STRIPPED_COMPILE.isDisabled());
GITHUB_API.integrate(!isWeb() && !isHashLink());
COMPILE_ALL_CLASSES.integrate(STRIPPED_COMPILE.isDisabled());
CUSTOM_CLASSES.integrate(STRIPPED_COMPILE.isDisabled());
ALLOW_MULTITHREADING.integrate(!isWeb());
MOD_SUPPORT.integrate(!isWeb());
TRANSLATIONS_SUPPORT.integrate(true);
GLOBAL_SCRIPT.integrate(true);
SOFTCODED_STATES.integrate(true);
NDLLS_SUPPORTED.integrate(!isWeb() && !isHashLink());
USE_ADAPTED_ASSETS.integrate(!isWeb());
THREE_D_SUPPORT.integrate(STRIPPED_COMPILE.isDisabled());
NAPE_ENABLED.integrate(STRIPPED_COMPILE.isDisabled());
VIDEO_CUTSCENES.integrate(isCPP() && (isDesktop() || isMobile()));
SHOW_BUILD_ON_FPS.integrate(true);
DARK_MODE_WINDOW.integrate(true);
setDefine("FLX_NO_GENERIC"); // Disable a optimization, to allow reflection to use more functions
if (DISCORD_RPC.isEnabled())
setHaxedef("DISCORD_DISABLE_IO_THREAD");
if (MODCHARTING_FEATURES.isEnabled())
{
setHaxedef("FM_ENGINE", "CODENAME");
setHaxedef("FM_ENGINE_VERSION", "1.0");
addMacroFlag("modchart.backend.macros.Macro.includeFiles()");
}
if (COMPILE_ALL_CLASSES.isEnabled())
{
addHaxeFlag("-dce no");
addMacroFlag("funkin.backend.system.macros.Macros.addAdditionalClasses()");
}
addMacroFlag("funkin.backend.system.macros.Macros.initMacros()");
if (isDebug())
setHaxedef("HXCPP_DEBUG_LINK");
environment.set("HAXEPATH", "./");
setHaxedef("HXCPP_CHECK_POINTER");
setHaxedef("HXCPP_STACK_LINE");
setHaxedef("HXCPP_CATCH_SEGV");
setHaxedef("hscriptPos");
setHaxedef("EXPERIMENTAL_FLXGRAPHIC_DESTROY_FIX");
setHaxedef("FLX_NO_FOCUS_LOST_SCREEN");
if (isRelease())
{
setHaxedef("FLX_NO_DEBUG");
setHaxedef("analyzer-optimize");
}
setHaxedef("openfl_dpi_aware");
}
function configureAssets()
{
trace("Configuring assets...");
var shouldPreload = PRELOAD_ALL.isEnabled();
var shouldEmbed = EMBED_ASSETS.isEnabled();
includeAssetLibrary("default", shouldEmbed, shouldPreload);
addAssetPath("assets", shouldEmbed);
addAsset("art/readme.txt", "do NOT readme.txt", false);
if (isDesktop())
addAsset("building/alsoft.txt", 'plugins/alsoft.${isWindows() ? "ini" : "conf"}', false);
}
function configureLibs()
{
trace("Configuring libraries...");
includeHaxelib("flixel");
includeHaxelib("flixel-addons");
includeHaxelib("format");
includeHaxelib("flxanimate");
includeHaxelib("hscript-improved");
includeHaxelib("markdown");
if (VIDEO_CUTSCENES.isEnabled())
includeHaxelib("hxvlc");
if (THREE_D_SUPPORT.isEnabled())
includeHaxelib("away3d");
if (NAPE_ENABLED.isEnabled())
includeHaxelib("nape-haxe4");
if (DISCORD_RPC.isEnabled())
includeHaxelib("hxdiscord_rpc");
if (MODCHARTING_FEATURES.isEnabled())
includeHaxelib("funkin-modchart");
if (isDebug())
includeHaxelib("hxcpp-debug-server");
}
function configureIcons()
{
trace("Configuring app icons...");
// TODO: ADD MOBILE ICONS
for (size in [16, 32, 64])
addIcon('art/icon${size}.png', size);
addIcon("art/icons/iconOG.png");
}
function includeHaxelib(name:String, version:String = ""):Void
{
haxelibs.push(new Haxelib(name, version));
}
function addAsset(path:String, ?rename:String, embed:Bool = false):Void
{
var asset = new Asset(path, rename, null, embed, true);
asset.library = "default";
assets.push(asset);
}
public function addAssetPath(path:String, ?rename:String, embed:Bool = false):Void
{
if (path == "") return;
var targetPath = Path.addTrailingSlash(rename ?? path);
if (!FileSystem.exists(path))
trace('[ERROR] Path "${path}" was not found');
else if (!FileSystem.isDirectory(path))
trace('[ERROR] Path "${path}" needs to be a directory.');
for (file in FileSystem.readDirectory(path))
{
if (FileSystem.isDirectory('${path}/${file}'))
addAssetPath('${path}/${file}', '${targetPath}${file}', embed);
else
addAsset('${path}/${file}', '${targetPath}${file}', embed);
}
}
function includeAssetLibrary(name:String, embed:Bool = false, preload:Bool = false):Void
{
this.libraries.push(new Library('', name, null, embed, preload, false, ""));
}
inline function addIcon(icon:String, ?size:Int):Void
icons.push(new Icon(icon, size));
inline function addHaxeFlag(value:String):Void
haxeflags.push(value);
inline function addMacroFlag(value:String):Void
addHaxeFlag('--macro ${value}');
inline function isDebug():Bool
return debug;
inline function isRelease():Bool
return !isDebug();
inline function isDisplay():Bool
return command == "display";
inline function isWeb():Bool
return platformType == PlatformType.WEB;
inline function isMobile():Bool
return platformType == PlatformType.MOBILE;
inline function isDesktop():Bool
return platformType == PlatformType.DESKTOP;
inline function isWindows():Bool
return target == Platform.WINDOWS;
inline function isMac():Bool
return target == Platform.MAC;
inline function isLinux():Bool
return target == Platform.LINUX;
inline function isAndroid():Bool
return target == Platform.ANDROID;
inline function isIOS():Bool
return target == Platform.IOS;
inline function isHashLink():Bool
return targetFlags.exists("hl");
inline function isCPP():Bool
return defines.exists("cpp");
public inline function getHaxedef(name:String):Null<Dynamic>
return haxedefs.get(name);
public inline function setHaxedef(name:String, ?value:String):Void
haxedefs.set(name, value ?? "");
public inline function unsetHaxedef(name:String):Void
haxedefs.remove(name);
public inline function getDefine(name:String):Null<Dynamic>
return defines.get(name);
public inline function setDefine(name:String, ?value:String):Void
defines.set(name, value ?? "");
public inline function unsetDefine(name:String):Void
defines.remove(name);
}
class CompileFlag {
public static final INVERSION:String = "NO_";
public static var project:Project;
public static function get(name:String):CompileFlag {
return new CompileFlag(name);
}
var name:String;
public function new(name:String) {
this.name = name;
}
public function enable(stopPropagation:Bool = false):Void
{
project.setHaxedef(name);
project.setDefine(name);
if (!stopPropagation)
getInverse().disable(true);
}
public function disable(stopPropagation:Bool = false):Void
{
project.unsetHaxedef(name);
project.unsetDefine(name);
if (!stopPropagation)
getInverse().enable(true);
}
public function integrate(defaultEnabled:Bool = false):Void {
var inverse = getInverse();
if (isEnabled()) inverse.disable(true); // Makes sure the inverse is disabled if it wasn't already
else if (inverse.isEnabled()) disable(true); // If the inverse is enabled, disable this
else (defaultEnabled ? enable : disable)(true); // Set to the default state otherwise
}
public function isEnabled():Bool {
return project.haxedefs.exists(name) || project.defines.exists(name);
}
public function isDisabled():Bool {
return getInverse().isEnabled() || !isEnabled();
}
function getInverse():CompileFlag {
var inversionName = name;
if (!inversionName.startsWith(INVERSION))
inversionName = INVERSION + inversionName;
return new CompileFlag(inversionName);
}
}
-241
View File
@@ -1,241 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<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! -->
<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"/>
<!-- 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"/>
<!-- Should it checks for updates? -->
<define name="UPDATE_CHECKING" if="desktop" unless="hl || debug"/>
<section if="cpp">
<!-- 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"/> -->
<!-- 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"/>
<!-- 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"/>
<!-- 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" if="cpp"/>
<!-- Comment this out to disable mods folder !-->
<haxedef name="MOD_SUPPORT" unless="web"/>
<!-- Comment this out to disable translations folders !-->
<haxedef name="TRANSLATIONS_SUPPORT"/>
<!-- Comment this out to disable global scripts !-->
<haxedef name="GLOBAL_SCRIPT"/>
<!-- Comment this out to disable softcoded states and state scripting !-->
<haxedef name="SOFTCODED_STATES"/>
<!-- Comment this out to disable support for custom ndlls. !-->
<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"/>
<!-- Comment this out to disable support for Away3D Flixel Integration (reduces compile times) !-->
<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"/>
<!-- Disable a optimization, to allow reflection to use more functions -->
<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 ______________________________ -->
<!-- KEEP BOTH OF THESE AS THERE ARE SOME PARTICULAR CASES! -->
<define name="disable-version-check"/>
<haxedef name="disable-version-check"/>
<haxelib name="flixel"/>
<haxelib name="flixel-addons"/>
<haxelib name="flixel-animate"/>
<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="hxcpp-debug-server" if="debug"/>
<!-- ____________________________ Source Settings ___________________________ -->
<!-- DO NO REMOVE THIS -->
<haxedef name="REGION"/>
<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"/>
<library name="assets" preload="true" if="PRELOAD_ALL"/>
<library name="assets" preload="false" if="NO_PRELOAD_ALL" />
<section unless="TEST_BUILD">
<assets path="assets/" rename="assets" exclude="*.ogg" if="web"/>
<assets path="assets/" rename="assets" exclude="*.mp3" unless="web"/>
<!-- TODO: make it copy this manually, instead of using assets node, so it doesn't manually check for fonts -->
<assets path='mods' rename='mods' embed='false' />
</section>
<!-- <assets path='art/readme.txt' rename='do NOT readme.txt' /> -->
<!-- ______________________________ Haxedefines _____________________________ -->
<haxeflag name="--macro" value="funkin.backend.system.macros.Macros.initMacros()"/>
<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"/>
<!-- Backward Compatibilities -->
<haxedef name="FLX_HEALTH" />
<haxedef name="FLX_NO_FOCUS_LOST_SCREEN"/>
<haxedef name="FLX_NO_DEBUG" unless="debug"/>
<haxedef name="DISCORD_DISABLE_IO_THREAD" if="DISCORD_RPC"/>
<!-- <haxedef name="no-deprecation-warnings"/> -->
<!-- Fix compiling issues -->
<setenv name="HAXEPATH" value="./"/>
<!-- Haxe 4.3.0+: Enable pretty syntax errors and stuff. -->
<haxedef name="message.reporting" value="pretty"/>
<!-- 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>
+929
View File
@@ -0,0 +1,929 @@
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)
]);
}
}
+120
View File
@@ -0,0 +1,120 @@
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;
}
}
+92
View File
@@ -0,0 +1,92 @@
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;
}
}
+144 -101
View File
@@ -1,7 +1,5 @@
package funkin.backend;
import animate.FlxAnimate;
import animate.FlxAnimateController.FlxAnimateAnimation;
import flixel.addons.effects.FlxSkewedSprite;
import flixel.animation.FlxAnimation;
import flixel.math.FlxMatrix;
@@ -9,6 +7,7 @@ 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;
@@ -16,10 +15,6 @@ 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)
{
@@ -48,7 +43,7 @@ enum abstract XMLAnimType(Int)
}
}
class FunkinSprite extends FlxAnimate implements IBeatReceiver implements IOffsetCompatible implements IXMLEvents
class FunkinSprite extends FlxSkewedSprite implements IBeatReceiver implements IOffsetCompatible implements IXMLEvents
{
public var extra:Map<String, Dynamic> = [];
@@ -61,9 +56,6 @@ class FunkinSprite extends FlxAnimate implements IBeatReceiver implements IOffse
public var animEnabled:Bool = true;
public var zoomFactorEnabled:Bool = true;
//Backwards compatibility
public var animateAtlas(get, never):FunkinSprite;
public var globalCurFrame(get, set):Int;
/**
@@ -74,9 +66,9 @@ class FunkinSprite extends FlxAnimate implements IBeatReceiver implements IOffse
public var beatOffset:Int = 0;
public var skipNegativeBeats:Bool = false;
public var animateSettings:FlxAnimateSettings = {};
var _rect2:FlxRect;
public var animateAtlas:FlxAnimate;
@:noCompletion public var atlasPlayingAnim:String;
@:noCompletion public var atlasPath:String;
public function new(?X:Float = 0, ?Y:Float = 0, ?SimpleGraphic:FlxGraphicAsset)
{
@@ -91,7 +83,6 @@ class FunkinSprite extends FlxAnimate implements IBeatReceiver implements IOffse
}
moves = false;
applyStageMatrix = true;
}
/**
@@ -107,6 +98,8 @@ class FunkinSprite extends FlxAnimate implements IBeatReceiver implements IOffse
@: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;
@@ -116,8 +109,9 @@ class FunkinSprite extends FlxAnimate implements IBeatReceiver implements IOffse
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;
@@ -126,6 +120,8 @@ class FunkinSprite extends FlxAnimate implements IBeatReceiver implements IOffse
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()) {
@@ -135,15 +131,18 @@ class FunkinSprite extends FlxAnimate implements IBeatReceiver implements IOffse
}
}
override function initVars() {
super.initVars();
_rect2 = FlxRect.get();
}
public function loadSprite(path:String, Unique:Bool = false, Key:String = null)
{
var noExt = Path.withoutExtension(path);
frames = Paths.getFrames(path, true, null, null, animateSettings);
if (Assets.exists('$noExt/Animation.json'))
{
atlasPath = noExt;
animateAtlas = new FlxAnimate(x, y, noExt);
}
else
{
frames = Paths.getFrames(path, true);
}
return this;
}
@@ -173,22 +172,50 @@ class FunkinSprite extends FlxAnimate implements IBeatReceiver implements IOffse
{
}
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();
}
// ANIMATE ATLAS DRAWING
#if REGION
public override function draw()
{
if (animateAtlas != null)
{
copyAtlasValues();
animateAtlas.draw();
}
else
{
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;
}
}
public override function destroy()
{
animateAtlas = FlxDestroyUtil.destroy(animateAtlas);
if (animOffsets != null) {
for (key in animOffsets.keys()) {
final point = animOffsets[key];
@@ -199,8 +226,6 @@ class FunkinSprite extends FlxAnimate implements IBeatReceiver implements IOffse
animOffsets = null;
}
super.destroy();
_rect2 = FlxDestroyUtil.put(_rect2);
}
#end
@@ -208,21 +233,27 @@ class FunkinSprite extends FlxAnimate implements IBeatReceiver implements IOffse
private inline function __shouldDoZoomFactor()
return zoomFactorEnabled && zoomFactor != 1;
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))
);
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;
}
override public function isOnScreen(?camera:FlxCamera):Bool
@@ -239,6 +270,20 @@ class FunkinSprite extends FlxAnimate implements IBeatReceiver implements IOffse
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>();
@@ -270,7 +315,13 @@ class FunkinSprite extends FlxAnimate implements IBeatReceiver implements IOffse
Force = anim != null && anim.forced;
}
animation.play(AnimName, Force, Reversed, Frame);
if (animateAtlas != null)
{
@:privateAccess
animateAtlas.anim.play(AnimName, Force, Reversed, Frame);
atlasPlayingAnim = AnimName;
}
else animation.play(AnimName, Force, Reversed, Frame);
var daOffset = getAnimOffset(AnimName);
frameOffset.set(daOffset.x, daOffset.y);
@@ -279,7 +330,7 @@ class FunkinSprite extends FlxAnimate implements IBeatReceiver implements IOffse
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, animateAtlasLabel:Bool = false)
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)
{
return XMLUtil.addAnimToSprite(this, {
name: name,
@@ -290,16 +341,22 @@ class FunkinSprite extends FlxAnimate implements IBeatReceiver implements IOffse
x: x,
y: y,
indices: indices,
forced: forced,
label: animateAtlasLabel
forced: forced
});
}
public inline function removeAnim(name:String) {
animation.remove(name);
public inline function removeAnim(name:String)
{
if (animateAtlas != null)
@:privateAccess animateAtlas.anim.animsMap.remove(name);
else
animation.remove(name);
}
public function getAnim(name:String):OneOfTwo<FlxAnimation, FlxAnimateAnimation> {
public function getAnim(name:String):OneOfTwo<FlxAnimation, FlxSymbolAnimation>
{
if(animateAtlas != null)
return animateAtlas.anim.getByName(name);
return animation.getByName(name);
}
@@ -310,26 +367,40 @@ class FunkinSprite extends FlxAnimate implements IBeatReceiver implements IOffse
return FlxPoint.weak(0, 0);
}
public inline function hasAnim(AnimName:String):Bool
return animation.exists(AnimName);
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 getAnimName()
return animation.name;
public inline function getAnimName() {
return (animateAtlas != null) ? atlasPlayingAnim : animation.name;
}
public inline function isAnimReversed():Bool
return animation.curAnim?.reversed ?? false;
public inline function isAnimReversed():Bool {
return animateAtlas != null ? animateAtlas.anim.reversed : animation.curAnim != null ? animation.curAnim.reversed : false;
}
public inline function getNameList():Array<String>
return animation.getNameList();
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 stopAnim()
animation.stop();
{
if (animateAtlas != null)
animateAtlas.anim.pause();
else
animation.stop();
}
public inline function isAnimFinished()
return animation.curAnim?.finished ?? true;
public inline function isAnimFinished() {
return animateAtlas != null ? animateAtlas.anim.finished : (animation.curAnim != null ? animation.curAnim.finished : true);
}
public inline function isAnimAtEnd()
return animation.curAnim?.isAtEnd ?? false;
public inline function isAnimAtEnd() {
return animateAtlas != null ? animateAtlas.anim.isAtEnd : (animation.curAnim != null ? animation.curAnim.isAtEnd : false);
}
override function updateAnimation(elapsed:Float) {
if (animEnabled)
@@ -351,38 +422,10 @@ class FunkinSprite extends FlxAnimate implements IBeatReceiver implements IOffse
return beatInterval = v;
}
@: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 get_globalCurFrame() {
return animateAtlas != null ? (animateAtlas.anim.curFrame) : (animation.curAnim != null ? animation.curAnim.curFrame : 0);
}
@:noCompletion private inline function set_globalCurFrame(val:Int) {
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;
return animateAtlas != null ? (animateAtlas.anim.curFrame = val) : (animation.curAnim != null ? animation.curAnim.curFrame = val : val);
}
}
+4 -83
View File
@@ -1,98 +1,19 @@
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 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;
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;
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,12 +236,6 @@ 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));
+6 -2
View File
@@ -114,8 +114,12 @@ class MusicBeatTransition extends MusicBeatSubstate {
}
if (transitionSprite != null) {
transitionSprite.setGraphicSize(transitionCamera.width, transitionCamera.height);
transitionSprite.updateHitbox();
if (transitionSprite.animateAtlas == null) {
transitionSprite.setGraphicSize(transitionCamera.width, transitionCamera.height);
transitionSprite.updateHitbox();
} else {
transitionSprite.screenCenter();
}
}
}
@@ -5,21 +5,9 @@ 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)
@@ -30,9 +18,6 @@ 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);
@@ -56,29 +41,12 @@ 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
@@ -173,16 +141,6 @@ 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;
}
@@ -217,7 +175,6 @@ class AssetsLibraryList extends AssetLibrary {
public function reset() {
unloadLibraries();
cachePaths.clear();
libraries = [];
// adds default libraries in again
+21 -13
View File
@@ -83,11 +83,10 @@ class ModsFolder {
*/
public static function loadModLib(path:String, force:Bool = false, ?modName:String) {
#if MOD_SUPPORT
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);
if (FileSystem.exists('$path.zip'))
return loadLibraryFromZip('$path'.toLowerCase(), '$path.zip', force, modName);
else
return loadLibraryFromFolder('$path'.toLowerCase(), '$path', force, modName);
#else
return null;
@@ -97,16 +96,27 @@ class ModsFolder {
public static function getModsList():Array<String> {
var mods:Array<String> = [];
#if MOD_SUPPORT
// Mods directory does not exist yet, create it
if (!FileSystem.exists(modsPath)) FileSystem.createDirectory(modsPath);
if (!FileSystem.exists(modsPath)) {
// Mods directory does not exist yet, create it
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 if (Flags.ALLOWED_ZIP_EXTENSIONS.contains(Path.extension(modFolder))) mods.push(Path.withoutExtension(modFolder));
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));
}
}
}
#end
return mods;
@@ -118,9 +128,7 @@ class ModsFolder {
#if TRANSLATIONS_SUPPORT
if(skipTranslated && (l is TranslatedAssetLibrary)) continue;
#end
// 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));
if (l is ScriptedAssetLibrary || l is IModsAssetLibrary) libs.push(cast(l, IModsAssetLibrary));
}
return libs;
}
@@ -149,22 +149,6 @@ 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.incrementUseCount();
collection.parent.useCount++;
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.decrementUseCount();
collection.parent.useCount--;
}
parentedFrames = null;
}
+4 -10
View File
@@ -8,7 +8,6 @@ import funkin.backend.scripting.Script;
import haxe.io.Path;
import lime.utils.AssetLibrary;
import openfl.utils.Assets as OpenFlAssets;
import animate.FlxAnimateFrames;
using StringTools;
@@ -175,9 +174,6 @@ 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');
@@ -194,14 +190,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, ?animateSettings:FlxAnimateSettings) {
public static function getFrames(key:String, assetsPath:Bool = false, ?library:String, ?ext:String = null) {
if (tempFramesCache.exists(key)) {
var frames = tempFramesCache[key];
if (frames != null && frames.parent != null && frames.parent.bitmap != null && frames.parent.bitmap.readable)
@@ -209,7 +205,7 @@ class Paths
else
tempFramesCache.remove(key);
}
return tempFramesCache[key] = loadFrames(assetsPath ? key : Paths.image(key, library, true, ext), false, null, false, ext, animateSettings);
return tempFramesCache[key] = loadFrames(assetsPath ? key : Paths.image(key, library, true, ext), false, null, false, ext);
}
/**
@@ -246,7 +242,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, ?animateSettings:FlxAnimateSettings):FlxFramesCollection {
static function loadFrames(path:String, Unique:Bool = false, Key:String = null, SkipAtlasCheck:Bool = false, SkipMultiCheck:Bool = false, ?Ext:String = null):FlxFramesCollection {
var noExt = Path.withoutExtension(path);
var ext = Ext != null ? Ext : Flags.IMAGE_EXT;
@@ -267,8 +263,6 @@ 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,8 +108,6 @@ 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,14 +1,11 @@
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;
@@ -18,16 +15,15 @@ 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 var PRELOAD_VIDEOS:Bool = true;
public function new(basePath:String, libName:String, ?modName:String, ?preloadVideos:Bool = true) {
public function new(basePath:String, libName:String, ?modName:String) {
this.libName = libName;
this.basePath = basePath;
@@ -35,59 +31,21 @@ class ZipFolderLibrary extends AssetLibrary implements IModsAssetLibrary {
this.modName = (modName == null) ? libName : modName;
zip = SysZip.openFromFile(basePath);
zip.read();
for(entry in zip.entries) {
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);
lowerCaseAssets[entry.fileName.toLowerCase()] = assets[entry.fileName.toLowerCase()] = assets[entry.fileName] = entry;
nameMap.set(entry.fileName.toLowerCase(), 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 | ${zip.entries.length} entries | Detected Video Extensions: ${_videoExtensions.join(", ")})';
return '(ZipFolderLibrary: $libName/$modName)';
}
public var _parsedAsset:String;
public override function getAudioBuffer(id:String):AudioBuffer {
__parseAsset(id);
return AudioBuffer.fromBytes(unzip(assets[_parsedAsset]));
@@ -110,12 +68,15 @@ 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);
@@ -126,7 +87,8 @@ 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;
}
@@ -141,8 +103,9 @@ class ZipFolderLibrary extends AssetLibrary implements IModsAssetLibrary {
return assets[_parsedAsset] != null;
}
private inline function getAssetPath() {
return getVideoRemap('$basePath/$_parsedAsset');
private function getAssetPath() {
trace('[ZIP]$basePath/$_parsedAsset');
return '[ZIP]$basePath/$_parsedAsset';
}
// TODO: rewrite this to 1 function, like ModsFolderLibrary
@@ -191,6 +154,14 @@ class ZipFolderLibrary extends AssetLibrary implements IModsAssetLibrary {
return content;
}
public override function list(type:String):Array<String> { return [for(k=>e in nameMap) '$prefix$e']; }
// 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;
}
}
#end
+3 -8
View File
@@ -278,13 +278,9 @@ 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' : "", 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) {
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) {
songPath = temp.substr(0, temp.length - metaPath.length - 1);
metaPath = temp;
}
@@ -304,7 +300,6 @@ 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
+2 -4
View File
@@ -75,7 +75,7 @@ class EventsData {
defValue: "In"
},
{name: "Mode", type: TDropDown(['direct', 'stage']), defValue: "direct"},
{name: "Multiplicative?", type: TBool, defValue: false}
{name: "Multiplicative?", type: TBool, defValue: true}
],
"Camera Modulo Change" => [
{name: "Modulo Interval", type: TInt(1, 9999999, 1), defValue: 4},
@@ -179,8 +179,7 @@ class EventsData {
finalParams.push({
name: paramData.name,
type: hscriptInterp.expr(hscriptParser.parseString(paramData.type)),
defValue: paramData.defaultValue,
saveIfDefault: paramData.saveIfDefault
defValue: paramData.defaultValue
});
} catch (e) {trace('Error parsing event param ${paramData.name} - ${eventName}: $e'); finalParams.push(null);}
}
@@ -197,7 +196,6 @@ typedef EventInfoFile = {
var name:String;
var type:String;
var defaultValue:Dynamic;
var ?saveIfDefault:Bool;
}>;
}
+1 -1
View File
@@ -60,7 +60,7 @@ class PsychParser {
note.time, // TIME
note.id, // DATA
note.sLen, // SUSTAIN LENGTH
chart.noteTypes.getDefault([""])[note.type - 1] // NOTE TYPE
chart.noteTypes.getDefault([""])[note.type] // NOTE TYPE
];
if ((swagSection.mustHitSection && strumLine.type == OPPONENT) ||
@@ -55,6 +55,9 @@ 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");
@@ -106,15 +109,12 @@ class GlobalScript {
public static function onModSwitch(newMod:String) {
destroy();
scripts = new ScriptPack("GlobalScript");
for (lib in funkin.backend.assets.ModsFolder.getLoadedModsLibs()) {
var modName = lib.modName;
var path = Paths.script('data/global/LIB_$modName');
for (i in funkin.backend.assets.ModsFolder.getLoadedMods()) {
var path = Paths.script('data/global/LIB_$i');
var script = Script.create(path);
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);
if (script is DummyScript)
continue;
script.remappedNames.set(script.fileName, '$i:${script.fileName}');
scripts.add(script);
script.load();
}
@@ -1,8 +1,14 @@
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.
*/
@@ -40,6 +46,13 @@ 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));
}
@@ -56,7 +69,7 @@ class MultiThreadedScript implements IFlxDestroyable implements IHScriptCustomBe
public function call(func:String, args:Array<Dynamic>) {
#if ALLOW_MULTITHREADING
funkin.backend.utils.ThreadUtil.execAsync(() -> {
thread.events.run(function() {
callEnded = false;
returnValue = script.call(func, args);
callEnded = true;
@@ -72,5 +85,13 @@ 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
}
}
+2 -3
View File
@@ -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, // deprecated
"CustomShader" => funkin.backend.shaders.CustomShader,
"FunkinText" => funkin.backend.FunkinText,
"FlxAnimate" => animate.FlxAnimate,
"FlxAnimate" => funkin.backend.FlxAnimate,
"FunkinSprite" => funkin.backend.FunkinSprite,
"Alphabet" => funkin.menus.ui.Alphabet,
"Flags" => funkin.backend.system.Flags,
@@ -102,7 +102,6 @@ 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,6 +4,7 @@ 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;
@@ -53,4 +54,4 @@ class CancellableEvent implements IFlxDestroyable {
public function destroy() {
data = null;
}
}
}
@@ -1,96 +0,0 @@
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,7 +11,6 @@ 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.
@@ -34,11 +33,11 @@ final class NoteHitEvent extends CancellableEvent {
/**
* Whenever the Rating sprites should be shown or not.
*/
public var displayRating:Null<Bool>;
public var displayRating:Bool;
/**
* Whenever the Combo sprite should be shown or not (like old Week 7 patches).
*/
public var displayCombo:Null<Bool>;
public var displayCombo:Bool;
/**
* Note that has been pressed
*/
@@ -66,11 +65,11 @@ final class NoteHitEvent extends CancellableEvent {
/**
* Prefix of the rating sprite path. Defaults to "game/score/"
*/
public var ratingPrefix:Null<String>;
public var ratingPrefix:String;
/**
* Suffix of the rating sprite path.
*/
public var ratingSuffix:Null<String>;
public var ratingSuffix:String;
/**
* Direction of the press (0 = Left, 1 = Down, 2 = Up, 3 = Right)
*/
@@ -98,19 +97,19 @@ final class NoteHitEvent extends CancellableEvent {
/**
* Scale of combo numbers.
*/
public var numScale:Null<Float>;
public var numScale:Float = 0.5;
/**
* Whenever antialiasing should be enabled on combo number.
*/
public var numAntialiasing:Null<Bool>;
public var numAntialiasing:Bool = true;
/**
* Scale of ratings.
*/
public var ratingScale:Null<Float>;
public var ratingScale:Float = 0.7;
/**
* Whenever antialiasing should be enabled on ratings.
*/
public var ratingAntialiasing:Null<Bool>;
public var ratingAntialiasing:Bool = true;
/**
* 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).
*/
@@ -146,13 +145,6 @@ 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.
*/
@@ -0,0 +1,36 @@
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;
}
}
@@ -1,766 +0,0 @@
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];
}
}
+32 -8
View File
@@ -2,15 +2,39 @@ package funkin.backend.shaders;
import openfl.Assets;
@:deprecated("Use funkin.backend.shaders.FunkinShader.fromFile instead.")
/**
* 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`
*/
class CustomShader extends FunkinShader {
@: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;
public var path:String = "";
public function new(name:String, ?glslVersion:String) {
super();
loadShaderFile(Paths.fragShader(name), Paths.vertShader(name), glslVersion);
/**
* 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);
}
}
+600 -251
View File
@@ -1,65 +1,533 @@
package funkin.backend.shaders;
import haxe.io.Path;
import flixel.graphics.FlxGraphic;
import flixel.system.FlxAssets.FlxShader;
import flixel.util.FlxSignal.FlxTypedSignal;
import haxe.Exception;
import hscript.IHScriptCustomBehaviour;
import lime.utils.Float32Array;
import openfl.display.BitmapData;
import openfl.display.Shader;
import openfl.display.ShaderInput;
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 FlxRuntimeShader implements IHScriptCustomBehaviour {
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;
public var onGLUpdate:FlxTypedSignal<Void->Void> = new FlxTypedSignal<Void->Void>();
public var onProcessGLData:FlxTypedSignal<(String, String)->Void> = new FlxTypedSignal<(String, String)->Void>();
public function new(?fragmentSource:String, ?vertexSource:String, ?version:String) {
super(fragmentSource, vertexSource, version ?? (fragmentSource != null || vertexSource != null ? Flags.DEFAULT_GLSL_VERSION : null));
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 static function fromFile(fragmentPath:String, ?vertexPath:String, ?version:String):FunkinShader {
return new FunkinShader().loadShaderFile(fragmentPath, vertexPath, version);
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 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);
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);
}
fragmentPath = FlxRuntimeShader._getPath(fragmentPath, false);
vertexPath = FlxRuntimeShader._getPath(vertexPath, true);
_fromFile(fragmentPath, vertexPath, version ?? (fragmentPath != null || vertexPath != null ? Flags.DEFAULT_GLSL_VERSION : null));
return shader;
}
return this;
@: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) {}
}
}
}
#if REGION /* IHScriptCustomBehaviour */
public function hget(name:String):Dynamic {
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);
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);
var cl:String = Type.getClassName(Type.getClass(field));
// little problem we are facing boys...
@@ -78,19 +546,17 @@ class FunkinShader extends FlxRuntimeShader implements IHScriptCustomBehaviour {
}
public function hset(name:String, val:Dynamic):Dynamic {
if (__glSourceDirty) __init();
if (__thisHasField(name) || __thisHasField('set_${name}')) {
if (__instanceFields.contains(name) || __instanceFields.contains('set_${name}')) {
Reflect.setProperty(this, name, val);
return val;
}
else if (!Reflect.hasField(__data, name)) {
// ??? huh
Reflect.setField(__data, name, val);
if (!Reflect.hasField(data, name)) {
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
@@ -132,193 +598,9 @@ class FunkinShader extends FlxRuntimeShader 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 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;
@@ -327,27 +609,35 @@ 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);
vec4 applyFlixelEffects(vec4 color) {
if(!hasTransform) {
return color;
}
// 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;
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);
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));
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;
@@ -368,17 +658,53 @@ 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 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;
attribute vec4 openfl_Position;
attribute vec2 openfl_TextureCoord;
public static final vertBackCompatVarList:Array<EReg> = [
~/attribute float alpha/,
~/attribute vec4 colorMultiplier/,
~/attribute vec4 colorOffset/,
~/uniform bool hasColorTransform/
];
varying float openfl_Alphav;
varying vec4 openfl_ColorMultiplierv;
varying vec4 openfl_ColorOffsetv;
varying vec2 openfl_TextureCoordv;
public static final vertHeaderBackCompat:String = "attribute float openfl_Alpha;
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_Alphav = openfl_Alpha;
openfl_TextureCoordv = openfl_TextureCoord;
if(openfl_HasColorTransform) {
openfl_ColorMultiplierv = openfl_ColorMultiplier;
openfl_ColorOffsetv = openfl_ColorOffset / 255.0;
}
openfl_Alphav = openfl_Alpha * alpha;
if(hasColorTransform) {
openfl_ColorOffsetv = colorOffset / 255.0;
openfl_ColorMultiplierv = colorMultiplier;
}
gl_Position = openfl_Matrix * openfl_Position;";
// 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 vertHeaderBackCompat:String = "attribute float openfl_Alpha;
attribute vec4 openfl_ColorMultiplier;
attribute vec4 openfl_ColorOffset;
attribute vec4 openfl_Position;
@@ -393,7 +719,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) {
@@ -402,8 +728,19 @@ 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>;
@@ -416,4 +753,16 @@ 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;
}
}
@@ -1,471 +0,0 @@
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,8 +30,6 @@ 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);
-6
View File
@@ -25,7 +25,6 @@ enum Control
CHANGE_MODE;
//CHEAT;
SWITCHMOD;
FPS_COUNTER;
// Debugs
DEV_ACCESS;
@@ -162,11 +161,6 @@ 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;
+8 -13
View File
@@ -11,11 +11,6 @@ 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();
@@ -26,14 +21,14 @@ class FakeCamera extends FlxCamera {
visible = false;
}
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 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 clearDrawStack() {}
override function render() {}
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 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 update(elapsed:Float) {}
@@ -46,10 +41,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, ?wrapMode:Context3DWrapMode, ?depthCompareMode:Context3DCompareMode) {
public dynamic function onDraw(?frame:FlxFrame, ?pixels:BitmapData, matrix:FlxMatrix, ?transform:ColorTransform, ?blend:BlendMode, ?smoothing:Bool = false, ?shader:FlxShader) {
}
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);
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);
}
}
+19 -63
View File
@@ -15,20 +15,14 @@ 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 = "";
@:lazy public static var MOD_API_VERSION:Null<Int> = null;
public static var MOD_API_VERSION:Int = 1;
public static var MOD_DOWNLOAD_LINK:String = "";
public static var MOD_DEPENDENCIES:Array<String> = [];
@@ -47,11 +41,12 @@ 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)';
@:lazy public static var WINDOW_TITLE_USE_MOD_NAME:Null<Bool> = null;
@:bypass public static var WINDOW_TITLE_USE_MOD_NAME:Bool = false;
@:lazy public static var TITLE:String = Application.current.meta.get('name');
@:lazy public static var VERSION:String = Application.current.meta.get('version');
@@ -106,10 +101,6 @@ 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"];
@@ -134,19 +125,12 @@ 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";
@@ -164,14 +148,10 @@ 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
@@ -286,7 +266,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";
@:lazy public static var DEFAULT_GLSL_VERSION:String = null;
public static var DEFAULT_GLSL_VERSION:String = "120";
@:also(funkin.backend.utils.HttpUtil.userAgent)
public static var USER_AGENT:String = 'request';
// -- End of Codename's Default Flags --
@@ -297,6 +277,8 @@ 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);
@@ -313,53 +295,28 @@ 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");
}
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> {
public static function loadFromDatas(datas:Array<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>) {
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
for(name=>value in flags)
if(!parse(name, value))
customFlags.set(name, value);
Options.modchartingHoldSubdivisions = DEFAULT_MODCHART_HOLD_SUBDIVISIONS;
#end
}
/**
@@ -408,6 +365,5 @@ class Flags {
parseFlags(flags);
}
}
loadPost();
}
}
}
+5 -4
View File
@@ -8,12 +8,13 @@ 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();
ticks = getTicks();
_total = ticks = getTicks();
skipNextTickUpdate = true;
}
override function __enterFrame(deltaTime:Float) {
if (skipNextTickUpdate != (skipNextTickUpdate = false)) ticks = getTicks();
super.__enterFrame(deltaTime);
public override function onEnterFrame(t) {
if (skipNextTickUpdate != (skipNextTickUpdate = false))
_total = ticks = getTicks();
super.onEnterFrame(t);
}
}
@@ -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.incrementUseCount();
graphic.useCount++;
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.decrementUseCount();
g.useCount--;
}
graphic = null;
super.destroy();
+1 -1
View File
@@ -115,7 +115,7 @@ final class Logs {
Sys.print(t.text);
}
NativeAPI.setConsoleColors();
Sys.println("\r");
Sys.print("\r\n");
__showing = false;
#elseif mobile
while(__showing) {
+48 -25
View File
@@ -1,5 +1,7 @@
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;
@@ -7,25 +9,24 @@ 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.system.framerate.Framerate;
import funkin.backend.assets.AssetSource;
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;
import sys.FileSystem;
import sys.io.File;
#if ALLOW_MULTITHREADING
import sys.thread.Thread;
#end
#if android
import extension.androidtools.content.Context;
import extension.androidtools.os.Build;
import android.content.Context;
import android.os.Build;
#end
class Main extends Sprite
@@ -33,13 +34,13 @@ class Main extends Sprite
public static var instance:Main;
public static var modToLoad:String = null;
public static var forceGPUOnlyBitmapsOff:Bool = false;
public static var forceGPUOnlyBitmapsOff:Bool = #if desktop false #else true #end;
public static var noTerminalColor:Bool = false;
public static var verbose:Bool = false;
public static var scaleMode:FunkinRatioScaleMode;
#if !mobile
public static var framerateSprite:Framerate;
public static var framerateSprite:funkin.backend.system.framerate.Framerate;
#end
var gameWidth:Int = 1280; // Width of the game in pixels (might be less / more in actual pixels).
@@ -57,12 +58,14 @@ 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()
@@ -76,7 +79,7 @@ class Main extends Sprite
addChild(game = new FunkinGame(gameWidth, gameHeight, MainState, Options.framerate, Options.framerate, skipSplash, startFullscreen));
#if (!mobile && !web)
addChild(framerateSprite = new Framerate());
addChild(framerateSprite = new funkin.backend.system.framerate.Framerate());
SystemInfo.init();
#end
}
@@ -94,13 +97,31 @@ class Main extends Sprite
#end;
public static var startedFromSource:Bool = #if TEST_BUILD true #else false #end;
// DEPRECATED
@:dox(hide) public static function execAsync(func:Void->Void) ThreadUtil.execAsync(func);
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();
}
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();
@@ -125,16 +146,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
@@ -189,18 +210,20 @@ 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();
}
@@ -0,0 +1,14 @@
package funkin.backend.system;
import lime.app.Application;
import funkin.backend.system.Main;
class MainApplication extends Application {
public function new() {
super();
#if openfl
openfl.Lib.current.stage.addChild(new Main());
#end
}
}
+14 -44
View File
@@ -7,14 +7,12 @@ 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;
@@ -42,7 +40,6 @@ class MainState extends FlxState {
ControlsUtil.resetCustomControls();
FlxG.bitmap.reset();
FlxG.sound.destroy(true);
FlxG.sound.resetCache();
Paths.assetsTree.reset();
@@ -60,32 +57,12 @@ 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,
// 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
(
ModsFolder.currentModFolder != null ?
ModsFolder.modsPath + ModsFolder.currentModFolder + "/addons/" :
null
)
];
@@ -95,8 +72,12 @@ class MainState extends FlxState {
for (addon in FileSystem.readDirectory(path)) {
if (!FileSystem.isDirectory(path + addon)) {
if (Flags.ALLOWED_ZIP_EXTENSIONS.contains(Path.extension(addon))) addon = Path.withoutExtension(addon);
else continue;
switch(Path.extension(addon).toLowerCase()) {
case 'zip':
addon = Path.withoutExtension(addon);
default:
continue;
}
}
var data:AddonInfo = {
@@ -119,14 +100,9 @@ class MainState extends FlxState {
#if MOD_SUPPORT
for (addon in _lowPriorityAddons)
loadLib(addon.path, ltrim(addon.name, "[LOW]"));
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);
}
if (ModsFolder.currentModFolder != null)
loadLib(ModsFolder.modsPath + ModsFolder.currentModFolder, ModsFolder.currentModFolder);
for (addon in _noPriorityAddons)
loadLib(addon.path, addon.name);
@@ -158,15 +134,9 @@ 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;
// 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) {
if (Options.devMode && Options.allowConfigWarning) {
var lib:ModsFolderLibrary;
for (e in Paths.assetsTree.libraries) if ((lib = cast AssetsLibraryList.getCleanLibrary(e)) is ModsFolderLibrary
&& lib.modName == ModsFolder.currentModFolder)
@@ -1,14 +1,62 @@
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
{
super.__fromImage(image);
toHardware();
#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
}
}

Some files were not shown because too many files have changed in this diff Show More