mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
Compare commits
108 Commits
v5.1.161
...
scene-edit
Author | SHA1 | Date | |
---|---|---|---|
![]() |
b43d5ec425 | ||
![]() |
3c43f28966 | ||
![]() |
a3f7c5782e | ||
![]() |
8dec6dfa28 | ||
![]() |
4eb49bdeb2 | ||
![]() |
813cadbd6e | ||
![]() |
58dd2c1a7b | ||
![]() |
104c27ebc8 | ||
![]() |
318099504c | ||
![]() |
8851be03a3 | ||
![]() |
a9a126ab0d | ||
![]() |
19e46fedc8 | ||
![]() |
ff987a0751 | ||
![]() |
0c0ab65b1a | ||
![]() |
52a5908d7e | ||
![]() |
49926a89a2 | ||
![]() |
b63b91f33d | ||
![]() |
67ea361416 | ||
![]() |
3b9078c6b3 | ||
![]() |
3d9e3f997e | ||
![]() |
3c34866faa | ||
![]() |
69cd2784c4 | ||
![]() |
5b7e419a41 | ||
![]() |
7773460d35 | ||
![]() |
9262266480 | ||
![]() |
84f2b4ca68 | ||
![]() |
19ae7a378c | ||
![]() |
f9ca330add | ||
![]() |
5ef990ac7d | ||
![]() |
8099820729 | ||
![]() |
df556f20e9 | ||
![]() |
2c8f2ab58d | ||
![]() |
20c3d62c90 | ||
![]() |
0a28981c74 | ||
![]() |
c8bb24475c | ||
![]() |
81bce61783 | ||
![]() |
71d1b6aa1f | ||
![]() |
c41974c24b | ||
![]() |
3bee88c6cd | ||
![]() |
4c874dfb7e | ||
![]() |
65f499f24e | ||
![]() |
3265bf7fb4 | ||
![]() |
5a437dea4e | ||
![]() |
19b576e8cc | ||
![]() |
67747e458e | ||
![]() |
260c2b9c8f | ||
![]() |
255ef1d8ef | ||
![]() |
53c633c646 | ||
![]() |
cec67a91d4 | ||
![]() |
4408dfe59d | ||
![]() |
c4274d2fc4 | ||
![]() |
b0103f31b7 | ||
![]() |
18905890d4 | ||
![]() |
6858e0fb59 | ||
![]() |
cf595a7d7d | ||
![]() |
e681d27bb8 | ||
![]() |
8941e04390 | ||
![]() |
e186681f39 | ||
![]() |
a578fa32e9 | ||
![]() |
6b40e8309c | ||
![]() |
5ff51351af | ||
![]() |
d66e4e0001 | ||
![]() |
2184eaf70b | ||
![]() |
29fc0598f6 | ||
![]() |
a7760e975a | ||
![]() |
e2397cb0a4 | ||
![]() |
24ff670886 | ||
![]() |
d24b7497c9 | ||
![]() |
0ecaa342f9 | ||
![]() |
141ac87c6e | ||
![]() |
057e6dcfed | ||
![]() |
9c69c90a66 | ||
![]() |
4df6ecc654 | ||
![]() |
c106d05098 | ||
![]() |
f3f426e949 | ||
![]() |
52d0ed1217 | ||
![]() |
511138269d | ||
![]() |
22dda6194c | ||
![]() |
aa2ef39f32 | ||
![]() |
a744b88c5c | ||
![]() |
2847601fc5 | ||
![]() |
bfbdf1cd3f | ||
![]() |
ed1694a818 | ||
![]() |
0ee121c014 | ||
![]() |
312e96a881 | ||
![]() |
c169c5037a | ||
![]() |
a82ae304a0 | ||
![]() |
adb30c5105 | ||
![]() |
aad11f2518 | ||
![]() |
737d389493 | ||
![]() |
4b071fbf17 | ||
![]() |
982a0c6e53 | ||
![]() |
91adaac722 | ||
![]() |
138a7c9abe | ||
![]() |
c7099d694e | ||
![]() |
fde1039707 | ||
![]() |
73e087936a | ||
![]() |
260fd5949e | ||
![]() |
a4939181a5 | ||
![]() |
cab56451ff | ||
![]() |
7b32bbacd6 | ||
![]() |
a15707d655 | ||
![]() |
714a9f1198 | ||
![]() |
2a91c54b0e | ||
![]() |
3272b8eda7 | ||
![]() |
cd432a22b6 | ||
![]() |
9ac483156e | ||
![]() |
d0f39027af |
22
.github/workflows/build-storybook.yml
vendored
22
.github/workflows/build-storybook.yml
vendored
@@ -17,31 +17,23 @@ jobs:
|
||||
build-storybook:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 50
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
cache: 'npm'
|
||||
cache-dependency-path: 'newIDE/app/package-lock.json'
|
||||
|
||||
- name: Configure AWS Credentials
|
||||
uses: aws-actions/configure-aws-credentials@v1
|
||||
uses: aws-actions/configure-aws-credentials@v2
|
||||
with:
|
||||
aws-access-key-id: ${{ secrets.BUILD_STORYBOOK_AWS_ACCESS_KEY_ID }}
|
||||
aws-secret-access-key: ${{ secrets.BUILD_STORYBOOK_AWS_SECRET_ACCESS_KEY }}
|
||||
aws-region: us-east-1
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 50
|
||||
|
||||
# Cache npm dependencies to speed up the workflow
|
||||
- name: Cache node modules
|
||||
uses: actions/cache@v2
|
||||
env:
|
||||
cache-name: cache-newIDE-app-node_modules
|
||||
with:
|
||||
# npm cache files are stored in `~/.npm` on Linux/macOS
|
||||
path: ~/.npm
|
||||
key: ${{ runner.os }}-${{ env.cache-name }}-${{ hashFiles('newIDE/app/package-lock.json') }}
|
||||
|
||||
- name: Install newIDE dependencies
|
||||
run: npm install
|
||||
working-directory: newIDE/app
|
||||
|
14
.github/workflows/extract-translations.yml
vendored
14
.github/workflows/extract-translations.yml
vendored
@@ -11,20 +11,12 @@ jobs:
|
||||
extract-translations:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
# Cache npm dependencies to speed up the workflow
|
||||
- name: Cache node modules
|
||||
uses: actions/cache@v2
|
||||
env:
|
||||
cache-name: cache-newIDE-app-node_modules
|
||||
with:
|
||||
# npm cache files are stored in `~/.npm` on Linux/macOS
|
||||
path: ~/.npm
|
||||
key: ${{ runner.os }}-${{ env.cache-name }}-${{ hashFiles('newIDE/app/package-lock.json') }}
|
||||
cache: 'npm'
|
||||
cache-dependency-path: 'newIDE/app/package-lock.json'
|
||||
|
||||
- name: Install gettext
|
||||
run: sudo apt update && sudo apt install gettext -y
|
||||
|
42
.github/workflows/issues.yml
vendored
42
.github/workflows/issues.yml
vendored
@@ -3,41 +3,17 @@ on:
|
||||
issues:
|
||||
types: [opened]
|
||||
jobs:
|
||||
autoclose:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Autoclose issues about adding a bug without changing the bug report template
|
||||
uses: arkon/issue-closer-action@v1.1
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
type: "body"
|
||||
regex: ".*Scroll down to '\\.\\.\\.\\.'.*"
|
||||
message: "Hi @${issue.user.login}! 👋 This issue was automatically closed because it seems that you have not included any steps to reproduce the bug.\n\nGitHub is a place for the technical development of GDevelop itself - you may want to go on the [forum](https://forum.gdevelop.io/), the Discord chat or [read the documentation](https://wiki.gdevelop.io/gdevelop5/start) to learn more about GDevelop. Thanks!"
|
||||
- name: Autoclose known beta 105 web-app update bug
|
||||
uses: arkon/issue-closer-action@v1.1
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
type: "body"
|
||||
regex: ".*_instance.getRawFloatProperty is not a function.*"
|
||||
message: "Hi @${issue.user.login}! 👋 This issue was automatically closed as this seems to be a known bug. It can be solved by **closing entirely the web-app and opening it again**. This will allow the web-app to auto-update and the problem should be gone."
|
||||
- name: Autoclose known beta 114 web-app update bug
|
||||
uses: arkon/issue-closer-action@v1.1
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
type: "body"
|
||||
regex: ".*getAssociatedSettings is not a function.*"
|
||||
message: "Hi @${issue.user.login}! 👋 This issue was automatically closed as this seems to be a known bug. It can be solved by **closing entirely the web-app and opening it again**. This will allow the web-app to auto-update and the problem should be gone."
|
||||
autocomment:
|
||||
runs-on: ubuntu-latest
|
||||
if: contains(github.event.issue.body, 'The node to be removed is not a child of this node')
|
||||
steps:
|
||||
- name: Autocomment indications on bug if it looks like #3453
|
||||
uses: peter-evans/create-or-update-comment@v1
|
||||
with:
|
||||
issue-number: ${{ github.event.issue.number }}
|
||||
body: |
|
||||
Hi @${{ github.actor }}!
|
||||
Thank you for taking the time to open an issue.
|
||||
- name: Autocomment indications on bug if it looks like #3453
|
||||
uses: peter-evans/create-or-update-comment@v3
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
issue-number: ${{ github.event.issue.number }}
|
||||
body: |
|
||||
Hi @${{ github.actor }}!
|
||||
Thank you for taking the time to open an issue.
|
||||
|
||||
The solved issue #3453 mentioned a similar error, maybe it could help fix this new issue.
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
The solved issue #3453 mentioned a similar error, maybe it could help fix this new issue.
|
||||
|
68
.github/workflows/pull-requests.yml
vendored
68
.github/workflows/pull-requests.yml
vendored
@@ -1,29 +1,53 @@
|
||||
name: GDevelop Issues automatic workflow
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened]
|
||||
types:
|
||||
- opened
|
||||
- reopened
|
||||
- synchronize
|
||||
jobs:
|
||||
read-locales-metadata:
|
||||
if: contains(github.event.pull_request.title, '[Auto PR] Update translations')
|
||||
if: github.event.pull_request.title == '[Auto PR] Update translations'
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
COMMENT_TITLE: "Translation ratio changes"
|
||||
steps:
|
||||
- name: Read and format locales metadata
|
||||
run: |
|
||||
LANS=($(git diff HEAD^ HEAD --unified=5 newIDE/app/src/locales/LocalesMetadata.js | tail +6 | grep -E "^\s+\"languageName" | sed -E "s/^ *\"languageName\": \"//g" | sed -E "s/\",//g" | sed -E "s/ /_/g"))
|
||||
ADDS=($(git diff HEAD^ HEAD --unified=0 newIDE/app/src/locales/LocalesMetadata.js | tail +6 | grep -E "^\+\s*\"translationRatio\"" | sed -E "s/^\+ *\"translationRatio\": //g"))
|
||||
SUBS=($(git diff HEAD^ HEAD --unified=0 newIDE/app/src/locales/LocalesMetadata.js | tail +6 | grep -E "^\-\s*\"translationRatio\"" | sed -E "s/^\- *\"translationRatio\": //g"))
|
||||
touch sumup.txt
|
||||
for index in ${!ADDS[@]}; do
|
||||
echo ${LANS[index]} | sed -E "s/_/ /g" >> sumup.txt
|
||||
DELTA=$(bc <<< "scale=2;(${ADDS[index]}-${SUBS[index]})*100/1")
|
||||
echo $DELTA % >> sumup.txt
|
||||
done
|
||||
- name: Store sumup in outputs
|
||||
id: sumup
|
||||
run: echo "::set-output name=sumupFileContent::$(cat sumup.txt)"
|
||||
- name: Autocomment pull request with sumup
|
||||
uses: peter-evans/create-or-update-comment@v1
|
||||
with:
|
||||
issue-number: ${{ github.event.number }}
|
||||
body: ${{ steps.sumup.outputs.sumupFileContent}}
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Read and format locales metadata
|
||||
env:
|
||||
BASE: ${{ github.event.pull_request.base.sha }}
|
||||
HEAD: ${{ github.event.pull_request.head.sha }}
|
||||
run: |
|
||||
LANS=($(git diff $BASE...$HEAD -- newIDE/app/src/locales/LocalesMetadata.js | grep -E "^\s+\"languageName" | sed -E "s/^ *\"languageName\": \"//g" | sed -E "s/\",//g" | sed -E "s/ /_/g"))
|
||||
ADDS=($(git diff $BASE...$HEAD -- newIDE/app/src/locales/LocalesMetadata.js | grep -E "^\+\s*\"translationRatio\"" | sed -E "s/^\+ *\"translationRatio\": //g"))
|
||||
SUBS=($(git diff $BASE...$HEAD -- newIDE/app/src/locales/LocalesMetadata.js | grep -E "^\-\s*\"translationRatio\"" | sed -E "s/^\- *\"translationRatio\": //g"))
|
||||
touch sumup.md
|
||||
echo "## $COMMENT_TITLE" >> sumup.md
|
||||
echo "" >> sumup.md
|
||||
echo "| Language | Change |" >> sumup.md
|
||||
echo "| --- | --- |" >> sumup.md
|
||||
for index in ${!ADDS[@]}; do
|
||||
DELTA=$(echo "scale=3; (${ADDS[index]} - ${SUBS[index]})*100/1" | bc)
|
||||
if (( $(echo "$DELTA == 0" | bc -l) )); then
|
||||
continue
|
||||
fi
|
||||
LANGUAGE=${LANS[index]//_/ }
|
||||
echo "| $LANGUAGE | $(printf "%1.3f" $DELTA) % |" >> sumup.md
|
||||
done
|
||||
- name: Find Comment
|
||||
uses: peter-evans/find-comment@v2
|
||||
id: fc
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
issue-number: ${{ github.event.number }}
|
||||
body-includes: ${{ env.COMMENT_TITLE }}
|
||||
- name: Autocomment pull request with sumup
|
||||
uses: peter-evans/create-or-update-comment@v3
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
issue-number: ${{ github.event.number }}
|
||||
comment-id: ${{ steps.fc.outputs.comment-id }}
|
||||
edit-mode: replace
|
||||
body-path: "sumup.md"
|
||||
|
16
.github/workflows/update-translations.yml
vendored
16
.github/workflows/update-translations.yml
vendored
@@ -14,20 +14,12 @@ jobs:
|
||||
update-translations:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
# Cache npm dependencies to speed up the workflow
|
||||
- name: Cache node modules
|
||||
uses: actions/cache@v2
|
||||
env:
|
||||
cache-name: cache-newIDE-app-node_modules
|
||||
with:
|
||||
# npm cache files are stored in `~/.npm` on Linux/macOS
|
||||
path: ~/.npm
|
||||
key: ${{ runner.os }}-${{ env.cache-name }}-${{ hashFiles('newIDE/app/package-lock.json') }}
|
||||
cache: 'npm'
|
||||
cache-dependency-path: 'newIDE/app/package-lock.json'
|
||||
|
||||
- name: Install gettext
|
||||
run: sudo apt update && sudo apt install gettext -y
|
||||
@@ -64,7 +56,7 @@ jobs:
|
||||
working-directory: newIDE/app
|
||||
|
||||
- name: Create a Pull Request with the changes
|
||||
uses: peter-evans/create-pull-request@v3.10.1
|
||||
uses: peter-evans/create-pull-request@v5
|
||||
with:
|
||||
commit-message: Update translations [skip ci]
|
||||
branch: chore/update-translations
|
||||
|
4
.vscode/settings.json
vendored
4
.vscode/settings.json
vendored
@@ -127,5 +127,7 @@
|
||||
"flow.useNPMPackagedFlow": true,
|
||||
|
||||
// Clang format styling (duplicated in scripts/CMakeClangUtils.txt)
|
||||
"C_Cpp.clang_format_style": "{BasedOnStyle: Google, BinPackParameters: false, BinPackArguments: false}"
|
||||
"C_Cpp.clang_format_style": "{BasedOnStyle: Google, BinPackParameters: false, BinPackArguments: false}",
|
||||
"prettier.prettierPath": "./GDJS/node_modules/prettier",
|
||||
"prettier.configPath": "./GDJS/.prettierrc"
|
||||
}
|
||||
|
@@ -38,7 +38,7 @@ void CommentEvent::SerializeTo(SerializerElement &element) const {
|
||||
.SetAttribute("textB", textB);
|
||||
|
||||
element.AddChild("comment").SetValue(com1);
|
||||
element.AddChild("comment2").SetValue(com2);
|
||||
if (!com2.empty()) element.AddChild("comment2").SetValue(com2);
|
||||
}
|
||||
|
||||
void CommentEvent::UnserializeFrom(gd::Project &project,
|
||||
@@ -53,7 +53,9 @@ void CommentEvent::UnserializeFrom(gd::Project &project,
|
||||
textB = colorElement.GetIntAttribute("textB");
|
||||
|
||||
com1 = element.GetChild("comment", 0, "Com1").GetValue().GetString();
|
||||
com2 = element.GetChild("comment2", 0, "Com2").GetValue().GetString();
|
||||
if (element.HasChild("comment2")) {
|
||||
com2 = element.GetChild("comment2", 0, "Com2").GetValue().GetString();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -1019,15 +1019,15 @@ gd::String EventsCodeGenerator::GenerateFreeCondition(
|
||||
bool conditionInverted,
|
||||
gd::EventsCodeGenerationContext& context) {
|
||||
// Generate call
|
||||
gd::String predicat;
|
||||
gd::String predicate;
|
||||
if (instrInfos.codeExtraInformation.type == "number" ||
|
||||
instrInfos.codeExtraInformation.type == "string") {
|
||||
predicat = GenerateRelationalOperatorCall(
|
||||
predicate = GenerateRelationalOperatorCall(
|
||||
instrInfos,
|
||||
arguments,
|
||||
instrInfos.codeExtraInformation.functionCallName);
|
||||
} else {
|
||||
predicat = instrInfos.codeExtraInformation.functionCallName + "(" +
|
||||
predicate = instrInfos.codeExtraInformation.functionCallName + "(" +
|
||||
GenerateArgumentsList(arguments, 0) + ")";
|
||||
}
|
||||
|
||||
@@ -1040,10 +1040,10 @@ gd::String EventsCodeGenerator::GenerateFreeCondition(
|
||||
conditionAlreadyTakeCareOfInversion = true;
|
||||
}
|
||||
if (!conditionAlreadyTakeCareOfInversion && conditionInverted)
|
||||
predicat = GenerateNegatedPredicat(predicat);
|
||||
predicate = GenerateNegatedPredicate(predicate);
|
||||
|
||||
// Generate condition code
|
||||
return returnBoolean + " = " + predicat + ";\n";
|
||||
return returnBoolean + " = " + predicate + ";\n";
|
||||
}
|
||||
|
||||
gd::String EventsCodeGenerator::GenerateObjectCondition(
|
||||
@@ -1065,18 +1065,18 @@ gd::String EventsCodeGenerator::GenerateObjectCondition(
|
||||
instrInfos.codeExtraInformation.functionCallName;
|
||||
|
||||
// Create call
|
||||
gd::String predicat;
|
||||
gd::String predicate;
|
||||
if ((instrInfos.codeExtraInformation.type == "number" ||
|
||||
instrInfos.codeExtraInformation.type == "string")) {
|
||||
predicat = GenerateRelationalOperatorCall(
|
||||
predicate = GenerateRelationalOperatorCall(
|
||||
instrInfos, arguments, objectFunctionCallNamePart, 1);
|
||||
} else {
|
||||
predicat = objectFunctionCallNamePart + "(" +
|
||||
predicate = objectFunctionCallNamePart + "(" +
|
||||
GenerateArgumentsList(arguments, 1) + ")";
|
||||
}
|
||||
if (conditionInverted) predicat = GenerateNegatedPredicat(predicat);
|
||||
if (conditionInverted) predicate = GenerateNegatedPredicate(predicate);
|
||||
|
||||
return "For each picked object \"" + objectName + "\", check " + predicat +
|
||||
return "For each picked object \"" + objectName + "\", check " + predicate +
|
||||
".\n";
|
||||
}
|
||||
|
||||
@@ -1090,16 +1090,16 @@ gd::String EventsCodeGenerator::GenerateBehaviorCondition(
|
||||
bool conditionInverted,
|
||||
gd::EventsCodeGenerationContext& context) {
|
||||
// Create call
|
||||
gd::String predicat;
|
||||
gd::String predicate;
|
||||
if ((instrInfos.codeExtraInformation.type == "number" ||
|
||||
instrInfos.codeExtraInformation.type == "string")) {
|
||||
predicat = GenerateRelationalOperatorCall(instrInfos, arguments, "", 2);
|
||||
predicate = GenerateRelationalOperatorCall(instrInfos, arguments, "", 2);
|
||||
} else {
|
||||
predicat = "(" + GenerateArgumentsList(arguments, 2) + ")";
|
||||
predicate = "(" + GenerateArgumentsList(arguments, 2) + ")";
|
||||
}
|
||||
if (conditionInverted) predicat = GenerateNegatedPredicat(predicat);
|
||||
if (conditionInverted) predicate = GenerateNegatedPredicate(predicate);
|
||||
|
||||
return "For each picked object \"" + objectName + "\", check " + predicat +
|
||||
return "For each picked object \"" + objectName + "\", check " + predicate +
|
||||
" for behavior \"" + behaviorName + "\".\n";
|
||||
}
|
||||
|
||||
|
@@ -668,13 +668,13 @@ class GD_CORE_API EventsCodeGenerator {
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Must negate a predicat.
|
||||
* \brief Must negate a predicate.
|
||||
*
|
||||
* The default implementation generates C-style code : It wraps the predicat
|
||||
* The default implementation generates C-style code : It wraps the predicate
|
||||
* inside parenthesis and add a !.
|
||||
*/
|
||||
virtual gd::String GenerateNegatedPredicat(const gd::String& predicat) const {
|
||||
return "!(" + predicat + ")";
|
||||
virtual gd::String GenerateNegatedPredicate(const gd::String& predicate) const {
|
||||
return "!(" + predicate + ")";
|
||||
};
|
||||
|
||||
virtual gd::String GenerateFreeCondition(
|
||||
|
@@ -66,6 +66,11 @@ class GD_CORE_API ReadOnlyEventVisitor {
|
||||
* Note that VisitEvent is also called with this event.
|
||||
*/
|
||||
virtual void VisitLinkEvent(const gd::LinkEvent& linkEvent) = 0;
|
||||
|
||||
/**
|
||||
* @brief Abort the iteration on the events.
|
||||
*/
|
||||
virtual void StopAnyEventIteration() = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
#include "EventsList.h"
|
||||
|
||||
#include "GDCore/Events/Event.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Tools/Log.h"
|
||||
@@ -100,9 +101,8 @@ bool EventsList::Contains(const gd::BaseEvent& eventToSearch,
|
||||
}
|
||||
|
||||
bool EventsList::MoveEventToAnotherEventsList(const gd::BaseEvent& eventToMove,
|
||||
gd::EventsList& newEventsList,
|
||||
std::size_t newPosition) {
|
||||
|
||||
gd::EventsList& newEventsList,
|
||||
std::size_t newPosition) {
|
||||
for (std::size_t i = 0; i < GetEventsCount(); ++i) {
|
||||
if (events[i].get() == &eventToMove) {
|
||||
std::shared_ptr<BaseEvent> event = events[i];
|
||||
|
@@ -69,12 +69,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsFileExtension(
|
||||
extension
|
||||
.AddAction(
|
||||
"EcrireFichierExp",
|
||||
_("Write a value"),
|
||||
_("Write the result of the expression in the stored data, in the "
|
||||
_("Save a value"),
|
||||
_("Save the result of the expression in the stored data, in the "
|
||||
"specified element.\nSpecify the structure leading to the "
|
||||
"element using / (example : Root/Level/Current)\nSpaces are "
|
||||
"forbidden in element names."),
|
||||
_("Write _PARAM2_ in _PARAM1_ of storage _PARAM0_"),
|
||||
_("Save _PARAM2_ in _PARAM1_ of storage _PARAM0_"),
|
||||
"",
|
||||
"res/actions/fichier24.png",
|
||||
"res/actions/fichier.png")
|
||||
@@ -85,12 +85,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsFileExtension(
|
||||
extension
|
||||
.AddAction(
|
||||
"EcrireFichierTxt",
|
||||
_("Write a text"),
|
||||
_("Write the text in the specified storage, in the specified "
|
||||
_("Save a text"),
|
||||
_("Save the text in the specified storage, in the specified "
|
||||
"element.\nSpecify "
|
||||
"the structure leading to the element using / (example : "
|
||||
"Root/Level/Current)\nSpaces are forbidden in element names."),
|
||||
_("Write _PARAM2_ in _PARAM1_ of storage _PARAM0_"),
|
||||
_("Save _PARAM2_ in _PARAM1_ of storage _PARAM0_"),
|
||||
"",
|
||||
"res/actions/fichier24.png",
|
||||
"res/actions/fichier.png")
|
||||
@@ -101,13 +101,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsFileExtension(
|
||||
extension
|
||||
.AddAction(
|
||||
"LireFichierExp",
|
||||
_("Read a value"),
|
||||
_("Read the value saved in the specified element and store it in a "
|
||||
_("Load a value"),
|
||||
_("Load the value saved in the specified element and store it in a "
|
||||
"scene "
|
||||
"variable.\nSpecify the structure leading to the element using / "
|
||||
"(example : Root/Level/Current)\nSpaces are forbidden in element "
|
||||
"names."),
|
||||
_("Read _PARAM1_ from storage _PARAM0_ and store value in _PARAM3_"),
|
||||
_("Load _PARAM1_ from storage _PARAM0_ and store value in _PARAM3_"),
|
||||
"",
|
||||
"res/actions/fichier24.png",
|
||||
"res/actions/fichier.png")
|
||||
@@ -119,13 +119,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsFileExtension(
|
||||
extension
|
||||
.AddAction(
|
||||
"LireFichierTxt",
|
||||
_("Read a text"),
|
||||
_("Read the text saved in the specified element and store it in a "
|
||||
_("Load a text"),
|
||||
_("Load the text saved in the specified element and store it in a "
|
||||
"scene "
|
||||
"variable.\nSpecify the structure leading to the element using / "
|
||||
"(example : Root/Level/Current)\nSpaces are forbidden in element "
|
||||
"names."),
|
||||
_("Read _PARAM1_ from storage _PARAM0_ and store as text in "
|
||||
_("Load _PARAM1_ from storage _PARAM0_ and store as text in "
|
||||
"_PARAM3_"),
|
||||
"",
|
||||
"res/actions/fichier24.png",
|
||||
|
@@ -54,6 +54,19 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSceneExtension(
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.MarkAsSimple();
|
||||
|
||||
extension
|
||||
.AddCondition("DoesSceneExist",
|
||||
_("Does scene exist"),
|
||||
_("Check if scene exists."),
|
||||
_("Scene _PARAM1_ exists"),
|
||||
"",
|
||||
"res/actions/texte.png",
|
||||
"res/actions/texte.png")
|
||||
.SetHelpPath("/interface/scene-editor/events")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("sceneName", _("Name of the scene to check"))
|
||||
.MarkAsSimple();
|
||||
|
||||
extension
|
||||
.AddAction("Scene",
|
||||
_("Change the scene"),
|
||||
|
@@ -287,7 +287,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
|
||||
obj.AddCondition("AnimationName",
|
||||
_("Current animation name"),
|
||||
_("Check the animation by played by the object."),
|
||||
_("Check the animation played by the object."),
|
||||
_("The animation of _PARAM0_ is _PARAM1_"),
|
||||
_("Animations and images"),
|
||||
"res/conditions/animation24.png",
|
||||
|
@@ -172,7 +172,7 @@ BuiltinExtensionsImplementer::ImplementsStringInstructionsExtension(
|
||||
_("Search the last occurrence in a text, starting from a position"),
|
||||
_("Search in a text the last occurrence, starting from a position "
|
||||
"(return "
|
||||
" the position of the result, from the beginning of the string, or "
|
||||
"the position of the result, from the beginning of the string, or "
|
||||
"-1 if not found)"),
|
||||
"",
|
||||
"res/conditions/toujours24_black.png")
|
||||
|
@@ -135,11 +135,11 @@ MetadataProvider::GetExtensionAndConditionMetadata(const gd::Platform& platform,
|
||||
|
||||
const auto& objects = extension->GetExtensionObjectsTypes();
|
||||
for (const gd::String& extObjectType : objects) {
|
||||
const auto& allObjetsConditions =
|
||||
const auto& allObjectsConditions =
|
||||
extension->GetAllConditionsForObject(extObjectType);
|
||||
if (allObjetsConditions.find(conditionType) != allObjetsConditions.end())
|
||||
if (allObjectsConditions.find(conditionType) != allObjectsConditions.end())
|
||||
return ExtensionAndMetadata<InstructionMetadata>(
|
||||
*extension, allObjetsConditions.find(conditionType)->second);
|
||||
*extension, allObjectsConditions.find(conditionType)->second);
|
||||
}
|
||||
|
||||
const auto& autos = extension->GetBehaviorsTypes();
|
||||
|
@@ -84,6 +84,9 @@ void ReadOnlyArbitraryEventsWorker::VisitEventList(const gd::EventsList& events)
|
||||
DoVisitEventList(events);
|
||||
|
||||
for (std::size_t i = 0; i < events.size(); ++i) {
|
||||
if (shouldStopIteration) {
|
||||
break;
|
||||
}
|
||||
events[i].AcceptVisitor(*this);
|
||||
|
||||
if (events[i].CanHaveSubEvents()) {
|
||||
@@ -98,11 +101,17 @@ void ReadOnlyArbitraryEventsWorker::VisitEvent(const gd::BaseEvent& event) {
|
||||
const vector<const gd::InstructionsList*> conditionsVectors =
|
||||
event.GetAllConditionsVectors();
|
||||
for (std::size_t j = 0; j < conditionsVectors.size(); ++j) {
|
||||
if (shouldStopIteration) {
|
||||
break;
|
||||
}
|
||||
VisitInstructionList(*conditionsVectors[j], true);
|
||||
}
|
||||
|
||||
const vector<const gd::InstructionsList*> actionsVectors = event.GetAllActionsVectors();
|
||||
for (std::size_t j = 0; j < actionsVectors.size(); ++j) {
|
||||
if (shouldStopIteration) {
|
||||
break;
|
||||
}
|
||||
VisitInstructionList(*actionsVectors[j], false);
|
||||
}
|
||||
}
|
||||
@@ -116,6 +125,9 @@ void ReadOnlyArbitraryEventsWorker::VisitInstructionList(
|
||||
DoVisitInstructionList(instructions, areConditions);
|
||||
|
||||
for (std::size_t i = 0; i < instructions.size(); ++i) {
|
||||
if (shouldStopIteration) {
|
||||
break;
|
||||
}
|
||||
VisitInstruction(instructions[i], areConditions);
|
||||
if (!instructions[i].GetSubInstructions().empty()) {
|
||||
VisitInstructionList(instructions[i].GetSubInstructions(),
|
||||
@@ -129,6 +141,10 @@ void ReadOnlyArbitraryEventsWorker::VisitInstruction(const gd::Instruction& inst
|
||||
DoVisitInstruction(instruction, isCondition);
|
||||
}
|
||||
|
||||
void ReadOnlyArbitraryEventsWorker::StopAnyEventIteration() {
|
||||
shouldStopIteration = true;
|
||||
}
|
||||
|
||||
ReadOnlyArbitraryEventsWorkerWithContext::~ReadOnlyArbitraryEventsWorkerWithContext() {}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -144,7 +144,7 @@ class GD_CORE_API ArbitraryEventsWorkerWithContext
|
||||
*/
|
||||
class GD_CORE_API ReadOnlyArbitraryEventsWorker : private ReadOnlyEventVisitor {
|
||||
public:
|
||||
ReadOnlyArbitraryEventsWorker(){};
|
||||
ReadOnlyArbitraryEventsWorker() : shouldStopIteration(false) {};
|
||||
virtual ~ReadOnlyArbitraryEventsWorker();
|
||||
|
||||
/**
|
||||
@@ -152,6 +152,9 @@ class GD_CORE_API ReadOnlyArbitraryEventsWorker : private ReadOnlyEventVisitor {
|
||||
*/
|
||||
void Launch(const gd::EventsList& events) { VisitEventList(events); };
|
||||
|
||||
protected:
|
||||
void StopAnyEventIteration() override;
|
||||
|
||||
private:
|
||||
void VisitEventList(const gd::EventsList& events);
|
||||
void VisitEvent(const gd::BaseEvent& event) override;
|
||||
@@ -188,6 +191,8 @@ class GD_CORE_API ReadOnlyArbitraryEventsWorker : private ReadOnlyEventVisitor {
|
||||
*/
|
||||
virtual void DoVisitInstruction(const gd::Instruction& instruction,
|
||||
bool isCondition) {};
|
||||
|
||||
bool shouldStopIteration;
|
||||
};
|
||||
|
||||
/**
|
||||
|
175
Core/GDCore/IDE/Events/EventsFunctionSelfCallChecker.cpp
Normal file
175
Core/GDCore/IDE/Events/EventsFunctionSelfCallChecker.cpp
Normal file
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "EventsFunctionSelfCallChecker.h"
|
||||
|
||||
#include "GDCore/Events/Expression.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2Node.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
|
||||
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
#include "GDCore/Extensions/Metadata/ParameterMetadataTools.h"
|
||||
#include "GDCore/Extensions/PlatformExtension.h"
|
||||
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
|
||||
#include "GDCore/Project/EventsBasedBehavior.h"
|
||||
#include "GDCore/Project/EventsBasedObject.h"
|
||||
#include "GDCore/Project/EventsFunction.h"
|
||||
#include "GDCore/Project/EventsFunctionsExtension.h"
|
||||
#include "GDCore/Project/Object.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/String.h"
|
||||
#include "GDCore/Tools/Log.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief Check the type of the first condition or action.
|
||||
*/
|
||||
class GD_CORE_API FirstInstructionTypeChecker
|
||||
: public ReadOnlyArbitraryEventsWorker {
|
||||
public:
|
||||
FirstInstructionTypeChecker(const gd::String &eventFunctionType_,
|
||||
const bool isEventFunctionCondition_)
|
||||
: eventFunctionType(eventFunctionType_),
|
||||
isEventFunctionCondition(isEventFunctionCondition_),
|
||||
isOnlyCallingItself(false){};
|
||||
virtual ~FirstInstructionTypeChecker(){};
|
||||
|
||||
void DoVisitInstruction(const gd::Instruction &instruction,
|
||||
bool isCondition) override {
|
||||
if (isCondition == isEventFunctionCondition) {
|
||||
isOnlyCallingItself = instruction.GetType() == eventFunctionType;
|
||||
StopAnyEventIteration();
|
||||
}
|
||||
};
|
||||
|
||||
bool isOnlyCallingItself;
|
||||
|
||||
private:
|
||||
gd::String eventFunctionType;
|
||||
bool isEventFunctionCondition;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Check the type of the first condition or action.
|
||||
*/
|
||||
class GD_CORE_API FirstActionExpressionTypeChecker
|
||||
: public ReadOnlyArbitraryEventsWorker,
|
||||
ExpressionParser2NodeWorker {
|
||||
public:
|
||||
FirstActionExpressionTypeChecker(const gd::Platform &platform_,
|
||||
const gd::String &eventFunctionType_)
|
||||
: platform(platform_), eventFunctionType(eventFunctionType_),
|
||||
isOnlyCallingItself(false){};
|
||||
virtual ~FirstActionExpressionTypeChecker(){};
|
||||
|
||||
void DoVisitInstruction(const gd::Instruction &instruction,
|
||||
bool isCondition) override {
|
||||
// Typically, it should be a "return" action.
|
||||
if (!isCondition) {
|
||||
gd::String lastObjectParameter = "";
|
||||
const gd::InstructionMetadata &instrInfos =
|
||||
MetadataProvider::GetActionMetadata(platform, instruction.GetType());
|
||||
for (std::size_t pNb = 0; pNb < instrInfos.parameters.size(); ++pNb) {
|
||||
|
||||
if (ParameterMetadata::IsExpression(
|
||||
"number", instrInfos.parameters[pNb].GetType()) ||
|
||||
ParameterMetadata::IsExpression(
|
||||
"string", instrInfos.parameters[pNb].GetType())) {
|
||||
auto node = instruction.GetParameter(pNb).GetRootNode();
|
||||
node->Visit(*this);
|
||||
}
|
||||
}
|
||||
StopAnyEventIteration();
|
||||
}
|
||||
}
|
||||
|
||||
// Only check expressions that directly calls a function.
|
||||
void OnVisitFunctionCallNode(FunctionCallNode &node) override {
|
||||
isOnlyCallingItself |= node.functionName == eventFunctionType;
|
||||
}
|
||||
|
||||
// Handle extra parenthesis.
|
||||
void OnVisitSubExpressionNode(SubExpressionNode &node) override {
|
||||
node.expression->Visit(*this);
|
||||
}
|
||||
void OnVisitOperatorNode(OperatorNode &node) override {}
|
||||
// Handle sign that could have been forgotten
|
||||
void OnVisitUnaryOperatorNode(UnaryOperatorNode &node) override {
|
||||
node.factor->Visit(*this);
|
||||
}
|
||||
void OnVisitNumberNode(NumberNode &node) override {}
|
||||
void OnVisitTextNode(TextNode &node) override {}
|
||||
void OnVisitVariableNode(VariableNode &node) override {}
|
||||
void OnVisitVariableAccessorNode(VariableAccessorNode &node) override {}
|
||||
void OnVisitVariableBracketAccessorNode(
|
||||
VariableBracketAccessorNode &node) override {}
|
||||
void OnVisitIdentifierNode(IdentifierNode &node) override {}
|
||||
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode &node) override {}
|
||||
void OnVisitEmptyNode(EmptyNode &node) override {}
|
||||
|
||||
bool isOnlyCallingItself;
|
||||
|
||||
private:
|
||||
const gd::Platform &platform;
|
||||
gd::String eventFunctionType;
|
||||
};
|
||||
|
||||
bool EventsFunctionSelfCallChecker::IsOnlyCallingItself(
|
||||
const gd::Project &project, const gd::String &functionFullType,
|
||||
const gd::EventsFunction &eventsFunction) {
|
||||
bool isOnlyCallingItself = false;
|
||||
|
||||
if (eventsFunction.IsExpression()) {
|
||||
FirstActionExpressionTypeChecker eventWorker(project.GetCurrentPlatform(),
|
||||
functionFullType);
|
||||
eventWorker.Launch(eventsFunction.GetEvents());
|
||||
isOnlyCallingItself = eventWorker.isOnlyCallingItself;
|
||||
} else {
|
||||
FirstInstructionTypeChecker eventWorker(functionFullType,
|
||||
!eventsFunction.IsAction());
|
||||
eventWorker.Launch(eventsFunction.GetEvents());
|
||||
isOnlyCallingItself = eventWorker.isOnlyCallingItself;
|
||||
}
|
||||
return isOnlyCallingItself;
|
||||
}
|
||||
|
||||
bool EventsFunctionSelfCallChecker::IsFreeFunctionOnlyCallingItself(
|
||||
const gd::Project &project,
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
const gd::EventsFunction &eventsFunction) {
|
||||
return IsOnlyCallingItself(
|
||||
project,
|
||||
PlatformExtension::GetEventsFunctionFullType(
|
||||
eventsFunctionsExtension.GetName(), eventsFunction.GetName()),
|
||||
eventsFunction);
|
||||
}
|
||||
|
||||
bool EventsFunctionSelfCallChecker::IsBehaviorFunctionOnlyCallingItself(
|
||||
const gd::Project &project,
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
const gd::EventsBasedBehavior &eventsBasedBehavior,
|
||||
const gd::EventsFunction &eventsFunction) {
|
||||
return IsOnlyCallingItself(
|
||||
project,
|
||||
PlatformExtension::GetBehaviorEventsFunctionFullType(
|
||||
eventsFunctionsExtension.GetName(), eventsBasedBehavior.GetName(),
|
||||
eventsFunction.GetName()),
|
||||
eventsFunction);
|
||||
}
|
||||
bool EventsFunctionSelfCallChecker::IsObjectFunctionOnlyCallingItself(
|
||||
const gd::Project &project,
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
const gd::EventsBasedObject &eventsBasedObject,
|
||||
const gd::EventsFunction &eventsFunction) {
|
||||
return IsOnlyCallingItself(project,
|
||||
PlatformExtension::GetObjectEventsFunctionFullType(
|
||||
eventsFunctionsExtension.GetName(),
|
||||
eventsBasedObject.GetName(),
|
||||
eventsFunction.GetName()),
|
||||
eventsFunction);
|
||||
}
|
||||
|
||||
} // namespace gd
|
64
Core/GDCore/IDE/Events/EventsFunctionSelfCallChecker.h
Normal file
64
Core/GDCore/IDE/Events/EventsFunctionSelfCallChecker.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "GDCore/String.h"
|
||||
#include <vector>
|
||||
namespace gd {
|
||||
class Project;
|
||||
class EventsFunctionsExtension;
|
||||
class EventsFunctionsContainer;
|
||||
class EventsFunction;
|
||||
class EventsBasedBehavior;
|
||||
class EventsBasedObject;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
/**
|
||||
* \brief Check if functions are only calling themselves.
|
||||
*
|
||||
* It allows to detect mistakes when implementing functions for compatibility
|
||||
* after a function renaming.
|
||||
* Infinite loops can happens when the legacy function call itself instead of
|
||||
* the new function.
|
||||
*
|
||||
* \note Only the first instruction or the expressions of the first action is
|
||||
* checked.
|
||||
*/
|
||||
class GD_CORE_API EventsFunctionSelfCallChecker {
|
||||
public:
|
||||
/**
|
||||
* \brief Check if a free function is only calling itself.
|
||||
*/
|
||||
static bool IsFreeFunctionOnlyCallingItself(
|
||||
const gd::Project &project,
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
const gd::EventsFunction &eventsFunction);
|
||||
|
||||
/**
|
||||
* \brief Check if a behavior function is only calling itself.
|
||||
*/
|
||||
static bool IsBehaviorFunctionOnlyCallingItself(
|
||||
const gd::Project &project,
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
const gd::EventsBasedBehavior &eventsBasedBehavior,
|
||||
const gd::EventsFunction &eventsFunction);
|
||||
|
||||
/**
|
||||
* \brief Check if an object function is only calling itself.
|
||||
*/
|
||||
static bool IsObjectFunctionOnlyCallingItself(
|
||||
const gd::Project &project,
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
const gd::EventsBasedObject &eventsBasedObject,
|
||||
const gd::EventsFunction &eventsFunction);
|
||||
|
||||
private:
|
||||
static bool IsOnlyCallingItself(const gd::Project &project,
|
||||
const gd::String &functionFullType,
|
||||
const gd::EventsFunction &eventsFunction);
|
||||
};
|
||||
} // namespace gd
|
@@ -642,7 +642,7 @@ std::vector<EventsSearchResult> EventsRefactorer::ReplaceStringInEvents(
|
||||
return modifiedEvents;
|
||||
}
|
||||
|
||||
gd::String ReplaceAllOccurencesCaseUnsensitive(gd::String context,
|
||||
gd::String ReplaceAllOccurrencesCaseInsensitive(gd::String context,
|
||||
gd::String from,
|
||||
const gd::String& to) {
|
||||
size_t lookHere = 0;
|
||||
@@ -673,7 +673,7 @@ bool EventsRefactorer::ReplaceStringInActions(gd::ObjectsContainer& project,
|
||||
matchCase
|
||||
? actions[aId].GetParameter(pNb).GetPlainString().FindAndReplace(
|
||||
toReplace, newString, true)
|
||||
: ReplaceAllOccurencesCaseUnsensitive(
|
||||
: ReplaceAllOccurrencesCaseInsensitive(
|
||||
actions[aId].GetParameter(pNb).GetPlainString(),
|
||||
toReplace,
|
||||
newString);
|
||||
@@ -713,7 +713,7 @@ bool EventsRefactorer::ReplaceStringInConditions(
|
||||
.GetParameter(pNb)
|
||||
.GetPlainString()
|
||||
.FindAndReplace(toReplace, newString, true)
|
||||
: ReplaceAllOccurencesCaseUnsensitive(
|
||||
: ReplaceAllOccurrencesCaseInsensitive(
|
||||
conditions[cId].GetParameter(pNb).GetPlainString(),
|
||||
toReplace,
|
||||
newString);
|
||||
@@ -749,7 +749,7 @@ bool EventsRefactorer::ReplaceStringInEventSearchableStrings(
|
||||
for (std::size_t sNb = 0; sNb < stringEvent.size(); ++sNb) {
|
||||
gd::String newStringEvent =
|
||||
matchCase ? stringEvent[sNb].FindAndReplace(toReplace, newString, true)
|
||||
: ReplaceAllOccurencesCaseUnsensitive(
|
||||
: ReplaceAllOccurrencesCaseInsensitive(
|
||||
stringEvent[sNb], toReplace, newString);
|
||||
newEventStrings.push_back(newStringEvent);
|
||||
}
|
||||
|
@@ -16,7 +16,7 @@ class EventsBasedObject;
|
||||
class AbstractEventsBasedEntity;
|
||||
class PropertyDescriptor;
|
||||
class NamedPropertyDescriptor;
|
||||
} // namespace gd
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
|
||||
@@ -24,22 +24,24 @@ namespace gd {
|
||||
* \brief Generate a getter and a setter functions for properties.
|
||||
*/
|
||||
class GD_CORE_API PropertyFunctionGenerator {
|
||||
public:
|
||||
public:
|
||||
/**
|
||||
* \brief Generate a getter and a setter for the given behavior property.
|
||||
*/
|
||||
static void GenerateBehaviorGetterAndSetter(
|
||||
gd::Project &project, gd::EventsFunctionsExtension &extension,
|
||||
gd::Project &project,
|
||||
gd::EventsFunctionsExtension &extension,
|
||||
gd::EventsBasedBehavior &eventsBasedBehavior,
|
||||
const gd::NamedPropertyDescriptor &property, bool isSharedProperties);
|
||||
const gd::NamedPropertyDescriptor &property,
|
||||
bool isSharedProperties);
|
||||
/**
|
||||
* \brief Generate a getter and a setter for the given object property.
|
||||
*/
|
||||
static void
|
||||
GenerateObjectGetterAndSetter(gd::Project &project,
|
||||
gd::EventsFunctionsExtension &extension,
|
||||
gd::EventsBasedObject &eventsBasedObject,
|
||||
const gd::NamedPropertyDescriptor &property);
|
||||
static void GenerateObjectGetterAndSetter(
|
||||
gd::Project &project,
|
||||
gd::EventsFunctionsExtension &extension,
|
||||
gd::EventsBasedObject &eventsBasedObject,
|
||||
const gd::NamedPropertyDescriptor &property);
|
||||
static bool CanGenerateGetterAndSetter(
|
||||
const gd::AbstractEventsBasedEntity &eventsBasedEntity,
|
||||
const gd::NamedPropertyDescriptor &property);
|
||||
@@ -50,23 +52,26 @@ public:
|
||||
static void GenerateConditionSkeleton(gd::Project &project,
|
||||
gd::EventsFunction &eventFunction);
|
||||
|
||||
~PropertyFunctionGenerator();
|
||||
~PropertyFunctionGenerator(){};
|
||||
|
||||
private:
|
||||
private:
|
||||
static void GenerateGetterAndSetter(
|
||||
gd::Project &project, gd::EventsFunctionsExtension &extension,
|
||||
gd::Project &project,
|
||||
gd::EventsFunctionsExtension &extension,
|
||||
gd::AbstractEventsBasedEntity &eventsBasedEntity,
|
||||
const gd::NamedPropertyDescriptor &property, const gd::String &objectType,
|
||||
bool isBehavior, bool isSharedProperties);
|
||||
const gd::NamedPropertyDescriptor &property,
|
||||
const gd::String &objectType,
|
||||
bool isBehavior,
|
||||
bool isSharedProperties);
|
||||
|
||||
static gd::String CapitalizeFirstLetter(const gd::String &string);
|
||||
static gd::String UnCapitalizeFirstLetter(const gd::String &string);
|
||||
static gd::String
|
||||
GetStringifiedExtraInfo(const gd::PropertyDescriptor &property);
|
||||
static gd::String GetStringifiedExtraInfo(
|
||||
const gd::PropertyDescriptor &property);
|
||||
|
||||
PropertyFunctionGenerator();
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_PROPERTYFUNCTIONGENERATOR_H
|
||||
#endif // GDCORE_PROPERTYFUNCTIONGENERATOR_H
|
||||
|
@@ -153,6 +153,8 @@ void CustomObjectConfiguration::ExposeResources(gd::ArbitraryResourceWorker& wor
|
||||
worker.ExposeTileset(newPropertyValue);
|
||||
} else if (resourceType == "bitmapFont") {
|
||||
worker.ExposeBitmapFont(newPropertyValue);
|
||||
} else if (resourceType == "model3D") {
|
||||
worker.ExposeModel3D(newPropertyValue);
|
||||
}
|
||||
|
||||
if (newPropertyValue != oldPropertyValue) {
|
||||
|
@@ -9,9 +9,9 @@
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Object.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Project/PropertyDescriptor.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
#include "GDCore/Tools/UUID/UUID.h"
|
||||
#include "GDCore/Project/PropertyDescriptor.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
@@ -21,12 +21,17 @@ InitialInstance::InitialInstance()
|
||||
: objectName(""),
|
||||
x(0),
|
||||
y(0),
|
||||
z(0),
|
||||
angle(0),
|
||||
rotationX(0),
|
||||
rotationY(0),
|
||||
zOrder(0),
|
||||
layer(""),
|
||||
personalizedSize(false),
|
||||
customSize(false),
|
||||
customDepth(false),
|
||||
width(0),
|
||||
height(0),
|
||||
depth(0),
|
||||
locked(false),
|
||||
sealed(false),
|
||||
persistentUuid(UUID::MakeUuid4()) {}
|
||||
@@ -35,11 +40,20 @@ void InitialInstance::UnserializeFrom(const SerializerElement& element) {
|
||||
SetObjectName(element.GetStringAttribute("name", "", "nom"));
|
||||
SetX(element.GetDoubleAttribute("x"));
|
||||
SetY(element.GetDoubleAttribute("y"));
|
||||
SetZ(element.GetDoubleAttribute("z", 0));
|
||||
SetAngle(element.GetDoubleAttribute("angle"));
|
||||
SetRotationX(element.GetDoubleAttribute("rotationX", 0));
|
||||
SetRotationY(element.GetDoubleAttribute("rotationY", 0));
|
||||
SetHasCustomSize(
|
||||
element.GetBoolAttribute("customSize", false, "personalizedSize"));
|
||||
SetCustomWidth(element.GetDoubleAttribute("width"));
|
||||
SetCustomHeight(element.GetDoubleAttribute("height"));
|
||||
if (element.HasChild("depth") || element.HasAttribute("depth")) {
|
||||
SetHasCustomDepth(true);
|
||||
SetCustomDepth(element.GetDoubleAttribute("depth"));
|
||||
} else {
|
||||
SetHasCustomDepth(false);
|
||||
}
|
||||
SetZOrder(element.GetIntAttribute("zOrder", 0, "plan"));
|
||||
SetLayer(element.GetStringAttribute("layer"));
|
||||
SetLocked(element.GetBoolAttribute("locked", false));
|
||||
@@ -53,9 +67,26 @@ void InitialInstance::UnserializeFrom(const SerializerElement& element) {
|
||||
element.GetChild("numberProperties", 0, "floatInfos");
|
||||
numberPropertiesElement.ConsiderAsArrayOf("property", "Info");
|
||||
for (std::size_t j = 0; j < numberPropertiesElement.GetChildrenCount(); ++j) {
|
||||
gd::String name = numberPropertiesElement.GetChild(j).GetStringAttribute("name");
|
||||
double value = numberPropertiesElement.GetChild(j).GetDoubleAttribute("value");
|
||||
numberProperties[name] = value;
|
||||
gd::String name =
|
||||
numberPropertiesElement.GetChild(j).GetStringAttribute("name");
|
||||
double value =
|
||||
numberPropertiesElement.GetChild(j).GetDoubleAttribute("value");
|
||||
|
||||
// Compatibility with GD <= 5.1.164
|
||||
if (name == "z") {
|
||||
SetZ(value);
|
||||
} else if (name == "rotationX") {
|
||||
SetRotationX(value);
|
||||
} else if (name == "rotationY") {
|
||||
SetRotationY(value);
|
||||
} else if (name == "depth") {
|
||||
SetHasCustomDepth(true);
|
||||
SetCustomDepth(value);
|
||||
}
|
||||
// end of compatibility code
|
||||
else {
|
||||
numberProperties[name] = value;
|
||||
}
|
||||
}
|
||||
|
||||
stringProperties.clear();
|
||||
@@ -77,21 +108,26 @@ void InitialInstance::SerializeTo(SerializerElement& element) const {
|
||||
element.SetAttribute("name", GetObjectName());
|
||||
element.SetAttribute("x", GetX());
|
||||
element.SetAttribute("y", GetY());
|
||||
if (GetZ() != 0) element.SetAttribute("z", GetZ());
|
||||
element.SetAttribute("zOrder", GetZOrder());
|
||||
element.SetAttribute("layer", GetLayer());
|
||||
element.SetAttribute("angle", GetAngle());
|
||||
if (GetRotationX() != 0) element.SetAttribute("rotationX", GetRotationX());
|
||||
if (GetRotationY() != 0) element.SetAttribute("rotationY", GetRotationY());
|
||||
element.SetAttribute("customSize", HasCustomSize());
|
||||
element.SetAttribute("width", GetCustomWidth());
|
||||
element.SetAttribute("height", GetCustomHeight());
|
||||
if (HasCustomDepth()) element.SetAttribute("depth", GetCustomDepth());
|
||||
if (IsLocked()) element.SetAttribute("locked", IsLocked());
|
||||
if (IsSealed()) element.SetAttribute("sealed", IsSealed());
|
||||
|
||||
if (persistentUuid.empty()) persistentUuid = UUID::MakeUuid4();
|
||||
element.SetStringAttribute("persistentUuid", persistentUuid);
|
||||
|
||||
SerializerElement& numberPropertiesElement = element.AddChild("numberProperties");
|
||||
SerializerElement& numberPropertiesElement =
|
||||
element.AddChild("numberProperties");
|
||||
numberPropertiesElement.ConsiderAsArrayOf("property");
|
||||
for (const auto& property: numberProperties) {
|
||||
for (const auto& property : numberProperties) {
|
||||
numberPropertiesElement.AddChild("property")
|
||||
.SetAttribute("name", property.first)
|
||||
.SetAttribute("value", property.second);
|
||||
@@ -99,7 +135,7 @@ void InitialInstance::SerializeTo(SerializerElement& element) const {
|
||||
|
||||
SerializerElement& stringPropElement = element.AddChild("stringProperties");
|
||||
stringPropElement.ConsiderAsArrayOf("property");
|
||||
for (const auto& property: stringProperties) {
|
||||
for (const auto& property : stringProperties) {
|
||||
stringPropElement.AddChild("property")
|
||||
.SetAttribute("name", property.first)
|
||||
.SetAttribute("value", property.second);
|
||||
@@ -117,10 +153,12 @@ std::map<gd::String, gd::PropertyDescriptor>
|
||||
InitialInstance::GetCustomProperties(gd::Project& project, gd::Layout& layout) {
|
||||
// Find an object
|
||||
if (layout.HasObjectNamed(GetObjectName()))
|
||||
return layout.GetObject(GetObjectName()).GetConfiguration()
|
||||
return layout.GetObject(GetObjectName())
|
||||
.GetConfiguration()
|
||||
.GetInitialInstanceProperties(*this, project, layout);
|
||||
else if (project.HasObjectNamed(GetObjectName()))
|
||||
return project.GetObject(GetObjectName()).GetConfiguration()
|
||||
return project.GetObject(GetObjectName())
|
||||
.GetConfiguration()
|
||||
.GetInitialInstanceProperties(*this, project, layout);
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor> nothing;
|
||||
@@ -132,10 +170,12 @@ bool InitialInstance::UpdateCustomProperty(const gd::String& name,
|
||||
gd::Project& project,
|
||||
gd::Layout& layout) {
|
||||
if (layout.HasObjectNamed(GetObjectName()))
|
||||
return layout.GetObject(GetObjectName()).GetConfiguration()
|
||||
return layout.GetObject(GetObjectName())
|
||||
.GetConfiguration()
|
||||
.UpdateInitialInstanceProperty(*this, name, value, project, layout);
|
||||
else if (project.HasObjectNamed(GetObjectName()))
|
||||
return project.GetObject(GetObjectName()).GetConfiguration()
|
||||
return project.GetObject(GetObjectName())
|
||||
.GetConfiguration()
|
||||
.UpdateInitialInstanceProperty(*this, name, value, project, layout);
|
||||
|
||||
return false;
|
||||
@@ -154,7 +194,8 @@ const gd::String& InitialInstance::GetRawStringProperty(
|
||||
return it != stringProperties.end() ? it->second : *badStringProperyValue;
|
||||
}
|
||||
|
||||
void InitialInstance::SetRawDoubleProperty(const gd::String& name, double value) {
|
||||
void InitialInstance::SetRawDoubleProperty(const gd::String& name,
|
||||
double value) {
|
||||
numberProperties[name] = value;
|
||||
}
|
||||
|
||||
|
@@ -73,22 +73,52 @@ class GD_CORE_API InitialInstance {
|
||||
void SetY(double y_) { y = y_; }
|
||||
|
||||
/**
|
||||
* \brief Get the rotation of the instance, in radians.
|
||||
* \brief Get the Z position of the instance
|
||||
*/
|
||||
double GetZ() const { return z; }
|
||||
|
||||
/**
|
||||
* \brief Set the Z position of the instance
|
||||
*/
|
||||
void SetZ(double z_) { z = z_; }
|
||||
|
||||
/**
|
||||
* \brief Get the rotation of the instance on Z axis, in radians.
|
||||
*/
|
||||
double GetAngle() const { return angle; }
|
||||
|
||||
/**
|
||||
* \brief Set the rotation of the instance, in radians.
|
||||
* \brief Set the rotation of the instance on Z axis, in radians.
|
||||
*/
|
||||
void SetAngle(double angle_) { angle = angle_; }
|
||||
|
||||
/**
|
||||
* \brief Get the Z order of the instance.
|
||||
* \brief Get the rotation of the instance on X axis, in radians.
|
||||
*/
|
||||
double GetRotationX() const { return rotationX; }
|
||||
|
||||
/**
|
||||
* \brief Set the rotation of the instance on X axis, in radians.
|
||||
*/
|
||||
void SetRotationX(double rotationX_) { rotationX = rotationX_; }
|
||||
|
||||
/**
|
||||
* \brief Get the rotation of the instance on Y axis, in radians.
|
||||
*/
|
||||
double GetRotationY() const { return rotationY; }
|
||||
|
||||
/**
|
||||
* \brief Set the rotation of the instance on Y axis, in radians.
|
||||
*/
|
||||
void SetRotationY(double rotationY_) { rotationY = rotationY_; }
|
||||
|
||||
/**
|
||||
* \brief Get the Z order of the instance (for a 2D object).
|
||||
*/
|
||||
int GetZOrder() const { return zOrder; }
|
||||
|
||||
/**
|
||||
* \brief Set the Z order of the instance.
|
||||
* \brief Set the Z order of the instance (for a 2D object).
|
||||
*/
|
||||
void SetZOrder(int zOrder_) { zOrder = zOrder_; }
|
||||
|
||||
@@ -103,29 +133,51 @@ class GD_CORE_API InitialInstance {
|
||||
void SetLayer(const gd::String& layer_) { layer = layer_; }
|
||||
|
||||
/**
|
||||
* \brief Return true if the instance has a size which is different from its
|
||||
* object default size.
|
||||
* \brief Return true if the instance has a width/height which is different from its
|
||||
* object default width/height. This is independent from `HasCustomDepth`.
|
||||
*
|
||||
* \see gd::Object
|
||||
*/
|
||||
bool HasCustomSize() const { return personalizedSize; }
|
||||
bool HasCustomSize() const { return customSize; }
|
||||
|
||||
/**
|
||||
* \brief Set whether the instance has a size which is different from its
|
||||
* object default size or not.
|
||||
* \brief Return true if the instance has a depth which is different from its
|
||||
* object default depth. This is independent from `HasCustomSize`.
|
||||
*
|
||||
* \param hasCustomSize true if the size is different from the object's
|
||||
* default size. \see gd::Object
|
||||
* \see gd::Object
|
||||
*/
|
||||
bool HasCustomDepth() const { return customDepth; }
|
||||
|
||||
/**
|
||||
* \brief Set whether the instance has a width/height which is different from its
|
||||
* object default width/height or not.
|
||||
* This is independent from `SetHasCustomDepth`.
|
||||
*
|
||||
* \see gd::Object
|
||||
*/
|
||||
void SetHasCustomSize(bool hasCustomSize_) {
|
||||
personalizedSize = hasCustomSize_;
|
||||
customSize = hasCustomSize_;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set whether the instance has a depth which is different from its
|
||||
* object default depth or not.
|
||||
* This is independent from `SetHasCustomSize`.
|
||||
*
|
||||
* \param hasCustomSize true if the depth is different from the object's
|
||||
* default depth.
|
||||
* \see gd::Object
|
||||
*/
|
||||
void SetHasCustomDepth(bool hasCustomDepth_) {
|
||||
customDepth = hasCustomDepth_;
|
||||
}
|
||||
|
||||
double GetCustomWidth() const { return width; }
|
||||
void SetCustomWidth(double width_) { width = width_; }
|
||||
|
||||
double GetCustomHeight() const { return height; }
|
||||
void SetCustomHeight(double height_) { height = height_; }
|
||||
double GetCustomDepth() const { return depth; }
|
||||
void SetCustomDepth(double depth_) { depth = depth_; }
|
||||
|
||||
/**
|
||||
* \brief Return true if the instance is locked and cannot be moved in the
|
||||
@@ -272,14 +324,19 @@ class GD_CORE_API InitialInstance {
|
||||
stringProperties; ///< More data which can be used by the object
|
||||
|
||||
gd::String objectName; ///< Object name
|
||||
double x; ///< Object initial X position
|
||||
double y; ///< Object initial Y position
|
||||
double angle; ///< Object initial angle
|
||||
int zOrder; ///< Object initial Z order
|
||||
gd::String layer; ///< Object initial layer
|
||||
bool personalizedSize; ///< True if object has a custom size
|
||||
double width; ///< Object custom width
|
||||
double height; ///< Object custom height
|
||||
double x; ///< Instance X position
|
||||
double y; ///< Instance Y position
|
||||
double z; ///< Instance Z position (for a 3D object)
|
||||
double angle; ///< Instance angle on Z axis
|
||||
double rotationX; ///< Instance angle on X axis (for a 3D object)
|
||||
double rotationY; ///< Instance angle on Y axis (for a 3D object)
|
||||
int zOrder; ///< Instance Z order (for a 2D object)
|
||||
gd::String layer; ///< Instance layer
|
||||
bool customSize; ///< True if object has a custom width and height
|
||||
bool customDepth; ///< True if object has a custom depth
|
||||
double width; ///< Instance custom width
|
||||
double height; ///< Instance custom height
|
||||
double depth; ///< Instance custom depth
|
||||
gd::VariablesContainer initialVariables; ///< Instance specific variables
|
||||
bool locked; ///< True if the instance is locked
|
||||
bool sealed; ///< True if the instance is sealed
|
||||
|
@@ -68,14 +68,14 @@ gd::InitialInstance& InitialInstancesContainer::InsertNewInitialInstance() {
|
||||
}
|
||||
|
||||
void InitialInstancesContainer::RemoveInstanceIf(
|
||||
std::function<bool(const gd::InitialInstance&)> predicat) {
|
||||
std::function<bool(const gd::InitialInstance&)> predicate) {
|
||||
// Note that we can't use erase–remove idiom here because remove_if would
|
||||
// move the instances, and the container must guarantee that
|
||||
// iterators/pointers to instances always remain valid.
|
||||
for (std::list<gd::InitialInstance>::iterator it = initialInstances.begin(),
|
||||
end = initialInstances.end();
|
||||
it != end;) {
|
||||
if (predicat(*it))
|
||||
if (predicate(*it))
|
||||
it = initialInstances.erase(it);
|
||||
else
|
||||
++it;
|
||||
|
@@ -178,7 +178,7 @@ class GD_CORE_API InitialInstancesContainer {
|
||||
|
||||
private:
|
||||
void RemoveInstanceIf(
|
||||
std::function<bool(const gd::InitialInstance &)> predicat);
|
||||
std::function<bool(const gd::InitialInstance &)> predicate);
|
||||
|
||||
std::list<gd::InitialInstance> initialInstances;
|
||||
|
||||
|
@@ -21,7 +21,10 @@ Layer::Layer()
|
||||
followBaseLayerCamera(false),
|
||||
camera3DNearPlaneDistance(0.1),
|
||||
camera3DFarPlaneDistance(10000),
|
||||
camera3DFieldOfView(45) {}
|
||||
camera3DFieldOfView(45),
|
||||
ambientLightColorR(200),
|
||||
ambientLightColorG(200),
|
||||
ambientLightColorB(200) {}
|
||||
|
||||
/**
|
||||
* Change cameras count, automatically adding/removing them.
|
||||
|
@@ -5,17 +5,17 @@
|
||||
*/
|
||||
#ifndef GDCORE_OBJECT_H
|
||||
#define GDCORE_OBJECT_H
|
||||
#include "GDCore/Vector2.h"
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/Project/Behavior.h"
|
||||
#include "GDCore/Project/ObjectConfiguration.h"
|
||||
#include "GDCore/Project/EffectsContainer.h"
|
||||
#include "GDCore/Project/ObjectConfiguration.h"
|
||||
#include "GDCore/Project/VariablesContainer.h"
|
||||
#include "GDCore/String.h"
|
||||
#include "GDCore/Tools/MakeUnique.h"
|
||||
#include "GDCore/Vector2.h"
|
||||
|
||||
namespace gd {
|
||||
class PropertyDescriptor;
|
||||
@@ -45,7 +45,7 @@ class GD_CORE_API Object {
|
||||
|
||||
/**
|
||||
* Create a new object with the name passed as argument.
|
||||
*
|
||||
*
|
||||
* Object takes the ownership of the configuration.
|
||||
*/
|
||||
Object(const gd::String& name,
|
||||
@@ -104,7 +104,9 @@ class GD_CORE_API Object {
|
||||
|
||||
/** \brief Change the asset store id of the object.
|
||||
*/
|
||||
void SetAssetStoreId(const gd::String& assetStoreId_) { assetStoreId = assetStoreId_; };
|
||||
void SetAssetStoreId(const gd::String& assetStoreId_) {
|
||||
assetStoreId = assetStoreId_;
|
||||
};
|
||||
|
||||
/** \brief Return the asset store id of the object.
|
||||
*/
|
||||
@@ -112,15 +114,11 @@ class GD_CORE_API Object {
|
||||
|
||||
/** \brief Change the type of the object.
|
||||
*/
|
||||
void SetType(const gd::String& type_) {
|
||||
configuration->SetType(type_);
|
||||
}
|
||||
void SetType(const gd::String& type_) { configuration->SetType(type_); }
|
||||
|
||||
/** \brief Return the type of the object.
|
||||
*/
|
||||
const gd::String& GetType() const {
|
||||
return configuration->GetType();
|
||||
}
|
||||
const gd::String& GetType() const { return configuration->GetType(); }
|
||||
|
||||
/** \brief Change the tags of the object.
|
||||
*/
|
||||
@@ -129,6 +127,10 @@ class GD_CORE_API Object {
|
||||
/** \brief Return the tags of the object.
|
||||
*/
|
||||
const gd::String& GetTags() const { return tags; }
|
||||
|
||||
/** \brief Shortcut to check if the object is a 3D object.
|
||||
*/
|
||||
bool Is3DObject() const { return configuration->Is3DObject(); }
|
||||
///@}
|
||||
|
||||
/** \name Behaviors management
|
||||
@@ -224,12 +226,12 @@ class GD_CORE_API Object {
|
||||
* effects.
|
||||
*/
|
||||
gd::EffectsContainer& GetEffects() { return effectsContainer; }
|
||||
///@}
|
||||
///@}
|
||||
|
||||
/** \name Serialization
|
||||
* Members functions related to serialization of the object
|
||||
*/
|
||||
///@{
|
||||
/** \name Serialization
|
||||
* Members functions related to serialization of the object
|
||||
*/
|
||||
///@{
|
||||
/**
|
||||
* \brief Serialize the object.
|
||||
* \see DoSerializeTo
|
||||
@@ -244,8 +246,9 @@ class GD_CORE_API Object {
|
||||
///@}
|
||||
|
||||
protected:
|
||||
gd::String name; ///< The full name of the object
|
||||
gd::String assetStoreId; ///< The ID of the asset if the object comes from the store.
|
||||
gd::String name; ///< The full name of the object
|
||||
gd::String assetStoreId; ///< The ID of the asset if the object comes from
|
||||
///< the store.
|
||||
std::unique_ptr<gd::ObjectConfiguration> configuration;
|
||||
std::map<gd::String, std::unique_ptr<gd::Behavior>>
|
||||
behaviors; ///< Contains all behaviors and their properties for the
|
||||
@@ -260,7 +263,7 @@ class GD_CORE_API Object {
|
||||
/**
|
||||
* Initialize object using another object. Used by copy-ctor and assign-op.
|
||||
* Don't forget to update me if members were changed!
|
||||
*
|
||||
*
|
||||
* It's needed because there is no default copy for a map of unique_ptr like
|
||||
* behaviors and it must be a deep copy.
|
||||
*/
|
||||
@@ -283,14 +286,4 @@ struct ObjectHasName : public std::binary_function<std::unique_ptr<gd::Object>,
|
||||
|
||||
} // namespace gd
|
||||
|
||||
/**
|
||||
* An object list is a vector containing (smart) pointers to objects.
|
||||
*/
|
||||
using ObjList = std::vector<std::unique_ptr<gd::Object>>;
|
||||
|
||||
/**
|
||||
* Objects are usually managed thanks to (smart) pointers.
|
||||
*/
|
||||
using ObjSPtr = std::unique_ptr<gd::Object>;
|
||||
|
||||
#endif // GDCORE_OBJECT_H
|
||||
|
@@ -20,7 +20,7 @@ namespace gd {
|
||||
|
||||
ObjectConfiguration::~ObjectConfiguration() {}
|
||||
|
||||
ObjectConfiguration::ObjectConfiguration() {}
|
||||
ObjectConfiguration::ObjectConfiguration(): is3DObject(false) {}
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor> ObjectConfiguration::GetProperties() const {
|
||||
std::map<gd::String, gd::PropertyDescriptor> nothing;
|
||||
|
@@ -61,12 +61,22 @@ class GD_CORE_API ObjectConfiguration {
|
||||
|
||||
/** \brief Change the type of the object.
|
||||
*/
|
||||
void SetType(const gd::String& type_) { type = type_; }
|
||||
void SetType(const gd::String& type_) {
|
||||
type = type_;
|
||||
|
||||
// For now, as a shortcut, consider only the objects from the built-in 3D extension
|
||||
// to be 3D object.
|
||||
is3DObject = type.find("Scene3D::") == 0;
|
||||
}
|
||||
|
||||
/** \brief Return the type of the object.
|
||||
*/
|
||||
const gd::String& GetType() const { return type; }
|
||||
|
||||
/** \brief Shortcut to check if the object is a 3D object.
|
||||
*/
|
||||
bool Is3DObject() const { return is3DObject; }
|
||||
|
||||
/** \name Object properties
|
||||
* Reading and updating object configuration properties
|
||||
*/
|
||||
@@ -170,6 +180,7 @@ class GD_CORE_API ObjectConfiguration {
|
||||
protected:
|
||||
gd::String type; ///< Which type of object is represented by this
|
||||
///< configuration.
|
||||
bool is3DObject;
|
||||
|
||||
/**
|
||||
* \brief Derived object configuration can redefine this method to load
|
||||
|
@@ -5,8 +5,10 @@
|
||||
*/
|
||||
|
||||
#include "ObjectGroup.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
#include "GDCore/String.h"
|
||||
|
||||
@@ -41,8 +43,9 @@ void ObjectGroup::SerializeTo(SerializerElement& element) const {
|
||||
|
||||
SerializerElement& objectsElement = element.AddChild("objects");
|
||||
objectsElement.ConsiderAsArrayOf("object");
|
||||
for (auto& name : GetAllObjectsNames())
|
||||
for (auto& name : GetAllObjectsNames()) {
|
||||
objectsElement.AddChild("object").SetAttribute("name", name);
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectGroup::UnserializeFrom(const SerializerElement& element) {
|
||||
|
@@ -8,7 +8,9 @@
|
||||
#define GDCORE_OBJECTGROUP_H
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
class SerializerElement;
|
||||
}
|
||||
|
@@ -4,79 +4,113 @@
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#include "GDCore/Project/ObjectGroupsContainer.h"
|
||||
#include "ObjectGroupsContainer.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "GDCore/Project/ObjectGroup.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
#include "GDCore/String.h"
|
||||
#include "GDCore/Tools/MakeUnique.h"
|
||||
|
||||
namespace gd {
|
||||
gd::ObjectGroup ObjectGroupsContainer::badGroup;
|
||||
|
||||
ObjectGroup ObjectGroupsContainer::badGroup;
|
||||
ObjectGroupsContainer::ObjectGroupsContainer() {}
|
||||
|
||||
ObjectGroupsContainer::ObjectGroupsContainer(
|
||||
const ObjectGroupsContainer& other) {
|
||||
Init(other);
|
||||
}
|
||||
|
||||
ObjectGroupsContainer& ObjectGroupsContainer::operator=(
|
||||
const ObjectGroupsContainer& other) {
|
||||
if (this != &other) Init(other);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void ObjectGroupsContainer::Init(const ObjectGroupsContainer& other) {
|
||||
objectGroups.clear();
|
||||
for (auto& it : other.objectGroups) {
|
||||
objectGroups.push_back(gd::make_unique<gd::ObjectGroup>(*it));
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectGroupsContainer::SerializeTo(SerializerElement& element) const {
|
||||
element.ConsiderAsArrayOf("group");
|
||||
for (std::size_t i = 0; i < objectGroups.size(); ++i) {
|
||||
objectGroups[i]->SerializeTo(element.AddChild("group"));
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectGroupsContainer::UnserializeFrom(const SerializerElement& element) {
|
||||
objectGroups.clear();
|
||||
element.ConsiderAsArrayOf("group", "Groupe");
|
||||
for (std::size_t i = 0; i < element.GetChildrenCount(); ++i) {
|
||||
const SerializerElement& groupElement = element.GetChild(i);
|
||||
gd::ObjectGroup& objectGroup =
|
||||
InsertNew(element.GetStringAttribute("name", "", "nom"), -1);
|
||||
objectGroup.UnserializeFrom(groupElement);
|
||||
}
|
||||
}
|
||||
|
||||
bool ObjectGroupsContainer::Has(const gd::String& name) const {
|
||||
auto i = std::find_if(
|
||||
objectGroups.begin(),
|
||||
objectGroups.end(),
|
||||
[&name](const ObjectGroup& group) { return group.GetName() == name; });
|
||||
auto i = std::find_if(objectGroups.begin(),
|
||||
objectGroups.end(),
|
||||
[&name](const std::unique_ptr<gd::ObjectGroup>& group) {
|
||||
return group->GetName() == name;
|
||||
});
|
||||
return (i != objectGroups.end());
|
||||
}
|
||||
|
||||
ObjectGroup& ObjectGroupsContainer::Get(std::size_t index) {
|
||||
if (index < objectGroups.size()) return objectGroups[index];
|
||||
if (index < objectGroups.size()) return *objectGroups[index];
|
||||
|
||||
return badGroup;
|
||||
}
|
||||
|
||||
const ObjectGroup& ObjectGroupsContainer::Get(std::size_t index) const {
|
||||
if (index < objectGroups.size()) return objectGroups[index];
|
||||
if (index < objectGroups.size()) return *objectGroups[index];
|
||||
|
||||
return badGroup;
|
||||
}
|
||||
|
||||
ObjectGroup& ObjectGroupsContainer::Get(const gd::String& name) {
|
||||
auto i = std::find_if(
|
||||
objectGroups.begin(),
|
||||
objectGroups.end(),
|
||||
[&name](const ObjectGroup& group) { return group.GetName() == name; });
|
||||
if (i != objectGroups.end()) return *i;
|
||||
auto i = std::find_if(objectGroups.begin(),
|
||||
objectGroups.end(),
|
||||
[&name](const std::unique_ptr<gd::ObjectGroup>& group) {
|
||||
return group->GetName() == name;
|
||||
});
|
||||
if (i != objectGroups.end()) return **i;
|
||||
|
||||
return badGroup;
|
||||
}
|
||||
|
||||
const ObjectGroup& ObjectGroupsContainer::Get(const gd::String& name) const {
|
||||
auto i = std::find_if(
|
||||
objectGroups.begin(),
|
||||
objectGroups.end(),
|
||||
[&name](const ObjectGroup& group) { return group.GetName() == name; });
|
||||
if (i != objectGroups.end()) return *i;
|
||||
auto i = std::find_if(objectGroups.begin(),
|
||||
objectGroups.end(),
|
||||
[&name](const std::unique_ptr<gd::ObjectGroup>& group) {
|
||||
return group->GetName() == name;
|
||||
});
|
||||
if (i != objectGroups.end()) return **i;
|
||||
|
||||
return badGroup;
|
||||
}
|
||||
|
||||
ObjectGroup& ObjectGroupsContainer::Insert(const gd::ObjectGroup& group,
|
||||
std::size_t position) {
|
||||
if (position < objectGroups.size()) {
|
||||
objectGroups.insert(objectGroups.begin() + position, group);
|
||||
return objectGroups[position];
|
||||
} else {
|
||||
objectGroups.push_back(group);
|
||||
return objectGroups.back();
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
void ObjectGroupsContainer::Remove(const gd::String& name) {
|
||||
objectGroups.erase(std::remove_if(objectGroups.begin(),
|
||||
objectGroups.end(),
|
||||
[&name](const ObjectGroup& group) {
|
||||
return group.GetName() == name;
|
||||
}),
|
||||
objectGroups.end());
|
||||
objectGroups.erase(
|
||||
std::remove_if(objectGroups.begin(),
|
||||
objectGroups.end(),
|
||||
[&name](const std::unique_ptr<gd::ObjectGroup>& group) {
|
||||
return group->GetName() == name;
|
||||
}),
|
||||
objectGroups.end());
|
||||
}
|
||||
|
||||
std::size_t ObjectGroupsContainer::GetPosition(const gd::String& name) const {
|
||||
for (std::size_t i = 0; i < objectGroups.size(); ++i) {
|
||||
if (objectGroups[i].GetName() == name) return i;
|
||||
if (objectGroups[i]->GetName() == name) return i;
|
||||
}
|
||||
|
||||
return gd::String::npos;
|
||||
@@ -84,21 +118,36 @@ std::size_t ObjectGroupsContainer::GetPosition(const gd::String& name) const {
|
||||
|
||||
ObjectGroup& ObjectGroupsContainer::InsertNew(const gd::String& name,
|
||||
std::size_t position) {
|
||||
ObjectGroup newGroup;
|
||||
newGroup.SetName(name);
|
||||
return Insert(newGroup, position);
|
||||
gd::ObjectGroup& newlyInsertedGroup = *(*(objectGroups.insert(
|
||||
position < objectGroups.size() ? objectGroups.begin() + position
|
||||
: objectGroups.end(),
|
||||
gd::make_unique<gd::ObjectGroup>())));
|
||||
newlyInsertedGroup.SetName(name);
|
||||
return newlyInsertedGroup;
|
||||
}
|
||||
|
||||
ObjectGroup& ObjectGroupsContainer::Insert(const gd::ObjectGroup& group,
|
||||
std::size_t position) {
|
||||
gd::ObjectGroup& newlyInsertedGroup = *(*(objectGroups.insert(
|
||||
position < objectGroups.size() ? objectGroups.begin() + position
|
||||
: objectGroups.end(),
|
||||
gd::make_unique<gd::ObjectGroup>(group))));
|
||||
return newlyInsertedGroup;
|
||||
}
|
||||
|
||||
bool ObjectGroupsContainer::Rename(const gd::String& oldName,
|
||||
const gd::String& newName) {
|
||||
if (Has(newName)) return false;
|
||||
|
||||
auto i = std::find_if(objectGroups.begin(),
|
||||
objectGroups.end(),
|
||||
[&oldName](const ObjectGroup& group) {
|
||||
return group.GetName() == oldName;
|
||||
});
|
||||
if (i != objectGroups.end()) i->SetName(newName);
|
||||
auto i =
|
||||
std::find_if(objectGroups.begin(),
|
||||
objectGroups.end(),
|
||||
[&oldName](const std::unique_ptr<gd::ObjectGroup>& group) {
|
||||
return group->GetName() == oldName;
|
||||
});
|
||||
if (i != objectGroups.end()) {
|
||||
(*i)->SetName(newName);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -107,30 +156,10 @@ void ObjectGroupsContainer::Move(std::size_t oldIndex, std::size_t newIndex) {
|
||||
if (oldIndex >= objectGroups.size() || newIndex >= objectGroups.size())
|
||||
return;
|
||||
|
||||
auto group = objectGroups[oldIndex];
|
||||
std::unique_ptr<gd::ObjectGroup> objectGroup =
|
||||
std::move(objectGroups[oldIndex]);
|
||||
objectGroups.erase(objectGroups.begin() + oldIndex);
|
||||
Insert(group, newIndex);
|
||||
}
|
||||
#endif
|
||||
|
||||
void ObjectGroupsContainer::SerializeTo(SerializerElement& element) const {
|
||||
element.ConsiderAsArrayOf("group");
|
||||
for (auto& group : objectGroups) {
|
||||
SerializerElement& groupElement = element.AddChild("group");
|
||||
group.SerializeTo(groupElement);
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectGroupsContainer::UnserializeFrom(const SerializerElement& element) {
|
||||
objectGroups.clear();
|
||||
element.ConsiderAsArrayOf("group", "Groupe");
|
||||
for (std::size_t i = 0; i < element.GetChildrenCount(); ++i) {
|
||||
SerializerElement& groupElement = element.GetChild(i);
|
||||
gd::ObjectGroup objectGroup;
|
||||
|
||||
objectGroup.UnserializeFrom(groupElement);
|
||||
objectGroups.push_back(objectGroup);
|
||||
}
|
||||
objectGroups.insert(objectGroups.begin() + newIndex, std::move(objectGroup));
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -6,8 +6,10 @@
|
||||
|
||||
#ifndef GDCORE_OBJECTGROUPSCONTAINER_H
|
||||
#define GDCORE_OBJECTGROUPSCONTAINER_H
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/Project/ObjectGroup.h"
|
||||
#include "GDCore/String.h"
|
||||
namespace gd {
|
||||
@@ -26,8 +28,10 @@ namespace gd {
|
||||
*/
|
||||
class GD_CORE_API ObjectGroupsContainer {
|
||||
public:
|
||||
ObjectGroupsContainer(){};
|
||||
ObjectGroupsContainer();
|
||||
ObjectGroupsContainer(const ObjectGroupsContainer&);
|
||||
virtual ~ObjectGroupsContainer(){};
|
||||
ObjectGroupsContainer& operator=(const ObjectGroupsContainer& rhs);
|
||||
|
||||
/**
|
||||
* \brief Return true if the specified group is in the container
|
||||
@@ -171,8 +175,14 @@ class GD_CORE_API ObjectGroupsContainer {
|
||||
const ObjectGroup& at(size_t index) const { return Get(index); };
|
||||
///@}
|
||||
|
||||
/**
|
||||
* Initialize from another object groups container. Used by copy-ctor and
|
||||
* assign-op. Don't forget to update me if members were changed!
|
||||
*/
|
||||
void Init(const gd::ObjectGroupsContainer& other);
|
||||
|
||||
private:
|
||||
std::vector<ObjectGroup> objectGroups;
|
||||
std::vector<std::unique_ptr<gd::ObjectGroup>> objectGroups;
|
||||
static ObjectGroup badGroup;
|
||||
};
|
||||
|
||||
|
@@ -4,7 +4,9 @@
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "GDCore/Project/ObjectsContainer.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "GDCore/Extensions/Platform.h"
|
||||
#include "GDCore/Project/Object.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
@@ -16,14 +18,12 @@ ObjectsContainer::ObjectsContainer() {}
|
||||
|
||||
ObjectsContainer::~ObjectsContainer() {}
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
void ObjectsContainer::SerializeObjectsTo(SerializerElement& element) const {
|
||||
element.ConsiderAsArrayOf("object");
|
||||
for (std::size_t j = 0; j < initialObjects.size(); j++) {
|
||||
initialObjects[j]->SerializeTo(element.AddChild("object"));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void ObjectsContainer::UnserializeObjectsFrom(
|
||||
gd::Project& project, const SerializerElement& element) {
|
||||
@@ -75,7 +75,6 @@ std::size_t ObjectsContainer::GetObjectPosition(const gd::String& name) const {
|
||||
std::size_t ObjectsContainer::GetObjectsCount() const {
|
||||
return initialObjects.size();
|
||||
}
|
||||
#if defined(GD_IDE_ONLY)
|
||||
gd::Object& ObjectsContainer::InsertNewObject(const gd::Project& project,
|
||||
const gd::String& objectType,
|
||||
const gd::String& name,
|
||||
@@ -87,7 +86,6 @@ gd::Object& ObjectsContainer::InsertNewObject(const gd::Project& project,
|
||||
|
||||
return newlyCreatedObject;
|
||||
}
|
||||
#endif
|
||||
|
||||
gd::Object& ObjectsContainer::InsertObject(const gd::Object& object,
|
||||
std::size_t position) {
|
||||
@@ -119,7 +117,7 @@ void ObjectsContainer::MoveObject(std::size_t oldIndex, std::size_t newIndex) {
|
||||
}
|
||||
|
||||
void ObjectsContainer::RemoveObject(const gd::String& name) {
|
||||
std::vector<std::unique_ptr<gd::Object> >::iterator objectIt =
|
||||
std::vector<std::unique_ptr<gd::Object>>::iterator objectIt =
|
||||
find_if(initialObjects.begin(),
|
||||
initialObjects.end(),
|
||||
bind2nd(ObjectHasName(), name));
|
||||
@@ -132,7 +130,7 @@ void ObjectsContainer::MoveObjectToAnotherContainer(
|
||||
const gd::String& name,
|
||||
gd::ObjectsContainer& newContainer,
|
||||
std::size_t newPosition) {
|
||||
std::vector<std::unique_ptr<gd::Object> >::iterator objectIt =
|
||||
std::vector<std::unique_ptr<gd::Object>>::iterator objectIt =
|
||||
find_if(initialObjects.begin(),
|
||||
initialObjects.end(),
|
||||
bind2nd(ObjectHasName(), name));
|
||||
|
@@ -65,6 +65,8 @@ Project::Project()
|
||||
pixelsRounding(false),
|
||||
adaptGameResolutionAtRuntime(true),
|
||||
sizeOnStartupMode("adaptWidth"),
|
||||
antialiasingMode("MSAA"),
|
||||
isAntialisingEnabledOnMobile(false),
|
||||
projectUuid(""),
|
||||
useDeprecatedZeroAsDefaultZOrder(false),
|
||||
useExternalSourceFiles(false),
|
||||
@@ -81,24 +83,23 @@ Project::~Project() {}
|
||||
void Project::ResetProjectUuid() { projectUuid = UUID::MakeUuid4(); }
|
||||
|
||||
std::unique_ptr<gd::Object> Project::CreateObject(
|
||||
const gd::String& type,
|
||||
const gd::String& name) const {
|
||||
return gd::make_unique<Object>(name, type, CreateObjectConfiguration(type));
|
||||
const gd::String& type, const gd::String& name) const {
|
||||
return gd::make_unique<Object>(name, type, CreateObjectConfiguration(type));
|
||||
}
|
||||
|
||||
std::unique_ptr<gd::ObjectConfiguration> Project::CreateObjectConfiguration(
|
||||
const gd::String& type) const {
|
||||
const gd::String& type) const {
|
||||
if (Project::HasEventsBasedObject(type)) {
|
||||
return gd::make_unique<CustomObjectConfiguration>(*this, type);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// Create a base object if the type can't be found in the platform.
|
||||
return currentPlatform->CreateObjectConfiguration(type);
|
||||
}
|
||||
}
|
||||
|
||||
bool Project::HasEventsBasedObject(const gd::String& type) const {
|
||||
const auto separatorIndex = type.find(PlatformExtension::GetNamespaceSeparator());
|
||||
const auto separatorIndex =
|
||||
type.find(PlatformExtension::GetNamespaceSeparator());
|
||||
if (separatorIndex == std::string::npos) {
|
||||
return false;
|
||||
}
|
||||
@@ -106,59 +107,67 @@ bool Project::HasEventsBasedObject(const gd::String& type) const {
|
||||
if (!Project::HasEventsFunctionsExtensionNamed(extensionName)) {
|
||||
return false;
|
||||
}
|
||||
auto &extension = Project::GetEventsFunctionsExtension(extensionName);
|
||||
auto& extension = Project::GetEventsFunctionsExtension(extensionName);
|
||||
gd::String objectTypeName = type.substr(separatorIndex + 2);
|
||||
return extension.GetEventsBasedObjects().Has(objectTypeName);
|
||||
}
|
||||
|
||||
gd::EventsBasedObject& Project::GetEventsBasedObject(const gd::String& type) {
|
||||
const auto separatorIndex = type.find(PlatformExtension::GetNamespaceSeparator());
|
||||
const auto separatorIndex =
|
||||
type.find(PlatformExtension::GetNamespaceSeparator());
|
||||
gd::String extensionName = type.substr(0, separatorIndex);
|
||||
gd::String objectTypeName = type.substr(separatorIndex + 2);
|
||||
|
||||
auto &extension = Project::GetEventsFunctionsExtension(extensionName);
|
||||
auto& extension = Project::GetEventsFunctionsExtension(extensionName);
|
||||
return extension.GetEventsBasedObjects().Get(objectTypeName);
|
||||
}
|
||||
|
||||
const gd::EventsBasedObject& Project::GetEventsBasedObject(const gd::String& type) const {
|
||||
const auto separatorIndex = type.find(PlatformExtension::GetNamespaceSeparator());
|
||||
const gd::EventsBasedObject& Project::GetEventsBasedObject(
|
||||
const gd::String& type) const {
|
||||
const auto separatorIndex =
|
||||
type.find(PlatformExtension::GetNamespaceSeparator());
|
||||
gd::String extensionName = type.substr(0, separatorIndex);
|
||||
gd::String objectTypeName = type.substr(separatorIndex + 2);
|
||||
|
||||
const auto &extension = Project::GetEventsFunctionsExtension(extensionName);
|
||||
const auto& extension = Project::GetEventsFunctionsExtension(extensionName);
|
||||
return extension.GetEventsBasedObjects().Get(objectTypeName);
|
||||
}
|
||||
|
||||
bool Project::HasEventsBasedBehavior(const gd::String& type) const {
|
||||
const auto separatorIndex = type.find(PlatformExtension::GetNamespaceSeparator());
|
||||
if (separatorIndex == std::string::npos) {
|
||||
return false;
|
||||
}
|
||||
gd::String extensionName = type.substr(0, separatorIndex);
|
||||
if (!Project::HasEventsFunctionsExtensionNamed(extensionName)) {
|
||||
return false;
|
||||
}
|
||||
auto &extension = Project::GetEventsFunctionsExtension(extensionName);
|
||||
gd::String behaviorTypeName = type.substr(separatorIndex + 2);
|
||||
return extension.GetEventsBasedBehaviors().Has(behaviorTypeName);
|
||||
const auto separatorIndex =
|
||||
type.find(PlatformExtension::GetNamespaceSeparator());
|
||||
if (separatorIndex == std::string::npos) {
|
||||
return false;
|
||||
}
|
||||
gd::String extensionName = type.substr(0, separatorIndex);
|
||||
if (!Project::HasEventsFunctionsExtensionNamed(extensionName)) {
|
||||
return false;
|
||||
}
|
||||
auto& extension = Project::GetEventsFunctionsExtension(extensionName);
|
||||
gd::String behaviorTypeName = type.substr(separatorIndex + 2);
|
||||
return extension.GetEventsBasedBehaviors().Has(behaviorTypeName);
|
||||
}
|
||||
|
||||
gd::EventsBasedBehavior& Project::GetEventsBasedBehavior(const gd::String& type) {
|
||||
const auto separatorIndex = type.find(PlatformExtension::GetNamespaceSeparator());
|
||||
gd::String extensionName = type.substr(0, separatorIndex);
|
||||
gd::String behaviorTypeName = type.substr(separatorIndex + 2);
|
||||
gd::EventsBasedBehavior& Project::GetEventsBasedBehavior(
|
||||
const gd::String& type) {
|
||||
const auto separatorIndex =
|
||||
type.find(PlatformExtension::GetNamespaceSeparator());
|
||||
gd::String extensionName = type.substr(0, separatorIndex);
|
||||
gd::String behaviorTypeName = type.substr(separatorIndex + 2);
|
||||
|
||||
auto &extension = Project::GetEventsFunctionsExtension(extensionName);
|
||||
return extension.GetEventsBasedBehaviors().Get(behaviorTypeName);
|
||||
auto& extension = Project::GetEventsFunctionsExtension(extensionName);
|
||||
return extension.GetEventsBasedBehaviors().Get(behaviorTypeName);
|
||||
}
|
||||
|
||||
const gd::EventsBasedBehavior& Project::GetEventsBasedBehavior(const gd::String& type) const {
|
||||
const auto separatorIndex = type.find(PlatformExtension::GetNamespaceSeparator());
|
||||
gd::String extensionName = type.substr(0, separatorIndex);
|
||||
gd::String behaviorTypeName = type.substr(separatorIndex + 2);
|
||||
const gd::EventsBasedBehavior& Project::GetEventsBasedBehavior(
|
||||
const gd::String& type) const {
|
||||
const auto separatorIndex =
|
||||
type.find(PlatformExtension::GetNamespaceSeparator());
|
||||
gd::String extensionName = type.substr(0, separatorIndex);
|
||||
gd::String behaviorTypeName = type.substr(separatorIndex + 2);
|
||||
|
||||
auto &extension = Project::GetEventsFunctionsExtension(extensionName);
|
||||
return extension.GetEventsBasedBehaviors().Get(behaviorTypeName);
|
||||
auto& extension = Project::GetEventsFunctionsExtension(extensionName);
|
||||
return extension.GetEventsBasedBehaviors().Get(behaviorTypeName);
|
||||
}
|
||||
|
||||
std::shared_ptr<gd::BaseEvent> Project::CreateEvent(
|
||||
@@ -378,7 +387,7 @@ void Project::MoveExternalLayout(std::size_t oldIndex, std::size_t newIndex) {
|
||||
};
|
||||
|
||||
void Project::MoveEventsFunctionsExtension(std::size_t oldIndex,
|
||||
std::size_t newIndex) {
|
||||
std::size_t newIndex) {
|
||||
if (oldIndex >= eventsFunctionsExtensions.size() ||
|
||||
newIndex >= eventsFunctionsExtensions.size())
|
||||
return;
|
||||
@@ -621,6 +630,8 @@ void Project::UnserializeFrom(const SerializerElement& element) {
|
||||
SetAdaptGameResolutionAtRuntime(
|
||||
propElement.GetBoolAttribute("adaptGameResolutionAtRuntime", false));
|
||||
SetSizeOnStartupMode(propElement.GetStringAttribute("sizeOnStartupMode", ""));
|
||||
SetAntialiasingMode(propElement.GetStringAttribute("antialiasingMode", "MSAA"));
|
||||
SetAntialisingEnabledOnMobile(propElement.GetBoolAttribute("antialisingEnabledOnMobile", false));
|
||||
SetProjectUuid(propElement.GetStringAttribute("projectUuid", ""));
|
||||
SetAuthor(propElement.GetChild("author", 0, "Auteur").GetValue().GetString());
|
||||
SetPackageName(propElement.GetStringAttribute("packageName"));
|
||||
@@ -875,6 +886,8 @@ void Project::SerializeTo(SerializerElement& element) const {
|
||||
propElement.SetAttribute("adaptGameResolutionAtRuntime",
|
||||
adaptGameResolutionAtRuntime);
|
||||
propElement.SetAttribute("sizeOnStartupMode", sizeOnStartupMode);
|
||||
propElement.SetAttribute("antialiasingMode", antialiasingMode);
|
||||
propElement.SetAttribute("antialisingEnabledOnMobile", isAntialisingEnabledOnMobile);
|
||||
propElement.SetAttribute("projectUuid", projectUuid);
|
||||
propElement.SetAttribute("folderProject", folderProject);
|
||||
propElement.SetAttribute("packageName", packageName);
|
||||
@@ -1005,7 +1018,7 @@ void Project::ExposeResources(gd::ArbitraryResourceWorker& worker) {
|
||||
// Add layouts resources
|
||||
for (std::size_t s = 0; s < GetLayoutsCount(); s++) {
|
||||
for (std::size_t j = 0; j < GetLayout(s).GetObjectsCount();
|
||||
++j) { // Add objects resources
|
||||
++j) { // Add objects resources
|
||||
GetLayout(s).GetObject(j).GetConfiguration().ExposeResources(worker);
|
||||
}
|
||||
|
||||
@@ -1106,6 +1119,8 @@ void Project::Init(const gd::Project& game) {
|
||||
pixelsRounding = game.pixelsRounding;
|
||||
adaptGameResolutionAtRuntime = game.adaptGameResolutionAtRuntime;
|
||||
sizeOnStartupMode = game.sizeOnStartupMode;
|
||||
antialiasingMode = game.antialiasingMode;
|
||||
isAntialisingEnabledOnMobile = game.isAntialisingEnabledOnMobile;
|
||||
projectUuid = game.projectUuid;
|
||||
useDeprecatedZeroAsDefaultZOrder = game.useDeprecatedZeroAsDefaultZOrder;
|
||||
|
||||
|
@@ -383,6 +383,26 @@ class GD_CORE_API Project : public ObjectsContainer {
|
||||
*/
|
||||
void SetPixelsRounding(bool enable) { pixelsRounding = enable; }
|
||||
|
||||
/**
|
||||
* Return the antialiasing mode used by the game ("none" or "MSAA").
|
||||
*/
|
||||
const gd::String& GetAntialiasingMode() const { return antialiasingMode; }
|
||||
|
||||
/**
|
||||
* Set the antialiasing mode used by the game ("none" or "MSAA").
|
||||
*/
|
||||
void SetAntialiasingMode(const gd::String& antialiasingMode_) { antialiasingMode = antialiasingMode_; }
|
||||
|
||||
/**
|
||||
* Return true if antialising is enabled on mobiles.
|
||||
*/
|
||||
bool IsAntialisingEnabledOnMobile() const { return isAntialisingEnabledOnMobile; }
|
||||
|
||||
/**
|
||||
* Set whether antialising is enabled on mobiles or not.
|
||||
*/
|
||||
void SetAntialisingEnabledOnMobile(bool enable) { isAntialisingEnabledOnMobile = enable; }
|
||||
|
||||
/**
|
||||
* \brief Return if the project should set 0 as Z-order for objects created
|
||||
* from events (which is deprecated) - instead of the highest Z order that was
|
||||
@@ -1040,6 +1060,8 @@ class GD_CORE_API Project : public ObjectsContainer {
|
||||
gd::String
|
||||
sizeOnStartupMode; ///< How to adapt the game size to the screen. Can be
|
||||
///< "adaptWidth", "adaptHeight" or empty
|
||||
gd::String antialiasingMode;
|
||||
bool isAntialisingEnabledOnMobile;
|
||||
gd::String projectUuid; ///< UUID useful to identify the game in online
|
||||
///< services or database that would require it.
|
||||
bool useDeprecatedZeroAsDefaultZOrder; ///< If true, objects created from
|
||||
|
@@ -108,19 +108,8 @@ namespace gdjs {
|
||||
this.setWidth(initialInstanceData.width);
|
||||
this.setHeight(initialInstanceData.height);
|
||||
}
|
||||
initialInstanceData.numberProperties.forEach((property) => {
|
||||
if (property.name === 'z') {
|
||||
this.setZ(property.value);
|
||||
} else if (property.name === 'depth') {
|
||||
if (initialInstanceData.customSize) {
|
||||
this.setDepth(property.value);
|
||||
}
|
||||
} else if (property.name === 'rotationX') {
|
||||
this.setRotationX(property.value);
|
||||
} else if (property.name === 'rotationY') {
|
||||
this.setRotationY(property.value);
|
||||
}
|
||||
});
|
||||
if (initialInstanceData.depth !== undefined)
|
||||
this.setDepth(initialInstanceData.depth);
|
||||
}
|
||||
|
||||
setX(x: float): void {
|
||||
|
20
Extensions/3D/CMakeLists.txt
Normal file
20
Extensions/3D/CMakeLists.txt
Normal file
@@ -0,0 +1,20 @@
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
cmake_policy(SET CMP0015 NEW)
|
||||
|
||||
project(Scene3D)
|
||||
gd_add_extension_includes()
|
||||
|
||||
#Defines
|
||||
###
|
||||
gd_add_extension_definitions(Scene3D)
|
||||
|
||||
#The targets
|
||||
###
|
||||
include_directories(.)
|
||||
file(GLOB source_files *.cpp *.h)
|
||||
gd_add_clang_utils(Scene3D "${source_files}")
|
||||
gd_add_extension_target(Scene3D "${source_files}")
|
||||
|
||||
#Linker files for the IDE extension
|
||||
###
|
||||
gd_extension_link_libraries(Scene3D)
|
106
Extensions/3D/HemisphereLight.ts
Normal file
106
Extensions/3D/HemisphereLight.ts
Normal file
@@ -0,0 +1,106 @@
|
||||
namespace gdjs {
|
||||
gdjs.PixiFiltersTools.registerFilterCreator(
|
||||
'Scene3D::HemisphereLight',
|
||||
new (class implements gdjs.PixiFiltersTools.FilterCreator {
|
||||
makeFilter(
|
||||
target: EffectsTarget,
|
||||
effectData: EffectData
|
||||
): gdjs.PixiFiltersTools.Filter {
|
||||
return new (class implements gdjs.PixiFiltersTools.Filter {
|
||||
light: THREE.HemisphereLight;
|
||||
rotationObject: THREE.Group;
|
||||
_isEnabled: boolean = false;
|
||||
top: string = 'Y-';
|
||||
elevation: float = 45;
|
||||
rotation: float = 0;
|
||||
|
||||
constructor() {
|
||||
this.light = new THREE.HemisphereLight();
|
||||
this.light.position.set(1, 0, 0);
|
||||
this.rotationObject = new THREE.Group();
|
||||
this.rotationObject.add(this.light);
|
||||
this.updateRotation();
|
||||
}
|
||||
|
||||
isEnabled(target: EffectsTarget): boolean {
|
||||
return this._isEnabled;
|
||||
}
|
||||
setEnabled(target: EffectsTarget, enabled: boolean): boolean {
|
||||
if (this._isEnabled === enabled) {
|
||||
return true;
|
||||
}
|
||||
if (enabled) {
|
||||
return this.applyEffect(target);
|
||||
} else {
|
||||
return this.removeEffect(target);
|
||||
}
|
||||
}
|
||||
applyEffect(target: EffectsTarget): boolean {
|
||||
const scene = target.get3DRendererObject() as
|
||||
| THREE.Scene
|
||||
| null
|
||||
| undefined;
|
||||
if (!scene) {
|
||||
return false;
|
||||
}
|
||||
scene.add(this.rotationObject);
|
||||
this._isEnabled = true;
|
||||
return true;
|
||||
}
|
||||
removeEffect(target: EffectsTarget): boolean {
|
||||
const scene = target.get3DRendererObject() as
|
||||
| THREE.Scene
|
||||
| null
|
||||
| undefined;
|
||||
if (!scene) {
|
||||
return false;
|
||||
}
|
||||
scene.remove(this.rotationObject);
|
||||
this._isEnabled = false;
|
||||
return true;
|
||||
}
|
||||
updatePreRender(target: gdjs.EffectsTarget): any {}
|
||||
updateDoubleParameter(parameterName: string, value: number): void {
|
||||
if (parameterName === 'intensity') {
|
||||
this.light.intensity = value;
|
||||
} else if (parameterName === 'elevation') {
|
||||
this.elevation = value;
|
||||
this.updateRotation();
|
||||
} else if (parameterName === 'rotation') {
|
||||
this.rotation = value;
|
||||
this.updateRotation();
|
||||
}
|
||||
}
|
||||
updateStringParameter(parameterName: string, value: string): void {
|
||||
if (parameterName === 'skyColor') {
|
||||
this.light.color = new THREE.Color(
|
||||
gdjs.PixiFiltersTools.rgbOrHexToHexNumber(value)
|
||||
);
|
||||
}
|
||||
if (parameterName === 'groundColor') {
|
||||
this.light.groundColor = new THREE.Color(
|
||||
gdjs.PixiFiltersTools.rgbOrHexToHexNumber(value)
|
||||
);
|
||||
}
|
||||
if (parameterName === 'top') {
|
||||
this.top = value;
|
||||
this.updateRotation();
|
||||
}
|
||||
}
|
||||
updateBooleanParameter(parameterName: string, value: boolean): void {}
|
||||
updateRotation() {
|
||||
if (this.top === 'Z+') {
|
||||
// 0° is a light from the right of the screen.
|
||||
this.rotationObject.rotation.z = gdjs.toRad(this.rotation);
|
||||
this.rotationObject.rotation.y = -gdjs.toRad(this.elevation);
|
||||
} else {
|
||||
// 0° becomes a light from Z+.
|
||||
this.rotationObject.rotation.y = gdjs.toRad(this.rotation) - 90;
|
||||
this.rotationObject.rotation.z = -gdjs.toRad(this.elevation);
|
||||
}
|
||||
}
|
||||
})();
|
||||
}
|
||||
})()
|
||||
);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
292
Extensions/3D/Model3DObjectConfiguration.cpp
Normal file
292
Extensions/3D/Model3DObjectConfiguration.cpp
Normal file
@@ -0,0 +1,292 @@
|
||||
/**
|
||||
|
||||
GDevelop - Particle System Extension
|
||||
Copyright (c) 2010-2016 Florian Rival (Florian.Rival@gmail.com)
|
||||
This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#include "Model3DObjectConfiguration.h"
|
||||
|
||||
#include "GDCore/CommonTools.h"
|
||||
#include "GDCore/IDE/Project/ArbitraryResourceWorker.h"
|
||||
#include "GDCore/Project/InitialInstance.h"
|
||||
#include "GDCore/Project/MeasurementUnit.h"
|
||||
#include "GDCore/Project/Object.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Project/PropertyDescriptor.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
#include "GDCore/Tools/Localization.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
Model3DObjectConfiguration::Model3DObjectConfiguration()
|
||||
: width(100), height(100), depth(100), rotationX(0), rotationY(0),
|
||||
rotationZ(0), modelResourceName(""), materialType("Basic"),
|
||||
originLocation("ModelOrigin"), centerLocation("ModelOrigin"),
|
||||
keepAspectRatio(true) {}
|
||||
|
||||
bool Model3DObjectConfiguration::UpdateProperty(const gd::String &propertyName,
|
||||
const gd::String &newValue) {
|
||||
if (propertyName == "width") {
|
||||
width = newValue.To<double>();
|
||||
return true;
|
||||
}
|
||||
if (propertyName == "height") {
|
||||
height = newValue.To<double>();
|
||||
return true;
|
||||
}
|
||||
if (propertyName == "depth") {
|
||||
depth = newValue.To<double>();
|
||||
return true;
|
||||
}
|
||||
if (propertyName == "rotationX") {
|
||||
rotationX = newValue.To<double>();
|
||||
return true;
|
||||
}
|
||||
if (propertyName == "rotationY") {
|
||||
rotationY = newValue.To<double>();
|
||||
return true;
|
||||
}
|
||||
if (propertyName == "rotationZ") {
|
||||
rotationZ = newValue.To<double>();
|
||||
return true;
|
||||
}
|
||||
if (propertyName == "modelResourceName") {
|
||||
modelResourceName = newValue;
|
||||
return true;
|
||||
}
|
||||
if (propertyName == "materialType") {
|
||||
materialType = newValue;
|
||||
return true;
|
||||
}
|
||||
if (propertyName == "originLocation") {
|
||||
originLocation = newValue;
|
||||
return true;
|
||||
}
|
||||
if (propertyName == "centerLocation") {
|
||||
centerLocation = newValue;
|
||||
return true;
|
||||
}
|
||||
if (propertyName == "keepAspectRatio") {
|
||||
keepAspectRatio = newValue == "1";
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor>
|
||||
Model3DObjectConfiguration::GetProperties() const {
|
||||
std::map<gd::String, gd::PropertyDescriptor> objectProperties;
|
||||
|
||||
objectProperties["width"]
|
||||
.SetValue(gd::String::From(width))
|
||||
.SetType("number")
|
||||
.SetLabel(_("Width"))
|
||||
.SetMeasurementUnit(gd::MeasurementUnit::GetPixel())
|
||||
.SetGroup(_("Default size"));
|
||||
|
||||
objectProperties["height"]
|
||||
.SetValue(gd::String::From(height))
|
||||
.SetType("number")
|
||||
.SetLabel(_("Height"))
|
||||
.SetMeasurementUnit(gd::MeasurementUnit::GetPixel())
|
||||
.SetGroup(_("Default size"));
|
||||
|
||||
objectProperties["depth"]
|
||||
.SetValue(gd::String::From(depth))
|
||||
.SetType("number")
|
||||
.SetLabel(_("Depth"))
|
||||
.SetMeasurementUnit(gd::MeasurementUnit::GetPixel())
|
||||
.SetGroup(_("Default size"));
|
||||
|
||||
objectProperties["keepAspectRatio"]
|
||||
.SetValue(keepAspectRatio ? "true" : "false")
|
||||
.SetType("boolean")
|
||||
.SetLabel(_("Reduce initial dimensions to keep aspect ratio"))
|
||||
.SetGroup(_("Default size"));
|
||||
|
||||
objectProperties["rotationX"]
|
||||
.SetValue(gd::String::From(rotationX))
|
||||
.SetType("number")
|
||||
.SetLabel(_("Rotation around X axis"))
|
||||
.SetMeasurementUnit(gd::MeasurementUnit::GetDegreeAngle())
|
||||
.SetGroup(_("Default orientation"));
|
||||
|
||||
objectProperties["rotationY"]
|
||||
.SetValue(gd::String::From(rotationY))
|
||||
.SetType("number")
|
||||
.SetLabel(_("Rotation around Y axis"))
|
||||
.SetMeasurementUnit(gd::MeasurementUnit::GetDegreeAngle())
|
||||
.SetGroup(_("Default orientation"));
|
||||
|
||||
objectProperties["rotationZ"]
|
||||
.SetValue(gd::String::From(rotationZ))
|
||||
.SetType("number")
|
||||
.SetLabel(_("Rotation around Z axis"))
|
||||
.SetMeasurementUnit(gd::MeasurementUnit::GetDegreeAngle())
|
||||
.SetGroup(_("Default orientation"));
|
||||
|
||||
objectProperties["modelResourceName"]
|
||||
.SetValue(modelResourceName)
|
||||
.SetType("resource")
|
||||
.AddExtraInfo("model3D")
|
||||
.SetLabel(_("3D model"));
|
||||
|
||||
objectProperties["materialType"]
|
||||
.SetValue(materialType.empty() ? "Basic" : materialType)
|
||||
.SetType("choice")
|
||||
.AddExtraInfo("Basic")
|
||||
.AddExtraInfo("StandardWithoutMetalness")
|
||||
.AddExtraInfo("KeepOriginal")
|
||||
.SetLabel(_("Material modifier"));
|
||||
|
||||
objectProperties["originLocation"]
|
||||
.SetValue(originLocation.empty() ? "TopLeft" : originLocation)
|
||||
.SetType("choice")
|
||||
.AddExtraInfo("ModelOrigin")
|
||||
.AddExtraInfo("TopLeft")
|
||||
.AddExtraInfo("ObjectCenter")
|
||||
.AddExtraInfo("BottomCenterZ")
|
||||
.AddExtraInfo("BottomCenterY")
|
||||
.SetLabel(_("Origin point"));
|
||||
|
||||
objectProperties["centerLocation"]
|
||||
.SetValue(centerLocation.empty() ? "ObjectCenter" : centerLocation)
|
||||
.SetType("choice")
|
||||
.AddExtraInfo("ModelOrigin")
|
||||
.AddExtraInfo("ObjectCenter")
|
||||
.AddExtraInfo("BottomCenterZ")
|
||||
.AddExtraInfo("BottomCenterY")
|
||||
.SetLabel(_("Center point"));
|
||||
|
||||
return objectProperties;
|
||||
}
|
||||
|
||||
bool Model3DObjectConfiguration::UpdateInitialInstanceProperty(
|
||||
gd::InitialInstance &instance, const gd::String &propertyName,
|
||||
const gd::String &newValue, gd::Project &project, gd::Layout &layout) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor>
|
||||
Model3DObjectConfiguration::GetInitialInstanceProperties(
|
||||
const gd::InitialInstance &instance, gd::Project &project,
|
||||
gd::Layout &layout) {
|
||||
std::map<gd::String, gd::PropertyDescriptor> instanceProperties;
|
||||
return instanceProperties;
|
||||
}
|
||||
|
||||
void Model3DObjectConfiguration::DoUnserializeFrom(
|
||||
gd::Project &project, const gd::SerializerElement &element) {
|
||||
auto &content = element.GetChild("content");
|
||||
|
||||
width = content.GetDoubleAttribute("width");
|
||||
height = content.GetDoubleAttribute("height");
|
||||
depth = content.GetDoubleAttribute("depth");
|
||||
rotationX = content.GetDoubleAttribute("rotationX");
|
||||
rotationY = content.GetDoubleAttribute("rotationY");
|
||||
rotationZ = content.GetDoubleAttribute("rotationZ");
|
||||
modelResourceName = content.GetStringAttribute("modelResourceName");
|
||||
materialType = content.GetStringAttribute("materialType");
|
||||
originLocation = content.GetStringAttribute("originLocation");
|
||||
centerLocation = content.GetStringAttribute("centerLocation");
|
||||
keepAspectRatio = content.GetBoolAttribute("keepAspectRatio");
|
||||
|
||||
RemoveAllAnimations();
|
||||
auto &animationsElement = content.GetChild("animations");
|
||||
animationsElement.ConsiderAsArrayOf("animation");
|
||||
for (std::size_t i = 0; i < animationsElement.GetChildrenCount(); ++i) {
|
||||
auto &animationElement = animationsElement.GetChild(i);
|
||||
Model3DAnimation animation;
|
||||
animation.SetName(animationElement.GetStringAttribute("name", ""));
|
||||
animation.SetSource(animationElement.GetStringAttribute("source", ""));
|
||||
animation.SetShouldLoop(animationElement.GetBoolAttribute("loop", false));
|
||||
AddAnimation(animation);
|
||||
}
|
||||
}
|
||||
|
||||
void Model3DObjectConfiguration::DoSerializeTo(
|
||||
gd::SerializerElement &element) const {
|
||||
auto &content = element.AddChild("content");
|
||||
content.SetAttribute("width", width);
|
||||
content.SetAttribute("height", height);
|
||||
content.SetAttribute("depth", depth);
|
||||
content.SetAttribute("rotationX", rotationX);
|
||||
content.SetAttribute("rotationY", rotationY);
|
||||
content.SetAttribute("rotationZ", rotationZ);
|
||||
content.SetAttribute("modelResourceName", modelResourceName);
|
||||
content.SetAttribute("materialType", materialType);
|
||||
content.SetAttribute("originLocation", originLocation);
|
||||
content.SetAttribute("centerLocation", centerLocation);
|
||||
content.SetAttribute("keepAspectRatio", keepAspectRatio);
|
||||
|
||||
auto &animationsElement = content.AddChild("animations");
|
||||
animationsElement.ConsiderAsArrayOf("animation");
|
||||
for (auto &animation : animations) {
|
||||
auto &animationElement = animationsElement.AddChild("animation");
|
||||
animationElement.SetAttribute("name", animation.GetName());
|
||||
animationElement.SetAttribute("source", animation.GetSource());
|
||||
animationElement.SetAttribute("loop", animation.ShouldLoop());
|
||||
}
|
||||
}
|
||||
|
||||
void Model3DObjectConfiguration::ExposeResources(
|
||||
gd::ArbitraryResourceWorker &worker) {
|
||||
worker.ExposeModel3D(modelResourceName);
|
||||
}
|
||||
|
||||
Model3DAnimation Model3DObjectConfiguration::badAnimation;
|
||||
|
||||
const Model3DAnimation &
|
||||
Model3DObjectConfiguration::GetAnimation(std::size_t nb) const {
|
||||
if (nb >= animations.size())
|
||||
return badAnimation;
|
||||
|
||||
return animations[nb];
|
||||
}
|
||||
|
||||
Model3DAnimation &Model3DObjectConfiguration::GetAnimation(std::size_t nb) {
|
||||
if (nb >= animations.size())
|
||||
return badAnimation;
|
||||
|
||||
return animations[nb];
|
||||
}
|
||||
|
||||
bool Model3DObjectConfiguration::HasAnimationNamed(
|
||||
const gd::String &name) const {
|
||||
return !name.empty() && (find_if(animations.begin(), animations.end(),
|
||||
[&name](const Model3DAnimation &animation) {
|
||||
return animation.GetName() == name;
|
||||
}) != animations.end());
|
||||
}
|
||||
|
||||
void Model3DObjectConfiguration::AddAnimation(
|
||||
const Model3DAnimation &animation) {
|
||||
animations.push_back(animation);
|
||||
}
|
||||
|
||||
bool Model3DObjectConfiguration::RemoveAnimation(std::size_t nb) {
|
||||
if (nb >= GetAnimationsCount())
|
||||
return false;
|
||||
|
||||
animations.erase(animations.begin() + nb);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Model3DObjectConfiguration::SwapAnimations(std::size_t firstIndex,
|
||||
std::size_t secondIndex) {
|
||||
if (firstIndex < animations.size() && secondIndex < animations.size() &&
|
||||
firstIndex != secondIndex)
|
||||
std::swap(animations[firstIndex], animations[secondIndex]);
|
||||
}
|
||||
|
||||
void Model3DObjectConfiguration::MoveAnimation(std::size_t oldIndex,
|
||||
std::size_t newIndex) {
|
||||
if (oldIndex >= animations.size() || newIndex >= animations.size())
|
||||
return;
|
||||
|
||||
auto animation = animations[oldIndex];
|
||||
animations.erase(animations.begin() + oldIndex);
|
||||
animations.insert(animations.begin() + newIndex, animation);
|
||||
}
|
177
Extensions/3D/Model3DObjectConfiguration.h
Normal file
177
Extensions/3D/Model3DObjectConfiguration.h
Normal file
@@ -0,0 +1,177 @@
|
||||
/**
|
||||
|
||||
GDevelop - Particle System Extension
|
||||
Copyright (c) 2010-2016 Florian Rival (Florian.Rival@gmail.com)
|
||||
This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GDCore/Project/ObjectConfiguration.h"
|
||||
namespace gd {
|
||||
class InitialInstance;
|
||||
class Project;
|
||||
} // namespace gd
|
||||
|
||||
class GD_EXTENSION_API Model3DAnimation {
|
||||
public:
|
||||
Model3DAnimation() : shouldLoop(false) {};
|
||||
virtual ~Model3DAnimation(){};
|
||||
|
||||
/**
|
||||
* \brief Return the name of the animation
|
||||
*/
|
||||
const gd::String &GetName() const { return name; }
|
||||
|
||||
/**
|
||||
* \brief Change the name of the animation
|
||||
*/
|
||||
void SetName(const gd::String &name_) { name = name_; }
|
||||
|
||||
/**
|
||||
* \brief Return the name of the animation from the GLB file.
|
||||
*/
|
||||
const gd::String &GetSource() const { return source; }
|
||||
|
||||
/**
|
||||
* \brief Change the name of the animation from the GLB file.
|
||||
*/
|
||||
void SetSource(const gd::String &source_) { source = source_; }
|
||||
|
||||
/**
|
||||
* \brief Return true if the animation should loop.
|
||||
*/
|
||||
const bool ShouldLoop() const { return shouldLoop; }
|
||||
|
||||
/**
|
||||
* \brief Change whether the animation should loop or not.
|
||||
*/
|
||||
void SetShouldLoop(bool shouldLoop_) { shouldLoop = shouldLoop_; }
|
||||
|
||||
private:
|
||||
gd::String name;
|
||||
gd::String source;
|
||||
bool shouldLoop;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Particle Emitter object used for storage and for the IDE.
|
||||
*/
|
||||
class GD_EXTENSION_API Model3DObjectConfiguration
|
||||
: public gd::ObjectConfiguration {
|
||||
public:
|
||||
Model3DObjectConfiguration();
|
||||
virtual ~Model3DObjectConfiguration(){};
|
||||
virtual std::unique_ptr<gd::ObjectConfiguration> Clone() const override {
|
||||
return gd::make_unique<Model3DObjectConfiguration>(*this);
|
||||
}
|
||||
|
||||
virtual void ExposeResources(gd::ArbitraryResourceWorker &worker) override;
|
||||
|
||||
virtual std::map<gd::String, gd::PropertyDescriptor>
|
||||
GetProperties() const override;
|
||||
|
||||
virtual bool UpdateProperty(const gd::String &name,
|
||||
const gd::String &value) override;
|
||||
|
||||
virtual std::map<gd::String, gd::PropertyDescriptor>
|
||||
GetInitialInstanceProperties(const gd::InitialInstance &instance,
|
||||
gd::Project &project,
|
||||
gd::Layout &layout) override;
|
||||
|
||||
virtual bool UpdateInitialInstanceProperty(gd::InitialInstance &instance,
|
||||
const gd::String &name,
|
||||
const gd::String &value,
|
||||
gd::Project &project,
|
||||
gd::Layout &layout) override;
|
||||
|
||||
/** \name Animations
|
||||
* Methods related to animations management
|
||||
*/
|
||||
///@{
|
||||
/**
|
||||
* \brief Return the animation at the specified index.
|
||||
* If the index is out of bound, a "bad animation" object is returned.
|
||||
*/
|
||||
const Model3DAnimation &GetAnimation(std::size_t nb) const;
|
||||
|
||||
/**
|
||||
* \brief Return the animation at the specified index.
|
||||
* If the index is out of bound, a "bad animation" object is returned.
|
||||
*/
|
||||
Model3DAnimation &GetAnimation(std::size_t nb);
|
||||
|
||||
/**
|
||||
* \brief Return the number of animations this object has.
|
||||
*/
|
||||
std::size_t GetAnimationsCount() const { return animations.size(); };
|
||||
|
||||
/**
|
||||
* \brief Return true if the animation called "name" exists.
|
||||
*/
|
||||
bool HasAnimationNamed(const gd::String& name) const;
|
||||
|
||||
/**
|
||||
* \brief Add an animation at the end of the existing ones.
|
||||
*/
|
||||
void AddAnimation(const Model3DAnimation &animation);
|
||||
|
||||
/**
|
||||
* \brief Remove an animation.
|
||||
*/
|
||||
bool RemoveAnimation(std::size_t nb);
|
||||
|
||||
/**
|
||||
* \brief Remove all animations.
|
||||
*/
|
||||
void RemoveAllAnimations() { animations.clear(); }
|
||||
|
||||
/**
|
||||
* \brief Return true if the object hasn't any animation.
|
||||
*/
|
||||
bool HasNoAnimations() const { return animations.empty(); }
|
||||
|
||||
/**
|
||||
* \brief Swap the position of two animations
|
||||
*/
|
||||
void SwapAnimations(std::size_t firstIndex, std::size_t secondIndex);
|
||||
|
||||
/**
|
||||
* \brief Change the position of the specified animation
|
||||
*/
|
||||
void MoveAnimation(std::size_t oldIndex, std::size_t newIndex);
|
||||
|
||||
/**
|
||||
* \brief Return a read-only reference to the vector containing all the
|
||||
* animation of the object.
|
||||
*/
|
||||
const std::vector<Model3DAnimation> &GetAllAnimations() const {
|
||||
return animations;
|
||||
}
|
||||
|
||||
///@}
|
||||
|
||||
protected:
|
||||
virtual void DoUnserializeFrom(gd::Project &project,
|
||||
const gd::SerializerElement &element) override;
|
||||
virtual void DoSerializeTo(gd::SerializerElement &element) const override;
|
||||
|
||||
private:
|
||||
double width;
|
||||
double height;
|
||||
double depth;
|
||||
double rotationX;
|
||||
double rotationY;
|
||||
double rotationZ;
|
||||
|
||||
gd::String modelResourceName;
|
||||
gd::String materialType;
|
||||
gd::String originLocation;
|
||||
gd::String centerLocation;
|
||||
|
||||
bool keepAspectRatio;
|
||||
|
||||
std::vector<Model3DAnimation> animations;
|
||||
static Model3DAnimation badAnimation; //< Bad animation when an out of bound
|
||||
// animation is requested.
|
||||
};
|
@@ -1,4 +1,6 @@
|
||||
namespace gdjs {
|
||||
type Model3DAnimation = { name: string; source: string; loop: boolean };
|
||||
|
||||
/** Base parameters for {@link gdjs.Cube3DRuntimeObject} */
|
||||
export interface Model3DObjectData extends Object3DData {
|
||||
/** The base parameters of the Model3D object */
|
||||
@@ -9,9 +11,40 @@ namespace gdjs {
|
||||
rotationZ: number;
|
||||
keepAspectRatio: boolean;
|
||||
materialType: 'Basic' | 'StandardWithoutMetalness' | 'KeepOriginal';
|
||||
originLocation:
|
||||
| 'ModelOrigin'
|
||||
| 'ObjectCenter'
|
||||
| 'BottomCenterZ'
|
||||
| 'BottomCenterY'
|
||||
| 'TopLeft';
|
||||
centerLocation:
|
||||
| 'ModelOrigin'
|
||||
| 'ObjectCenter'
|
||||
| 'BottomCenterZ'
|
||||
| 'BottomCenterY';
|
||||
animations: Model3DAnimation[];
|
||||
};
|
||||
}
|
||||
|
||||
type FloatPoint3D = [float, float, float];
|
||||
|
||||
const getPointForLocation = (location: string): FloatPoint3D | null => {
|
||||
switch (location) {
|
||||
case 'ModelOrigin':
|
||||
return null;
|
||||
case 'ObjectCenter':
|
||||
return [0.5, 0.5, 0.5];
|
||||
case 'BottomCenterZ':
|
||||
return [0.5, 0.5, 0];
|
||||
case 'BottomCenterY':
|
||||
return [0.5, 1, 0.5];
|
||||
case 'TopLeft':
|
||||
return [0, 0, 0];
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A 3D object which displays a 3D model.
|
||||
*/
|
||||
@@ -22,17 +55,61 @@ namespace gdjs {
|
||||
_materialType: gdjs.Model3DRuntimeObject.MaterialType =
|
||||
gdjs.Model3DRuntimeObject.MaterialType.Basic;
|
||||
|
||||
/**
|
||||
* The local point of the model that will be at the object position.
|
||||
*
|
||||
* Coordinates are between 0 and 1.
|
||||
*
|
||||
* Its value is `null` when the point is configured to `"ModelOrigin"`
|
||||
* because the model origin needs to be evaluated according to the object
|
||||
* configuration.
|
||||
* @see gdjs.Model3DRuntimeObject3DRenderer.getOriginPoint
|
||||
*/
|
||||
_originPoint: FloatPoint3D | null;
|
||||
/**
|
||||
* The local point of the model that is used as rotation center.
|
||||
*
|
||||
* Coordinates are between 0 and 1.
|
||||
*
|
||||
* Its value is `null` when the point is configured to `"ModelOrigin"`
|
||||
* because the model origin needs to be evaluated according to the object
|
||||
* configuration.
|
||||
* @see gdjs.Model3DRuntimeObject3DRenderer.getCenterPoint
|
||||
*/
|
||||
_centerPoint: FloatPoint3D | null;
|
||||
|
||||
_animations: Model3DAnimation[];
|
||||
_currentAnimationIndex: integer = 0;
|
||||
_animationSpeedScale: float = 1;
|
||||
_animationPaused: boolean = false;
|
||||
|
||||
constructor(
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
objectData: Model3DObjectData
|
||||
) {
|
||||
super(instanceContainer, objectData);
|
||||
this._modelResourceName = objectData.content.modelResourceName;
|
||||
this._animations = objectData.content.animations;
|
||||
this._originPoint = getPointForLocation(
|
||||
objectData.content.originLocation
|
||||
);
|
||||
this._centerPoint = getPointForLocation(
|
||||
objectData.content.centerLocation
|
||||
);
|
||||
this._renderer = new gdjs.Model3DRuntimeObjectRenderer(
|
||||
this,
|
||||
instanceContainer
|
||||
);
|
||||
this._updateMaterialType(objectData);
|
||||
this._materialType = this._convertMaterialType(
|
||||
objectData.content.materialType
|
||||
);
|
||||
this._updateModel(objectData);
|
||||
if (this._animations.length > 0) {
|
||||
this._renderer.playAnimation(
|
||||
this._animations[0].source,
|
||||
this._animations[0].loop
|
||||
);
|
||||
}
|
||||
|
||||
// *ALWAYS* call `this.onCreated()` at the very end of your object constructor.
|
||||
this.onCreated();
|
||||
@@ -53,23 +130,42 @@ namespace gdjs {
|
||||
oldObjectData.content.keepAspectRatio !==
|
||||
newObjectData.content.keepAspectRatio
|
||||
) {
|
||||
this._updateDefaultTransformation(newObjectData);
|
||||
this._updateModel(newObjectData);
|
||||
}
|
||||
if (
|
||||
oldObjectData.content.materialType !==
|
||||
newObjectData.content.materialType
|
||||
) {
|
||||
this._updateMaterialType(newObjectData);
|
||||
this._materialType = this._convertMaterialType(
|
||||
newObjectData.content.materialType
|
||||
);
|
||||
this._updateModel(newObjectData);
|
||||
}
|
||||
if (
|
||||
oldObjectData.content.originLocation !==
|
||||
newObjectData.content.originLocation
|
||||
) {
|
||||
this._originPoint = getPointForLocation(
|
||||
newObjectData.content.originLocation
|
||||
);
|
||||
}
|
||||
if (
|
||||
oldObjectData.content.centerLocation !==
|
||||
newObjectData.content.centerLocation
|
||||
) {
|
||||
this._centerPoint = getPointForLocation(
|
||||
newObjectData.content.centerLocation
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
_updateDefaultTransformation(objectData: Model3DObjectData) {
|
||||
_updateModel(objectData: Model3DObjectData) {
|
||||
const rotationX = objectData.content.rotationX || 0;
|
||||
const rotationY = objectData.content.rotationY || 0;
|
||||
const rotationZ = objectData.content.rotationZ || 0;
|
||||
const keepAspectRatio = objectData.content.keepAspectRatio;
|
||||
this._renderer._updateDefaultTransformation(
|
||||
this._renderer._updateModel(
|
||||
rotationX,
|
||||
rotationY,
|
||||
rotationZ,
|
||||
@@ -96,12 +192,118 @@ namespace gdjs {
|
||||
}
|
||||
}
|
||||
|
||||
_updateMaterialType(objectData: Model3DObjectData) {
|
||||
this._materialType = this._convertMaterialType(
|
||||
objectData.content.materialType
|
||||
update(instanceContainer: gdjs.RuntimeInstanceContainer): void {
|
||||
const elapsedTime = this.getElapsedTime() / 1000;
|
||||
this._renderer.updateAnimation(elapsedTime * this._animationSpeedScale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the index of the animation being played.
|
||||
* @return The index of the new animation being played
|
||||
*/
|
||||
getAnimationIndex(): number {
|
||||
return this._currentAnimationIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the animation being played.
|
||||
* @param animationIndex The index of the new animation to be played
|
||||
*/
|
||||
setAnimationIndex(animationIndex: number): void {
|
||||
animationIndex = animationIndex | 0;
|
||||
if (
|
||||
animationIndex < this._animations.length &&
|
||||
this._currentAnimationIndex !== animationIndex &&
|
||||
animationIndex >= 0
|
||||
) {
|
||||
const animation = this._animations[animationIndex];
|
||||
this._currentAnimationIndex = animationIndex;
|
||||
this._renderer.playAnimation(animation.source, animation.loop);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the animation being played.
|
||||
* @return The name of the new animation being played
|
||||
*/
|
||||
getAnimationName(): string {
|
||||
if (this._currentAnimationIndex >= this._animations.length) {
|
||||
return '';
|
||||
}
|
||||
return this._animations[this._currentAnimationIndex].name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the animation being played.
|
||||
* @param newAnimationName The name of the new animation to be played
|
||||
*/
|
||||
setAnimationName(newAnimationName: string): void {
|
||||
if (!newAnimationName) {
|
||||
return;
|
||||
}
|
||||
const animationIndex = this._animations.findIndex(
|
||||
(animation) => animation.name === newAnimationName
|
||||
);
|
||||
this._renderer._updateMaterials();
|
||||
this._updateDefaultTransformation(objectData);
|
||||
if (animationIndex >= 0) {
|
||||
this.setAnimationIndex(animationIndex);
|
||||
}
|
||||
}
|
||||
|
||||
isCurrentAnimationName(name: string): boolean {
|
||||
return this.getAnimationName() === name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if animation has ended.
|
||||
* The animation had ended if:
|
||||
* - it's not configured as a loop;
|
||||
* - the current frame is the last frame;
|
||||
* - the last frame has been displayed long enough.
|
||||
*/
|
||||
hasAnimationEnded(): boolean {
|
||||
return this._renderer.hasAnimationEnded();
|
||||
}
|
||||
|
||||
isAnimationPaused() {
|
||||
return this._animationPaused;
|
||||
}
|
||||
|
||||
pauseAnimation() {
|
||||
this._animationPaused = true;
|
||||
return this._renderer.pauseAnimation();
|
||||
}
|
||||
|
||||
resumeAnimation() {
|
||||
this._animationPaused = false;
|
||||
return this._renderer.resumeAnimation();
|
||||
}
|
||||
|
||||
getAnimationSpeedScale() {
|
||||
return this._animationSpeedScale;
|
||||
}
|
||||
|
||||
setAnimationSpeedScale(ratio: float): void {
|
||||
this._animationSpeedScale = ratio;
|
||||
}
|
||||
|
||||
getCenterX(): float {
|
||||
const centerPoint = this._renderer.getCenterPoint();
|
||||
return this.getWidth() * centerPoint[0];
|
||||
}
|
||||
|
||||
getCenterY(): float {
|
||||
const centerPoint = this._renderer.getCenterPoint();
|
||||
return this.getHeight() * centerPoint[1];
|
||||
}
|
||||
|
||||
getDrawableX(): float {
|
||||
const originPoint = this._renderer.getOriginPoint();
|
||||
return this.getX() - this.getWidth() * originPoint[0];
|
||||
}
|
||||
|
||||
getDrawableY(): float {
|
||||
const originPoint = this._renderer.getOriginPoint();
|
||||
return this.getY() - this.getHeight() * originPoint[1];
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,38 +1,144 @@
|
||||
namespace gdjs {
|
||||
type FloatPoint3D = [float, float, float];
|
||||
|
||||
const removeMetalness = (material: THREE.Material): void => {
|
||||
//@ts-ignore
|
||||
if (material.metalness) {
|
||||
//@ts-ignore
|
||||
material.metalness = 0;
|
||||
}
|
||||
};
|
||||
|
||||
const removeMetalnessFromMesh = (node: THREE.Object3D<THREE.Event>) => {
|
||||
const mesh = node as THREE.Mesh;
|
||||
if (!mesh.material) {
|
||||
return;
|
||||
}
|
||||
if (Array.isArray(mesh.material)) {
|
||||
for (let index = 0; index < mesh.material.length; index++) {
|
||||
removeMetalness(mesh.material[index]);
|
||||
}
|
||||
} else {
|
||||
removeMetalness(mesh.material);
|
||||
}
|
||||
};
|
||||
|
||||
const traverseToRemoveMetalnessFromMeshes = (
|
||||
node: THREE.Object3D<THREE.Event>
|
||||
) => node.traverse(removeMetalnessFromMesh);
|
||||
|
||||
const convertToBasicMaterial = (
|
||||
material: THREE.Material
|
||||
): THREE.MeshBasicMaterial => {
|
||||
const basicMaterial = new THREE.MeshBasicMaterial();
|
||||
//@ts-ignore
|
||||
if (material.color) {
|
||||
//@ts-ignore
|
||||
basicMaterial.color = material.color;
|
||||
}
|
||||
//@ts-ignore
|
||||
if (material.map) {
|
||||
//@ts-ignore
|
||||
basicMaterial.map = material.map;
|
||||
}
|
||||
return basicMaterial;
|
||||
};
|
||||
|
||||
const setBasicMaterialTo = (node: THREE.Object3D<THREE.Event>): void => {
|
||||
const mesh = node as THREE.Mesh;
|
||||
if (!mesh.material) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Array.isArray(mesh.material)) {
|
||||
for (let index = 0; index < mesh.material.length; index++) {
|
||||
mesh.material[index] = convertToBasicMaterial(mesh.material[index]);
|
||||
}
|
||||
} else {
|
||||
mesh.material = convertToBasicMaterial(mesh.material);
|
||||
}
|
||||
};
|
||||
|
||||
const traverseToSetBasicMaterialFromMeshes = (
|
||||
node: THREE.Object3D<THREE.Event>
|
||||
) => node.traverse(setBasicMaterialTo);
|
||||
|
||||
class Model3DRuntimeObject3DRenderer extends gdjs.RuntimeObject3DRenderer {
|
||||
private _model3DRuntimeObject: gdjs.Model3DRuntimeObject;
|
||||
/**
|
||||
* The 3D model stretched in a 1x1x1 cube.
|
||||
*/
|
||||
private _threeObject: THREE.Object3D;
|
||||
private _originalModel: THREE_ADDONS.GLTF;
|
||||
private _animationMixer: THREE.AnimationMixer;
|
||||
private _action: THREE.AnimationAction | null;
|
||||
|
||||
/**
|
||||
* The model origin evaluated according to the object configuration.
|
||||
*
|
||||
* Coordinates are between 0 and 1.
|
||||
*/
|
||||
private _modelOriginPoint: FloatPoint3D;
|
||||
|
||||
constructor(
|
||||
runtimeObject: gdjs.Model3DRuntimeObject,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer
|
||||
) {
|
||||
// @ts-ignore It can't be null if THREE exists.
|
||||
const originalModelMesh: THREE.Object3D = instanceContainer
|
||||
// GLB files with skeleton must not have any transformation to work properly.
|
||||
const originalModel = instanceContainer
|
||||
.getGame()
|
||||
.getModel3DManager()
|
||||
.getModel(runtimeObject._modelResourceName);
|
||||
const modelObject3D = originalModelMesh.clone();
|
||||
// _updateModel will actually add a clone of the model.
|
||||
const model = new THREE.Group();
|
||||
|
||||
// Create a group to transform the object according to
|
||||
// position, angle and dimensions.
|
||||
const group = new THREE.Group();
|
||||
group.rotation.order = 'ZYX';
|
||||
group.add(modelObject3D);
|
||||
group.add(model);
|
||||
super(runtimeObject, instanceContainer, group);
|
||||
|
||||
this._model3DRuntimeObject = runtimeObject;
|
||||
this._threeObject = modelObject3D;
|
||||
this._threeObject = model;
|
||||
this._originalModel = originalModel;
|
||||
this._modelOriginPoint = [0, 0, 0];
|
||||
|
||||
this.updateSize();
|
||||
this.updatePosition();
|
||||
this.updateRotation();
|
||||
|
||||
this._animationMixer = new THREE.AnimationMixer(model);
|
||||
this._action = null;
|
||||
}
|
||||
|
||||
_updateDefaultTransformation(
|
||||
updateAnimation(timeDelta: float) {
|
||||
this._animationMixer.update(timeDelta);
|
||||
}
|
||||
|
||||
updatePosition() {
|
||||
const originPoint = this.getOriginPoint();
|
||||
const centerPoint = this.getCenterPoint();
|
||||
this.get3DRendererObject().position.set(
|
||||
this._object.getX() -
|
||||
this._object.getWidth() * (originPoint[0] - centerPoint[0]),
|
||||
this._object.getY() -
|
||||
this._object.getHeight() * (originPoint[1] - centerPoint[1]),
|
||||
this._object.getZ() -
|
||||
this._object.getDepth() * (originPoint[2] - centerPoint[2])
|
||||
);
|
||||
}
|
||||
|
||||
getOriginPoint() {
|
||||
return this._model3DRuntimeObject._originPoint || this._modelOriginPoint;
|
||||
}
|
||||
|
||||
getCenterPoint() {
|
||||
return this._model3DRuntimeObject._centerPoint || this._modelOriginPoint;
|
||||
}
|
||||
|
||||
private _updateDefaultTransformation(
|
||||
threeObject: THREE.Object3D,
|
||||
rotationX: float,
|
||||
rotationY: float,
|
||||
rotationZ: float,
|
||||
@@ -41,38 +147,63 @@ namespace gdjs {
|
||||
originalDepth: float,
|
||||
keepAspectRatio: boolean
|
||||
) {
|
||||
const boundingBox = this._getModelAABB(rotationX, rotationY, rotationZ);
|
||||
threeObject.rotation.set(
|
||||
gdjs.toRad(rotationX),
|
||||
gdjs.toRad(rotationY),
|
||||
gdjs.toRad(rotationZ)
|
||||
);
|
||||
threeObject.updateMatrixWorld(true);
|
||||
const boundingBox = new THREE.Box3().setFromObject(threeObject);
|
||||
|
||||
const modelWidth = boundingBox.max.x - boundingBox.min.x;
|
||||
const modelHeight = boundingBox.max.y - boundingBox.min.y;
|
||||
const modelDepth = boundingBox.max.z - boundingBox.min.z;
|
||||
this._modelOriginPoint[0] = -boundingBox.min.x / modelWidth;
|
||||
this._modelOriginPoint[1] = -boundingBox.min.y / modelHeight;
|
||||
this._modelOriginPoint[2] = -boundingBox.min.z / modelDepth;
|
||||
|
||||
// The model is flipped on Y axis.
|
||||
this._modelOriginPoint[1] = 1 - this._modelOriginPoint[1];
|
||||
|
||||
// Center the model.
|
||||
this._threeObject.position.set(
|
||||
-(boundingBox.min.x + boundingBox.max.x) / 2,
|
||||
(this._threeObject.position.y =
|
||||
-(boundingBox.min.y + boundingBox.max.y) / 2),
|
||||
(this._threeObject.position.z =
|
||||
-(boundingBox.min.z + boundingBox.max.z) / 2)
|
||||
);
|
||||
const centerPoint = this._model3DRuntimeObject._centerPoint;
|
||||
if (centerPoint) {
|
||||
threeObject.position.set(
|
||||
-(
|
||||
boundingBox.min.x +
|
||||
(boundingBox.max.x - boundingBox.min.x) * centerPoint[0]
|
||||
),
|
||||
// The model is flipped on Y axis.
|
||||
-(
|
||||
boundingBox.min.y +
|
||||
(boundingBox.max.y - boundingBox.min.y) * (1 - centerPoint[1])
|
||||
),
|
||||
-(
|
||||
boundingBox.min.z +
|
||||
(boundingBox.max.z - boundingBox.min.z) * centerPoint[2]
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Rotate the model.
|
||||
this._threeObject.scale.set(1, 1, 1);
|
||||
this._threeObject.rotation.set(
|
||||
threeObject.scale.set(1, 1, 1);
|
||||
threeObject.rotation.set(
|
||||
gdjs.toRad(rotationX),
|
||||
gdjs.toRad(rotationY),
|
||||
gdjs.toRad(rotationZ)
|
||||
);
|
||||
|
||||
// Stretch the model in a 1x1x1 cube.
|
||||
const modelWidth = boundingBox.max.x - boundingBox.min.x;
|
||||
const modelHeight = boundingBox.max.y - boundingBox.min.y;
|
||||
const modelDepth = boundingBox.max.z - boundingBox.min.z;
|
||||
|
||||
const scaleX = 1 / modelWidth;
|
||||
const scaleY = 1 / modelHeight;
|
||||
const scaleZ = 1 / modelDepth;
|
||||
|
||||
const scaleMatrix = new THREE.Matrix4();
|
||||
scaleMatrix.makeScale(scaleX, scaleY, scaleZ);
|
||||
this._threeObject.updateMatrix();
|
||||
this._threeObject.applyMatrix4(scaleMatrix);
|
||||
// Flip on Y because the Y axis is on the opposite side of direct basis.
|
||||
// It avoids models to be like a mirror refection.
|
||||
scaleMatrix.makeScale(scaleX, -scaleY, scaleZ);
|
||||
threeObject.updateMatrix();
|
||||
threeObject.applyMatrix4(scaleMatrix);
|
||||
|
||||
if (keepAspectRatio) {
|
||||
// Reduce the object dimensions to keep aspect ratio.
|
||||
@@ -85,98 +216,138 @@ namespace gdjs {
|
||||
this._object._setOriginalHeight(scaleRatio * modelHeight);
|
||||
this._object._setOriginalDepth(scaleRatio * modelDepth);
|
||||
}
|
||||
|
||||
this._threeObject.updateMatrix();
|
||||
}
|
||||
|
||||
private _getModelAABB(
|
||||
_updateModel(
|
||||
rotationX: float,
|
||||
rotationY: float,
|
||||
rotationZ: float
|
||||
rotationZ: float,
|
||||
originalWidth: float,
|
||||
originalHeight: float,
|
||||
originalDepth: float,
|
||||
keepAspectRatio: boolean
|
||||
) {
|
||||
// The original model is used because `setFromObject` is working in
|
||||
// world transformation.
|
||||
// Start from the original model because:
|
||||
// - _replaceMaterials is destructive
|
||||
// - _updateDefaultTransformation may need to work with meshes in local space
|
||||
|
||||
// @ts-ignore It can't be null if THREE exists.
|
||||
const originalModelMesh: THREE.Object3D = this._object
|
||||
.getInstanceContainer()
|
||||
.getGame()
|
||||
.getModel3DManager()
|
||||
.getModel(this._model3DRuntimeObject._modelResourceName);
|
||||
// This group hold the rotation defined by properties.
|
||||
const threeObject = new THREE.Group();
|
||||
threeObject.rotation.order = 'ZYX';
|
||||
const root = THREE_ADDONS.SkeletonUtils.clone(this._originalModel.scene);
|
||||
threeObject.add(root);
|
||||
|
||||
originalModelMesh.rotation.set(
|
||||
gdjs.toRad(rotationX),
|
||||
gdjs.toRad(rotationY),
|
||||
gdjs.toRad(rotationZ)
|
||||
this._replaceMaterials(threeObject);
|
||||
|
||||
this._updateDefaultTransformation(
|
||||
threeObject,
|
||||
rotationX,
|
||||
rotationY,
|
||||
rotationZ,
|
||||
originalWidth,
|
||||
originalHeight,
|
||||
originalDepth,
|
||||
keepAspectRatio
|
||||
);
|
||||
|
||||
const aabb = new THREE.Box3().setFromObject(originalModelMesh);
|
||||
|
||||
// Revert changes.
|
||||
originalModelMesh.rotation.set(0, 0, 0);
|
||||
|
||||
return aabb;
|
||||
}
|
||||
|
||||
_updateMaterials() {
|
||||
// @ts-ignore It can't be null if THREE exists.
|
||||
const originalModelMesh: THREE.Object3D = this._model3DRuntimeObject
|
||||
.getInstanceContainer()
|
||||
.getGame()
|
||||
.getModel3DManager()
|
||||
.getModel(this._model3DRuntimeObject._modelResourceName);
|
||||
const modelObject3D = originalModelMesh.clone();
|
||||
|
||||
// Replace the 3D object.
|
||||
this.get3DRendererObject().remove(this._threeObject);
|
||||
this.get3DRendererObject().add(modelObject3D);
|
||||
this.get3DRendererObject().add(threeObject);
|
||||
this._threeObject = threeObject;
|
||||
|
||||
this._threeObject = modelObject3D;
|
||||
|
||||
this._replaceMaterials();
|
||||
// Start the current animation on the new 3D object.
|
||||
this._animationMixer = new THREE.AnimationMixer(root);
|
||||
const isAnimationPaused = this._model3DRuntimeObject.isAnimationPaused();
|
||||
this._model3DRuntimeObject.setAnimationIndex(
|
||||
this._model3DRuntimeObject.getAnimationIndex()
|
||||
);
|
||||
if (isAnimationPaused) {
|
||||
this.pauseAnimation();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace materials to better work with lights (or no light).
|
||||
*/
|
||||
_replaceMaterials() {
|
||||
private _replaceMaterials(threeObject: THREE.Object3D) {
|
||||
if (
|
||||
this._model3DRuntimeObject._materialType ===
|
||||
gdjs.Model3DRuntimeObject.MaterialType.StandardWithoutMetalness
|
||||
) {
|
||||
this._threeObject.traverse((node) => {
|
||||
if (node.type === 'Mesh') {
|
||||
const mesh = node as THREE.Mesh;
|
||||
const material = mesh.material as THREE.MeshStandardMaterial;
|
||||
//@ts-ignore
|
||||
if (material.metalness) {
|
||||
//@ts-ignore
|
||||
material.metalness = 0;
|
||||
}
|
||||
}
|
||||
});
|
||||
traverseToRemoveMetalnessFromMeshes(threeObject);
|
||||
} else if (
|
||||
this._model3DRuntimeObject._materialType ===
|
||||
gdjs.Model3DRuntimeObject.MaterialType.Basic
|
||||
) {
|
||||
this._threeObject.traverse((node) => {
|
||||
if (node.type === 'Mesh') {
|
||||
const mesh = node as THREE.Mesh;
|
||||
const basicMaterial = new THREE.MeshBasicMaterial();
|
||||
//@ts-ignore
|
||||
if (mesh.material.color) {
|
||||
//@ts-ignore
|
||||
basicMaterial.color = mesh.material.color;
|
||||
}
|
||||
//@ts-ignore
|
||||
if (mesh.material.map) {
|
||||
//@ts-ignore
|
||||
basicMaterial.map = mesh.material.map;
|
||||
}
|
||||
mesh.material = basicMaterial;
|
||||
}
|
||||
});
|
||||
traverseToSetBasicMaterialFromMeshes(threeObject);
|
||||
}
|
||||
}
|
||||
|
||||
getAnimationCount() {
|
||||
return this._originalModel.animations.length;
|
||||
}
|
||||
|
||||
getAnimationName(animationIndex: integer) {
|
||||
return this._originalModel.animations[animationIndex].name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if animation has ended.
|
||||
* The animation had ended if:
|
||||
* - it's not configured as a loop;
|
||||
* - the current frame is the last frame;
|
||||
* - the last frame has been displayed long enough.
|
||||
*/
|
||||
hasAnimationEnded(): boolean {
|
||||
if (!this._action) {
|
||||
return true;
|
||||
}
|
||||
return !this._action.isRunning();
|
||||
}
|
||||
|
||||
animationPaused() {
|
||||
if (!this._action) {
|
||||
return;
|
||||
}
|
||||
return this._action.paused;
|
||||
}
|
||||
|
||||
pauseAnimation() {
|
||||
if (!this._action) {
|
||||
return;
|
||||
}
|
||||
this._action.paused = true;
|
||||
}
|
||||
|
||||
resumeAnimation() {
|
||||
if (!this._action) {
|
||||
return;
|
||||
}
|
||||
this._action.paused = false;
|
||||
}
|
||||
|
||||
playAnimation(animationName: string, shouldLoop: boolean) {
|
||||
this._animationMixer.stopAllAction();
|
||||
const clip = THREE.AnimationClip.findByName(
|
||||
this._originalModel.animations,
|
||||
animationName
|
||||
);
|
||||
if (!clip) {
|
||||
console.error(
|
||||
`The GLB file: ${this._model3DRuntimeObject._modelResourceName} doesn't have any animation named: ${animationName}`
|
||||
);
|
||||
return;
|
||||
}
|
||||
this._action = this._animationMixer.clipAction(clip);
|
||||
this._action.setLoop(
|
||||
shouldLoop ? THREE.LoopRepeat : THREE.LoopOnce,
|
||||
Number.POSITIVE_INFINITY
|
||||
);
|
||||
this._action.clampWhenFinished = true;
|
||||
this._action.play();
|
||||
// Make sure the first frame is displayed.
|
||||
this._animationMixer.update(0);
|
||||
}
|
||||
}
|
||||
|
||||
export const Model3DRuntimeObjectRenderer = Model3DRuntimeObject3DRenderer;
|
||||
|
@@ -147,7 +147,7 @@ module.exports = {
|
||||
.addCondition(
|
||||
'AppOpenErrored',
|
||||
_('App open errored'),
|
||||
_('Check if there was a error while loading the app open.'),
|
||||
_('Check if there was an error while loading the app open.'),
|
||||
_('App open had an error'),
|
||||
'',
|
||||
'JsPlatform/Extensions/admobicon24.png',
|
||||
|
@@ -606,7 +606,7 @@ module.exports = {
|
||||
);
|
||||
|
||||
if (this._instance.hasCustomSize() && this._pixiObject) {
|
||||
const customWidth = this._instance.getCustomWidth();
|
||||
const customWidth = this.getCustomWidth();
|
||||
if (
|
||||
this._pixiObject &&
|
||||
this._pixiObject._style.wordWrapWidth !== customWidth
|
||||
|
@@ -711,7 +711,7 @@ module.exports = {
|
||||
const wordWrap = properties.get('wordWrap').getValue() === 'true';
|
||||
if (wordWrap && this._instance.hasCustomSize()) {
|
||||
this._pixiObject.maxWidth =
|
||||
this._instance.getCustomWidth() / this._pixiObject.scale.x;
|
||||
this.getCustomWidth() / this._pixiObject.scale.x;
|
||||
this._pixiObject.dirty = true;
|
||||
} else {
|
||||
this._pixiObject.maxWidth = 0;
|
||||
|
@@ -8,6 +8,7 @@ project(GD-Extensions)
|
||||
include(CMakeUtils.txt) #Functions to factor common tasks done in CMakeLists.txt of extensions
|
||||
|
||||
#Add all the CMakeLists (for non pure JS extensions):
|
||||
ADD_SUBDIRECTORY(3D)
|
||||
ADD_SUBDIRECTORY(AnchorBehavior)
|
||||
ADD_SUBDIRECTORY(DestroyOutsideBehavior)
|
||||
ADD_SUBDIRECTORY(DraggableBehavior)
|
||||
|
@@ -46,7 +46,7 @@ module.exports = {
|
||||
_(
|
||||
'Load a dialogue data object - Yarn json format, stored in a scene variable. Use this command to load all the Dialogue data at the beginning of the game.'
|
||||
),
|
||||
_('Load dialogue data from Scene variable _PARAM1_'),
|
||||
_('Load dialogue data from Scene variable _PARAM0_'),
|
||||
'',
|
||||
'JsPlatform/Extensions/yarn32.png',
|
||||
'JsPlatform/Extensions/yarn32.png'
|
||||
|
@@ -563,8 +563,8 @@ module.exports = {
|
||||
this._pixiObject.rotation = RenderedInstance.toRad(
|
||||
this._instance.getAngle()
|
||||
);
|
||||
// Custom size can be read in instance.getCustomWidth() and
|
||||
// instance.getCustomHeight()
|
||||
// Custom size can be read in this.getCustomWidth() and
|
||||
// this.getCustomHeight()
|
||||
};
|
||||
|
||||
/**
|
||||
|
@@ -41,7 +41,7 @@ namespace gdjs {
|
||||
/**
|
||||
* The current authentication status.
|
||||
*/
|
||||
export let authentified = false;
|
||||
export let authenticated = false;
|
||||
|
||||
/**
|
||||
* The logged-in users data.
|
||||
@@ -345,10 +345,13 @@ namespace gdjs {
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if the user is currently authentified.
|
||||
* @see authentified
|
||||
* Returns true if the user is currently authenticated.
|
||||
* @see authenticated
|
||||
*/
|
||||
export const isAuthentified = (): boolean => authentified;
|
||||
export const isAuthenticated = (): boolean => authenticated;
|
||||
|
||||
/** @deprecated Use isAuthenticated instead. */
|
||||
export const isAuthentified = isAuthenticated;
|
||||
|
||||
/**
|
||||
* Signs the user in with basic email-password authentication.
|
||||
@@ -442,14 +445,14 @@ namespace gdjs {
|
||||
firebaseTools.onAppCreated.push(() => {
|
||||
firebase.auth().onAuthStateChanged((user) => {
|
||||
if (user) {
|
||||
authentified = true;
|
||||
authenticated = true;
|
||||
currentUser = user;
|
||||
user.getIdToken().then(
|
||||
// Prefetch the token
|
||||
(token) => (_token = token)
|
||||
);
|
||||
} else {
|
||||
authentified = false;
|
||||
authenticated = false;
|
||||
currentUser = null;
|
||||
}
|
||||
});
|
||||
|
@@ -14,7 +14,7 @@ namespace gdjs {
|
||||
/**
|
||||
* Uploads a file as string to the firebase storage bucket.
|
||||
* @param file - The entire file as string.
|
||||
* @param onlinePath - The path under wich the file will be accessible on the bucket.
|
||||
* @param onlinePath - The path under which the file will be accessible on the bucket.
|
||||
* @param [type] - The type/format of the string to upload.
|
||||
* @param [callbackStateVariable] - The variable where to store if the operation was successful.
|
||||
* @param [callbackValueVariable] - The variable where to store the result (url to the file).
|
||||
|
@@ -395,7 +395,7 @@ module.exports = {
|
||||
.addIncludeFile('Extensions/Firebase/A_firebasejs/B_firebase-auth.js')
|
||||
.addIncludeFile('Extensions/Firebase/B_firebasetools/C_firebasetools.js')
|
||||
.addIncludeFile('Extensions/Firebase/B_firebasetools/D_authtools.js')
|
||||
.setFunctionName('gdjs.evtTools.firebaseTools.auth.isAuthentified');
|
||||
.setFunctionName('gdjs.evtTools.firebaseTools.auth.isAuthenticated');
|
||||
|
||||
extension
|
||||
.addStrExpression(
|
||||
|
@@ -533,7 +533,7 @@ describeIfOnline('Firebase extension end-to-end tests', function () {
|
||||
const password2 = `myNewPass${Math.random().toString(16)}${Date.now()}!`;
|
||||
|
||||
const expectToNotLogin = async (password) => {
|
||||
if (gdjs.evtTools.firebaseTools.auth.isAuthentified())
|
||||
if (gdjs.evtTools.firebaseTools.auth.isAuthenticated())
|
||||
await firebase.auth().signOut();
|
||||
|
||||
let errors = false;
|
||||
@@ -553,11 +553,11 @@ describeIfOnline('Firebase extension end-to-end tests', function () {
|
||||
if (!errors)
|
||||
throw new Error('Expected wrong credentials to prevent login');
|
||||
|
||||
expect(gdjs.evtTools.firebaseTools.auth.isAuthentified()).to.not.be.ok();
|
||||
expect(gdjs.evtTools.firebaseTools.auth.isAuthenticated()).to.not.be.ok();
|
||||
};
|
||||
|
||||
const expectToLogin = async (password) => {
|
||||
if (gdjs.evtTools.firebaseTools.auth.isAuthentified())
|
||||
if (gdjs.evtTools.firebaseTools.auth.isAuthenticated())
|
||||
await firebase.auth().signOut();
|
||||
|
||||
await promisifyCallbackVariables((callback) =>
|
||||
@@ -568,13 +568,13 @@ describeIfOnline('Firebase extension end-to-end tests', function () {
|
||||
)
|
||||
);
|
||||
|
||||
expect(gdjs.evtTools.firebaseTools.auth.isAuthentified()).to.be.ok();
|
||||
expect(gdjs.evtTools.firebaseTools.auth.isAuthenticated()).to.be.ok();
|
||||
};
|
||||
|
||||
before(async () => firebase.auth().signOut());
|
||||
|
||||
it('let users create accounts', async () => {
|
||||
expect(gdjs.evtTools.firebaseTools.auth.isAuthentified()).to.not.be.ok();
|
||||
expect(gdjs.evtTools.firebaseTools.auth.isAuthenticated()).to.not.be.ok();
|
||||
|
||||
await promisifyCallbackVariables((callback) =>
|
||||
gdjs.evtTools.firebaseTools.auth.createAccountWithEmail(
|
||||
@@ -584,13 +584,13 @@ describeIfOnline('Firebase extension end-to-end tests', function () {
|
||||
)
|
||||
);
|
||||
|
||||
expect(gdjs.evtTools.firebaseTools.auth.isAuthentified()).to.be.ok();
|
||||
expect(gdjs.evtTools.firebaseTools.auth.isAuthenticated()).to.be.ok();
|
||||
});
|
||||
|
||||
it('let users log out', async () => {
|
||||
expect(gdjs.evtTools.firebaseTools.auth.isAuthentified()).to.be.ok();
|
||||
expect(gdjs.evtTools.firebaseTools.auth.isAuthenticated()).to.be.ok();
|
||||
await firebase.auth().signOut();
|
||||
expect(gdjs.evtTools.firebaseTools.auth.isAuthentified()).to.not.be.ok();
|
||||
expect(gdjs.evtTools.firebaseTools.auth.isAuthenticated()).to.not.be.ok();
|
||||
});
|
||||
|
||||
it('prevents logging in with invalid credentials', async () =>
|
||||
|
@@ -18,6 +18,7 @@ export type ObjectsRenderingService = {
|
||||
gd: libGDevelop,
|
||||
PIXI: any,
|
||||
THREE: any,
|
||||
THREE_ADDONS: {SkeletonUtils: any},
|
||||
RenderedInstance: any,
|
||||
Rendered3DInstance: any,
|
||||
registerInstanceRenderer: (objectType: string, renderer: any) => void,
|
||||
|
@@ -290,74 +290,31 @@ module.exports = {
|
||||
.getValue()
|
||||
);
|
||||
if (this._radius <= 0) this._radius = 1;
|
||||
const colorHex = objectsRenderingService.rgbOrHexToHexNumber(
|
||||
const color = objectsRenderingService.rgbOrHexToHexNumber(
|
||||
this._associatedObjectConfiguration
|
||||
.getProperties(this.project)
|
||||
.get('color')
|
||||
.getValue()
|
||||
);
|
||||
this._color = [
|
||||
((colorHex >> 16) & 0xff) / 255,
|
||||
((colorHex >> 8) & 0xff) / 255,
|
||||
(colorHex & 0xff) / 255,
|
||||
];
|
||||
|
||||
const geometry = new PIXI.Geometry();
|
||||
const shader = PIXI.Shader.from(
|
||||
`
|
||||
precision mediump float;
|
||||
attribute vec2 aVertexPosition;
|
||||
// The icon in the middle.
|
||||
const lightIconSprite = new PIXI.Sprite(PIXI.Texture.from('CppPlatform/Extensions/lightIcon32.png'));
|
||||
lightIconSprite.anchor.x = 0.5;
|
||||
lightIconSprite.anchor.y = 0.5;
|
||||
|
||||
uniform mat3 translationMatrix;
|
||||
uniform mat3 projectionMatrix;
|
||||
varying vec2 vPos;
|
||||
|
||||
void main() {
|
||||
vPos = aVertexPosition;
|
||||
gl_Position = vec4((projectionMatrix * translationMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);
|
||||
}`,
|
||||
`
|
||||
precision mediump float;
|
||||
uniform vec2 center;
|
||||
uniform float radius;
|
||||
uniform vec3 color;
|
||||
uniform mat3 translationMatrix;
|
||||
uniform mat3 projectionMatrix;
|
||||
|
||||
varying vec2 vPos;
|
||||
|
||||
void main() {
|
||||
float l = length(vPos - center);
|
||||
float intensity = 0.0;
|
||||
if(l < radius)
|
||||
intensity = clamp((radius - l)*(radius - l)/(radius*radius), 0.0, 1.0);
|
||||
gl_FragColor = vec4(color*intensity, 1.0);
|
||||
}
|
||||
`,
|
||||
{
|
||||
center: [this._instance.getX(), this._instance.getY()],
|
||||
radius: this._radius,
|
||||
color: this._color,
|
||||
}
|
||||
// The circle to show the radius of the light.
|
||||
const radiusBorderWidth = 2;
|
||||
const radiusGraphics = new PIXI.Graphics();
|
||||
radiusGraphics.lineStyle(
|
||||
radiusBorderWidth,
|
||||
color,
|
||||
0.8
|
||||
);
|
||||
radiusGraphics.drawCircle(0, 0, Math.max(1, this._radius - radiusBorderWidth));
|
||||
|
||||
this._vertexBuffer = new Float32Array([
|
||||
this._instance.getX() - this._radius,
|
||||
this._instance.getY() + this._radius,
|
||||
this._instance.getX() + this._radius,
|
||||
this._instance.getY() + this._radius,
|
||||
this._instance.getX() + this._radius,
|
||||
this._instance.getY() - this._radius,
|
||||
this._instance.getX() - this._radius,
|
||||
this._instance.getY() - this._radius,
|
||||
]);
|
||||
|
||||
geometry
|
||||
.addAttribute('aVertexPosition', this._vertexBuffer, 2)
|
||||
.addIndex([0, 1, 2, 2, 3, 0]);
|
||||
|
||||
this._pixiObject = new PIXI.Mesh(geometry, shader);
|
||||
this._pixiObject.blendMode = PIXI.BLEND_MODES.ADD;
|
||||
this._pixiObject = new PIXI.Container();
|
||||
this._pixiObject.addChild(lightIconSprite);
|
||||
this._pixiObject.addChild(radiusGraphics);
|
||||
this._pixiContainer.addChild(this._pixiObject);
|
||||
this.update();
|
||||
}
|
||||
@@ -380,37 +337,22 @@ module.exports = {
|
||||
* This is called to update the PIXI object on the scene editor
|
||||
*/
|
||||
RenderedLightObjectInstance.prototype.update = function () {
|
||||
this._pixiObject.shader.uniforms.center = new Float32Array([
|
||||
this._instance.getX(),
|
||||
this._instance.getY(),
|
||||
]);
|
||||
|
||||
this._vertexBuffer[0] = this._instance.getX() - this._radius;
|
||||
this._vertexBuffer[1] = this._instance.getY() + this._radius;
|
||||
this._vertexBuffer[2] = this._instance.getX() + this._radius;
|
||||
this._vertexBuffer[3] = this._instance.getY() + this._radius;
|
||||
this._vertexBuffer[4] = this._instance.getX() + this._radius;
|
||||
this._vertexBuffer[5] = this._instance.getY() - this._radius;
|
||||
this._vertexBuffer[6] = this._instance.getX() - this._radius;
|
||||
this._vertexBuffer[7] = this._instance.getY() - this._radius;
|
||||
|
||||
this._pixiObject.geometry
|
||||
.getBuffer('aVertexPosition')
|
||||
.update(this._vertexBuffer);
|
||||
this._pixiObject.position.x = this._instance.getX();
|
||||
this._pixiObject.position.y = this._instance.getY();
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the width of the instance, when it's not resized.
|
||||
*/
|
||||
RenderedLightObjectInstance.prototype.getDefaultWidth = function () {
|
||||
return this._pixiObject.width;
|
||||
return this._radius * 2;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the height of the instance, when it's not resized.
|
||||
*/
|
||||
RenderedLightObjectInstance.prototype.getDefaultHeight = function () {
|
||||
return this._pixiObject.height;
|
||||
return this._radius * 2;
|
||||
};
|
||||
|
||||
RenderedLightObjectInstance.prototype.getOriginX = function () {
|
||||
|
@@ -758,7 +758,7 @@ module.exports = {
|
||||
|
||||
aut
|
||||
.addAction(
|
||||
'SetSleepingaAllowed',
|
||||
'SetSleepingAllowed',
|
||||
_('Sleeping allowed'),
|
||||
_(
|
||||
'Allow or not an object to sleep. If enabled the object will be able to sleep, improving performance for non-currently-moving objects.'
|
||||
@@ -774,6 +774,11 @@ module.exports = {
|
||||
.setDefaultValue('true')
|
||||
.getCodeExtraInformation()
|
||||
.setFunctionName('setSleepingAllowed');
|
||||
|
||||
// Deprecated action (fixed typo):
|
||||
aut
|
||||
.addDuplicatedAction("SetSleepingaAllowed", "SetSleepingAllowed")
|
||||
.setHidden();
|
||||
|
||||
aut
|
||||
.addCondition(
|
||||
|
@@ -140,7 +140,7 @@ namespace gdjs {
|
||||
} else if (behaviorData.platformType === 'Jumpthru') {
|
||||
this._platformType = PlatformRuntimeBehavior.JUMPTHRU;
|
||||
} else {
|
||||
this._platformType = PlatformRuntimeBehavior.NORMALPLAFTORM;
|
||||
this._platformType = PlatformRuntimeBehavior.NORMALPLATFORM;
|
||||
}
|
||||
this._canBeGrabbed = behaviorData.canBeGrabbed || false;
|
||||
this._yGrabOffset = behaviorData.yGrabOffset || 0;
|
||||
@@ -232,7 +232,7 @@ namespace gdjs {
|
||||
} else if (platformType === 'Jumpthru') {
|
||||
this._platformType = PlatformRuntimeBehavior.JUMPTHRU;
|
||||
} else {
|
||||
this._platformType = PlatformRuntimeBehavior.NORMALPLAFTORM;
|
||||
this._platformType = PlatformRuntimeBehavior.NORMALPLATFORM;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -248,7 +248,9 @@ namespace gdjs {
|
||||
return this._yGrabOffset;
|
||||
}
|
||||
|
||||
static NORMALPLAFTORM = 0;
|
||||
static NORMALPLATFORM = 0;
|
||||
/** @deprecated Use NORMALPLATFORM instead. */
|
||||
static NORMALPLAFTORM = PlatformRuntimeBehavior.NORMALPLATFORM;
|
||||
static JUMPTHRU = 1;
|
||||
static LADDER = 2;
|
||||
|
||||
|
@@ -598,8 +598,8 @@ namespace gdjs {
|
||||
break;
|
||||
}
|
||||
case 'connectionId': {
|
||||
const messagegeData = messageContent.data;
|
||||
const connectionId = messagegeData.connectionId;
|
||||
const messageData = messageContent.data;
|
||||
const connectionId = messageData.connectionId;
|
||||
if (!connectionId) {
|
||||
logger.error('No connectionId received');
|
||||
return;
|
||||
|
@@ -239,6 +239,7 @@ namespace gdjs {
|
||||
}
|
||||
|
||||
beginFillPath() {
|
||||
this.updateOutline();
|
||||
this._graphics.beginFill(
|
||||
this._object._fillColor,
|
||||
this._object._fillOpacity / 255
|
||||
|
1252
Extensions/Steamworks/JsExtension.js
Normal file
1252
Extensions/Steamworks/JsExtension.js
Normal file
File diff suppressed because it is too large
Load Diff
63
Extensions/Steamworks/Z_steamworksinputtools.ts
Normal file
63
Extensions/Steamworks/Z_steamworksinputtools.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
namespace gdjs {
|
||||
export namespace steamworks {
|
||||
gdjs.registerFirstRuntimeSceneLoadedCallback(() => {
|
||||
if (gdjs.steamworks.steamAPI) gdjs.steamworks.steamAPI.input.init();
|
||||
});
|
||||
|
||||
export function getControllerCount(): integer {
|
||||
return gdjs.steamworks.steamAPI
|
||||
? gdjs.steamworks.steamAPI.input.getControllers().length
|
||||
: 0;
|
||||
}
|
||||
|
||||
export function activateActionSet(
|
||||
controllerIndex: number,
|
||||
actionSetName: string
|
||||
): void {
|
||||
if (!gdjs.steamworks.steamAPI) return;
|
||||
gdjs.steamworks.steamAPI.input
|
||||
.getControllers()
|
||||
[controllerIndex]?.activateActionSet(
|
||||
gdjs.steamworks.steamAPI.input.getActionSet(actionSetName)
|
||||
);
|
||||
}
|
||||
|
||||
export function isDigitalActionPressed(
|
||||
controllerIndex: number,
|
||||
actionName: string
|
||||
): boolean {
|
||||
if (!gdjs.steamworks.steamAPI) return false;
|
||||
return !!gdjs.steamworks.steamAPI.input
|
||||
.getControllers()
|
||||
[controllerIndex]?.isDigitalActionPressed(
|
||||
gdjs.steamworks.steamAPI.input.getDigitalAction(actionName)
|
||||
);
|
||||
}
|
||||
|
||||
export function getAnalogActionVectorX(
|
||||
controllerIndex: number,
|
||||
actionName: string
|
||||
): float {
|
||||
return gdjs.steamworks.steamAPI
|
||||
? gdjs.steamworks.steamAPI.input
|
||||
.getControllers()
|
||||
[controllerIndex]?.getAnalogActionVector(
|
||||
gdjs.steamworks.steamAPI.input.getAnalogAction(actionName)
|
||||
).x ?? 0
|
||||
: 0;
|
||||
}
|
||||
|
||||
export function getAnalogActionVectorY(
|
||||
controllerIndex: number,
|
||||
actionName: string
|
||||
): float {
|
||||
return gdjs.steamworks.steamAPI
|
||||
? gdjs.steamworks.steamAPI.input
|
||||
.getControllers()
|
||||
[controllerIndex]?.getAnalogActionVector(
|
||||
gdjs.steamworks.steamAPI.input.getAnalogAction(actionName)
|
||||
).y ?? 0
|
||||
: 0;
|
||||
}
|
||||
}
|
||||
}
|
566
Extensions/Steamworks/steamworkstools.ts
Normal file
566
Extensions/Steamworks/steamworkstools.ts
Normal file
@@ -0,0 +1,566 @@
|
||||
namespace gdjs {
|
||||
export namespace steamworks {
|
||||
const logger = new gdjs.Logger('Steamworks');
|
||||
export let steamAPI: import('steamworks.js').Client | null = null;
|
||||
|
||||
gdjs.registerFirstRuntimeSceneLoadedCallback((runtimeScene) => {
|
||||
const remote = runtimeScene.getGame().getRenderer().getElectronRemote();
|
||||
if (!remote) return; // Steamworks is only supported on electron
|
||||
const steamworks_js = remote.require(
|
||||
'steamworks.js'
|
||||
) as typeof import('steamworks.js');
|
||||
|
||||
// Sets the proper electron flags for the steam overlay to function properly
|
||||
steamworks_js.electronEnableSteamOverlay();
|
||||
|
||||
const unparsedAppID = runtimeScene
|
||||
.getGame()
|
||||
.getExtensionProperty('Steamworks', 'AppID');
|
||||
|
||||
if (!unparsedAppID) {
|
||||
logger.error(
|
||||
'A steam AppID needs to be configured in the game properties for steamworks features to be used!'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const appID = parseInt(unparsedAppID, 10);
|
||||
|
||||
// Restart the game through steam if it needs to be launched with steam but has not been
|
||||
if (
|
||||
runtimeScene
|
||||
.getGame()
|
||||
.getExtensionProperty('Steamworks', 'RequireSteam') &&
|
||||
!runtimeScene.getGame().isPreview() &&
|
||||
steamworks_js.restartAppIfNecessary(appID)
|
||||
) {
|
||||
remote.process.exit(1);
|
||||
return;
|
||||
}
|
||||
|
||||
steamAPI = steamworks_js.init(appID);
|
||||
});
|
||||
|
||||
// ---
|
||||
|
||||
export function claimAchievement(achievement: string): void {
|
||||
if (steamAPI) steamAPI.achievement.activate(achievement);
|
||||
else
|
||||
logger.warn(
|
||||
`Could not claim achievement ${achievement}, steamworks was not properly loaded!`
|
||||
);
|
||||
}
|
||||
|
||||
export function unclaimAchievement(achievement: string): void {
|
||||
if (steamAPI) steamAPI.achievement.clear(achievement);
|
||||
else
|
||||
logger.warn(
|
||||
`Could not unclaim achievement ${achievement}, steamworks was not properly loaded!`
|
||||
);
|
||||
}
|
||||
|
||||
export function hasAchievement(achievement: string): boolean {
|
||||
return !!steamAPI && steamAPI.achievement.isActivated(achievement);
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
export function getSteamId(): string {
|
||||
return steamAPI
|
||||
? steamAPI.localplayer.getSteamId().steamId64.toString(10)
|
||||
: '';
|
||||
}
|
||||
|
||||
export function getName(): string {
|
||||
return steamAPI ? steamAPI.localplayer.getName() : 'Unknown';
|
||||
}
|
||||
|
||||
export function getCountry(): string {
|
||||
return steamAPI ? steamAPI.localplayer.getIpCountry() : 'Unknown';
|
||||
}
|
||||
|
||||
export function getLevel(): number {
|
||||
return steamAPI ? steamAPI.localplayer.getLevel() : 0;
|
||||
}
|
||||
|
||||
export function setRichPresence(key: string, value: string): void {
|
||||
if (steamAPI) steamAPI.localplayer.setRichPresence(key, value);
|
||||
else
|
||||
logger.warn(
|
||||
`Could not set the rich presence, steamworks was not properly loaded!`
|
||||
);
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
export function isSteamworksProperlyLoaded(): boolean {
|
||||
return !!steamAPI;
|
||||
}
|
||||
|
||||
export function getAppID(): number {
|
||||
return steamAPI ? steamAPI.utils.getAppId() : 0;
|
||||
}
|
||||
|
||||
export function getServerRealTime(): number {
|
||||
return steamAPI ? steamAPI.utils.getServerRealTime() : Date.now();
|
||||
}
|
||||
|
||||
export function isOnSteamDeck(): boolean {
|
||||
return steamAPI ? steamAPI.utils.isSteamRunningOnSteamDeck() : false;
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
enum LobbyType {
|
||||
Private = 0,
|
||||
FriendsOnly = 1,
|
||||
Public = 2,
|
||||
Invisible = 3,
|
||||
}
|
||||
|
||||
const knownLobbies = new Map<
|
||||
string,
|
||||
import('steamworks.js/client').matchmaking.Lobby
|
||||
>();
|
||||
let currentLobby:
|
||||
| import('steamworks.js/client').matchmaking.Lobby
|
||||
| null = null;
|
||||
|
||||
export function getKnownLobby(lobbyId: string) {
|
||||
if (!steamAPI) {
|
||||
logger.warn(
|
||||
`Could not access lobby '${lobbyId}', steamworks was not properly loaded!`
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
const lobby = knownLobbies.get(lobbyId);
|
||||
if (!lobby) {
|
||||
logger.error(
|
||||
`Could not access lobby '${lobbyId}'! You might need to join it before trying to access it.`
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
return lobby;
|
||||
}
|
||||
|
||||
export function createLobby(
|
||||
lobbyType: 'Private' | 'FriendsOnly' | 'Public' | 'Invisible',
|
||||
maxPlayers: number,
|
||||
result: gdjs.Variable
|
||||
): gdjs.AsyncTask {
|
||||
if (steamAPI) {
|
||||
return new gdjs.PromiseTask(
|
||||
steamAPI.matchmaking
|
||||
.createLobby(
|
||||
LobbyType[lobbyType] as any /* Const enums are 😩 */,
|
||||
maxPlayers
|
||||
)
|
||||
.then((lobby) => {
|
||||
const id = lobby.id.toString(10);
|
||||
knownLobbies.set(id, lobby);
|
||||
currentLobby = lobby;
|
||||
result.setString(id);
|
||||
})
|
||||
.catch(() => {
|
||||
result.setString('failure');
|
||||
})
|
||||
);
|
||||
} else {
|
||||
logger.warn(
|
||||
`Could not create a lobby, steamworks was not properly loaded!`
|
||||
);
|
||||
return new gdjs.ResolveTask();
|
||||
}
|
||||
}
|
||||
|
||||
export function getLobbiesList(results: gdjs.Variable): gdjs.AsyncTask {
|
||||
if (steamAPI) {
|
||||
return new gdjs.PromiseTask(
|
||||
steamAPI.matchmaking
|
||||
.getLobbies()
|
||||
.then((lobbies) => {
|
||||
const allLobbiesIds = lobbies.map((lobby) => {
|
||||
const id = lobby.id.toString(10);
|
||||
knownLobbies.set(id, lobby);
|
||||
return id;
|
||||
});
|
||||
results.fromJSObject(allLobbiesIds);
|
||||
})
|
||||
.catch(() => {
|
||||
results.setString('failure');
|
||||
})
|
||||
);
|
||||
} else {
|
||||
logger.warn(
|
||||
`Could not obtain the lobbies list, steamworks was not properly loaded!`
|
||||
);
|
||||
return new gdjs.ResolveTask();
|
||||
}
|
||||
}
|
||||
|
||||
export function joinLobby(
|
||||
lobbyId: string,
|
||||
result: gdjs.Variable
|
||||
): gdjs.AsyncTask {
|
||||
if (steamAPI) {
|
||||
return new gdjs.PromiseTask(
|
||||
steamAPI.matchmaking
|
||||
.joinLobby(BigInt(lobbyId))
|
||||
.then((lobby) => {
|
||||
knownLobbies.set(lobbyId, lobby);
|
||||
currentLobby = lobby;
|
||||
result.setString(lobbyId);
|
||||
})
|
||||
.catch(() => {
|
||||
result.setString('failure');
|
||||
})
|
||||
);
|
||||
} else {
|
||||
logger.warn(
|
||||
`Could not join a lobby, steamworks was not properly loaded!`
|
||||
);
|
||||
return new gdjs.ResolveTask();
|
||||
}
|
||||
}
|
||||
|
||||
export function getCurrentLobbyId(): string {
|
||||
return currentLobby ? currentLobby.id.toString(10) : 'none';
|
||||
}
|
||||
|
||||
export function leaveCurrentLobby(): void {
|
||||
if (currentLobby) currentLobby.leave();
|
||||
}
|
||||
|
||||
export function openDialogForInvitingUsersToTheCurrentLobby(): void {
|
||||
if (currentLobby) currentLobby.openInviteDialog();
|
||||
}
|
||||
|
||||
export function getCurrentLobbyAttribute(attribute: string): string {
|
||||
if (!currentLobby) return '';
|
||||
|
||||
const data = currentLobby.getData(attribute);
|
||||
return data === null ? '' : data;
|
||||
}
|
||||
|
||||
export function getLobbyAttribute(
|
||||
lobbyId: string,
|
||||
attribute: string
|
||||
): string {
|
||||
const lobby = getKnownLobby(lobbyId);
|
||||
if (!lobby) return '';
|
||||
|
||||
const data = lobby.getData(attribute);
|
||||
return data === null ? '' : data;
|
||||
}
|
||||
|
||||
export function setCurrentLobbyAttribute(
|
||||
attribute: string,
|
||||
value: string,
|
||||
success: gdjs.Variable
|
||||
): void {
|
||||
if (currentLobby)
|
||||
success.setBoolean(currentLobby.setData(attribute, value));
|
||||
}
|
||||
|
||||
export function setCurrentLobbyJoinability(
|
||||
shouldBeJoinable: boolean,
|
||||
success: gdjs.Variable
|
||||
): void {
|
||||
if (currentLobby)
|
||||
success.setBoolean(currentLobby.setJoinable(shouldBeJoinable));
|
||||
}
|
||||
|
||||
export function getCurrentLobbyMemberCount(): number {
|
||||
return currentLobby ? Number(currentLobby.getMemberCount()) : 0;
|
||||
}
|
||||
|
||||
export function getLobbyMemberCount(lobbyId: string): number {
|
||||
const lobby = getKnownLobby(lobbyId);
|
||||
return lobby ? Number(lobby.getMemberCount()) : 0;
|
||||
}
|
||||
|
||||
export function getCurrentLobbyMemberLimit(): number {
|
||||
return currentLobby ? Number(currentLobby.getMemberLimit()) : 0;
|
||||
}
|
||||
|
||||
export function getLobbyMemberLimit(lobbyId: string): number {
|
||||
const lobby = getKnownLobby(lobbyId);
|
||||
if (!lobby) return 0;
|
||||
return lobby ? Number(lobby.getMemberLimit()) : 0;
|
||||
}
|
||||
|
||||
export function getCurrentLobbyOwner(): string {
|
||||
return currentLobby ? currentLobby.getOwner().steamId64.toString(10) : '';
|
||||
}
|
||||
|
||||
export function getLobbyOwner(lobbyId: string): string {
|
||||
const lobby = getKnownLobby(lobbyId);
|
||||
return lobby ? lobby.getOwner().steamId64.toString(10) : '';
|
||||
}
|
||||
|
||||
export function getCurrentLobbyMembersList(storeIn: gdjs.Variable): void {
|
||||
if (currentLobby) {
|
||||
storeIn.fromJSObject(
|
||||
currentLobby
|
||||
.getMembers()
|
||||
.map((steamID) => steamID.steamId64.toString(10))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function getLobbyMembersList(
|
||||
lobbyId: string,
|
||||
storeIn: gdjs.Variable
|
||||
): void {
|
||||
const lobby = getKnownLobby(lobbyId);
|
||||
if (lobby) {
|
||||
storeIn.fromJSObject(
|
||||
lobby.getMembers().map((steamID) => steamID.steamId64.toString(10))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
export function isAppOwned(appId: string): boolean {
|
||||
return !!steamAPI && steamAPI.apps.isSubscribedApp(Number(appId));
|
||||
}
|
||||
|
||||
export function isAppInstalled(appId: string): boolean {
|
||||
return !!steamAPI && steamAPI.apps.isAppInstalled(Number(appId));
|
||||
}
|
||||
|
||||
export function isDLCInstalled(dlcId: string): boolean {
|
||||
return !!steamAPI && steamAPI.apps.isDlcInstalled(Number(dlcId));
|
||||
}
|
||||
|
||||
export function getAppInstallDirectory(appId: string): string {
|
||||
return steamAPI ? steamAPI.apps.appInstallDir(Number(appId)) : '';
|
||||
}
|
||||
|
||||
export function isVacBanned(): boolean {
|
||||
return !!steamAPI && steamAPI.apps.isVacBanned();
|
||||
}
|
||||
|
||||
export function isLowViolence(): boolean {
|
||||
return !!steamAPI && steamAPI.apps.isLowViolence();
|
||||
}
|
||||
|
||||
export function userBoughtTheGame(): boolean {
|
||||
return !!steamAPI && steamAPI.apps.isSubscribed();
|
||||
}
|
||||
|
||||
export function currentGameLanguage(): string {
|
||||
return steamAPI ? steamAPI.apps.currentGameLanguage() : '';
|
||||
}
|
||||
|
||||
export function currentBetaName(): string {
|
||||
return steamAPI ? steamAPI.apps.currentBetaName() || '' : '';
|
||||
}
|
||||
|
||||
export function getBuildId(): number {
|
||||
return steamAPI ? steamAPI.apps.appBuildId() : 0;
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
export function isCloudEnabled(): boolean {
|
||||
return (
|
||||
!!steamAPI &&
|
||||
steamAPI.cloud.isEnabledForAccount() &&
|
||||
steamAPI.cloud.isEnabledForApp()
|
||||
);
|
||||
}
|
||||
|
||||
export function readFile(fileName: string): string {
|
||||
return steamAPI ? steamAPI.cloud.readFile(fileName) : '';
|
||||
}
|
||||
|
||||
export function writeFile(
|
||||
fileName: string,
|
||||
content: string,
|
||||
results: gdjs.Variable
|
||||
): void {
|
||||
if (steamAPI)
|
||||
results.setBoolean(steamAPI.cloud.writeFile(fileName, content));
|
||||
}
|
||||
|
||||
export function fileExists(fileName: string): boolean {
|
||||
return steamAPI ? steamAPI.cloud.fileExists(fileName) : false;
|
||||
}
|
||||
|
||||
export function deleteFile(fileName: string, results: gdjs.Variable): void {
|
||||
if (steamAPI) results.setBoolean(steamAPI.cloud.deleteFile(fileName));
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
export function createWorkshopItem(result: gdjs.Variable): gdjs.AsyncTask {
|
||||
if (steamAPI)
|
||||
return new gdjs.PromiseTask(
|
||||
steamAPI.workshop
|
||||
.createItem()
|
||||
.then(({ itemId }) => {
|
||||
result.setString(itemId.toString());
|
||||
})
|
||||
.catch(() => {
|
||||
result.setString('failure');
|
||||
})
|
||||
);
|
||||
else {
|
||||
result.setString('failure');
|
||||
return new gdjs.ResolveTask();
|
||||
}
|
||||
}
|
||||
|
||||
enum UgcItemVisibility {
|
||||
Public = 0,
|
||||
FriendsOnly = 1,
|
||||
Private = 2,
|
||||
Unlisted = 3,
|
||||
}
|
||||
|
||||
export function updateWorkshopItem(
|
||||
itemId: string,
|
||||
title: string,
|
||||
description: string,
|
||||
changeNote: string,
|
||||
previewPath: string,
|
||||
contentPath: string,
|
||||
tags: string,
|
||||
visibility: keyof import('steamworks.js/client').workshop.UgcItemVisibility,
|
||||
result: gdjs.Variable
|
||||
): gdjs.AsyncTask {
|
||||
if (steamAPI) {
|
||||
const changes: import('steamworks.js/client').workshop.UgcUpdate = {};
|
||||
|
||||
if (title) changes.title = title;
|
||||
if (description) changes.description = description;
|
||||
if (changeNote) changes.changeNote = changeNote;
|
||||
if (previewPath) changes.previewPath = previewPath;
|
||||
if (contentPath) changes.contentPath = contentPath;
|
||||
if (tags) changes.tags = tags.split(',');
|
||||
if (visibility)
|
||||
//@ts-ignore const enum 😩
|
||||
changes.visibility = UgcItemVisibility[visibility];
|
||||
|
||||
return new gdjs.PromiseTask(
|
||||
steamAPI.workshop
|
||||
.updateItem(BigInt(itemId), changes)
|
||||
.then(() => {
|
||||
result.setBoolean(true);
|
||||
})
|
||||
.catch(() => {
|
||||
result.setBoolean(false);
|
||||
})
|
||||
);
|
||||
} else {
|
||||
result.setBoolean(false);
|
||||
return new gdjs.ResolveTask();
|
||||
}
|
||||
}
|
||||
|
||||
export function subscribeToWorkshopItem(
|
||||
itemId: string,
|
||||
result: gdjs.Variable
|
||||
): gdjs.AsyncTask {
|
||||
if (steamAPI)
|
||||
return new gdjs.PromiseTask(
|
||||
steamAPI.workshop
|
||||
.subscribe(BigInt(itemId))
|
||||
.then(() => {
|
||||
result.setBoolean(true);
|
||||
})
|
||||
.catch(() => {
|
||||
result.setBoolean(false);
|
||||
})
|
||||
);
|
||||
else {
|
||||
result.setBoolean(false);
|
||||
return new gdjs.ResolveTask();
|
||||
}
|
||||
}
|
||||
|
||||
export function unsubscribeToWorkshopItem(
|
||||
itemId: string,
|
||||
result: gdjs.Variable
|
||||
): gdjs.AsyncTask {
|
||||
if (steamAPI)
|
||||
return new gdjs.PromiseTask(
|
||||
steamAPI.workshop
|
||||
.unsubscribe(BigInt(itemId))
|
||||
.then(() => {
|
||||
result.setBoolean(true);
|
||||
})
|
||||
.catch(() => {
|
||||
result.setBoolean(false);
|
||||
})
|
||||
);
|
||||
else {
|
||||
result.setBoolean(false);
|
||||
return new gdjs.ResolveTask();
|
||||
}
|
||||
}
|
||||
|
||||
export function startWorkshopDownload(
|
||||
itemId: string,
|
||||
highPriority: boolean
|
||||
): void {
|
||||
if (steamAPI) steamAPI.workshop.download(BigInt(itemId), highPriority);
|
||||
}
|
||||
|
||||
enum WorkshopItemStates {
|
||||
None = 0,
|
||||
Subscribed = 1,
|
||||
LegacyItem = 2,
|
||||
Installed = 4,
|
||||
NeedsUpdate = 8,
|
||||
Downloading = 16,
|
||||
DownloadPending = 32,
|
||||
}
|
||||
|
||||
export function workshopItemState(
|
||||
itemId: string,
|
||||
state: keyof WorkshopItemStates
|
||||
): boolean {
|
||||
return (
|
||||
!!steamAPI &&
|
||||
(steamAPI.workshop.state(BigInt(itemId)) &
|
||||
WorkshopItemStates[state]) !==
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
export function getWorkshopItemLocation(itemId: string): string {
|
||||
return steamAPI
|
||||
? steamAPI.workshop.installInfo(BigInt(itemId))?.folder || ''
|
||||
: '';
|
||||
}
|
||||
|
||||
export function getWorkshopItemSizeOnDisk(itemId: string): number {
|
||||
return steamAPI
|
||||
? Number(steamAPI.workshop.installInfo(BigInt(itemId))?.sizeOnDisk) || 0
|
||||
: 0;
|
||||
}
|
||||
|
||||
export function getWorkshopItemInstallTimestamp(itemId: string): number {
|
||||
return steamAPI
|
||||
? steamAPI.workshop.installInfo(BigInt(itemId))?.timestamp || 0
|
||||
: 0;
|
||||
}
|
||||
|
||||
export function getWorkshopItemDownloadProgress(itemId: string): number {
|
||||
return steamAPI
|
||||
? Number(steamAPI.workshop.downloadInfo(BigInt(itemId))?.current) || 0
|
||||
: 0;
|
||||
}
|
||||
|
||||
export function getWorkshopItemDownloadTotal(itemId: string): number {
|
||||
return steamAPI
|
||||
? Number(steamAPI.workshop.downloadInfo(BigInt(itemId))?.total) || 0
|
||||
: 0;
|
||||
}
|
||||
}
|
||||
}
|
362
Extensions/Steamworks/types.d.ts
vendored
Normal file
362
Extensions/Steamworks/types.d.ts
vendored
Normal file
@@ -0,0 +1,362 @@
|
||||
declare module 'steamworks.js/client' {
|
||||
export function init(appId: number): void;
|
||||
export function restartAppIfNecessary(appId: number): boolean;
|
||||
export function runCallbacks(): void;
|
||||
export interface PlayerSteamId {
|
||||
steamId64: bigint;
|
||||
steamId32: string;
|
||||
accountId: number;
|
||||
}
|
||||
export namespace achievement {
|
||||
export function activate(achievement: string): boolean;
|
||||
export function isActivated(achievement: string): boolean;
|
||||
export function clear(achievement: string): boolean;
|
||||
}
|
||||
export namespace apps {
|
||||
export function isSubscribedApp(appId: number): boolean;
|
||||
export function isAppInstalled(appId: number): boolean;
|
||||
export function isDlcInstalled(appId: number): boolean;
|
||||
export function isSubscribedFromFreeWeekend(): boolean;
|
||||
export function isVacBanned(): boolean;
|
||||
export function isCybercafe(): boolean;
|
||||
export function isLowViolence(): boolean;
|
||||
export function isSubscribed(): boolean;
|
||||
export function appBuildId(): number;
|
||||
export function appInstallDir(appId: number): string;
|
||||
export function appOwner(): PlayerSteamId;
|
||||
export function availableGameLanguages(): Array<string>;
|
||||
export function currentGameLanguage(): string;
|
||||
export function currentBetaName(): string | null;
|
||||
}
|
||||
export namespace auth {
|
||||
/** @param timeoutSeconds - The number of seconds to wait for the ticket to be validated. Default value is 10 seconds. */
|
||||
export function getSessionTicket(
|
||||
timeoutSeconds?: number | undefined | null
|
||||
): Promise<Ticket>;
|
||||
export class Ticket {
|
||||
cancel(): void;
|
||||
getBytes(): Buffer;
|
||||
}
|
||||
}
|
||||
|
||||
export const enum ChatMemberStateChange {
|
||||
/** This user has joined or is joining the lobby. */
|
||||
Entered,
|
||||
/** This user has left or is leaving the lobby. */
|
||||
Left,
|
||||
/** User disconnected without leaving the lobby first. */
|
||||
Disconnected,
|
||||
/** The user has been kicked. */
|
||||
Kicked,
|
||||
/** The user has been kicked and banned. */
|
||||
Banned,
|
||||
}
|
||||
|
||||
export interface CallbackReturns {
|
||||
[callback.SteamCallback.PersonaStateChange]: {
|
||||
steam_id: bigint;
|
||||
flags: { bits: number };
|
||||
};
|
||||
[callback.SteamCallback.SteamServersConnected]: {};
|
||||
[callback.SteamCallback.SteamServersDisconnected]: {
|
||||
reason: number;
|
||||
};
|
||||
[callback.SteamCallback.SteamServerConnectFailure]: {
|
||||
reason: number;
|
||||
still_retrying: boolean;
|
||||
};
|
||||
[callback.SteamCallback.LobbyDataUpdate]: {
|
||||
lobby: bigint;
|
||||
member: bigint;
|
||||
success: boolean;
|
||||
};
|
||||
[callback.SteamCallback.LobbyChatUpdate]: {
|
||||
lobby: bigint;
|
||||
user_changed: bigint;
|
||||
making_change: bigint;
|
||||
member_state_change: ChatMemberStateChange;
|
||||
};
|
||||
[callback.SteamCallback.P2PSessionRequest]: {
|
||||
remote: bigint;
|
||||
};
|
||||
[callback.SteamCallback.P2PSessionConnectFail]: {
|
||||
remote: bigint;
|
||||
error: number;
|
||||
};
|
||||
[callback.SteamCallback.GameLobbyJoinRequested]: {
|
||||
lobby_steam_id: bigint;
|
||||
friend_steam_id: bigint;
|
||||
};
|
||||
[callback.SteamCallback.MicroTxnAuthorizationResponse]: {
|
||||
app_id: number;
|
||||
order_id: number | bigint;
|
||||
authorized: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
export namespace callback {
|
||||
export const enum SteamCallback {
|
||||
PersonaStateChange = 0,
|
||||
SteamServersConnected = 1,
|
||||
SteamServersDisconnected = 2,
|
||||
SteamServerConnectFailure = 3,
|
||||
LobbyDataUpdate = 4,
|
||||
LobbyChatUpdate = 5,
|
||||
P2PSessionRequest = 6,
|
||||
P2PSessionConnectFail = 7,
|
||||
GameLobbyJoinRequested = 8,
|
||||
MicroTxnAuthorizationResponse = 9,
|
||||
}
|
||||
export function register<C extends keyof CallbackReturns>(
|
||||
steamCallback: C,
|
||||
handler: (value: CallbackReturns[C]) => void
|
||||
): Handle;
|
||||
export class Handle {
|
||||
disconnect(): void;
|
||||
}
|
||||
}
|
||||
export namespace cloud {
|
||||
export function isEnabledForAccount(): boolean;
|
||||
export function isEnabledForApp(): boolean;
|
||||
export function readFile(name: string): string;
|
||||
export function writeFile(name: string, content: string): boolean;
|
||||
export function deleteFile(name: string): boolean;
|
||||
export function fileExists(name: string): boolean;
|
||||
}
|
||||
export namespace input {
|
||||
export interface AnalogActionVector {
|
||||
x: number;
|
||||
y: number;
|
||||
}
|
||||
export function init(): void;
|
||||
export function getControllers(): Array<Controller>;
|
||||
export function getActionSet(actionSetName: string): bigint;
|
||||
export function getDigitalAction(actionName: string): bigint;
|
||||
export function getAnalogAction(actionName: string): bigint;
|
||||
export function shutdown(): void;
|
||||
export class Controller {
|
||||
activateActionSet(actionSetHandle: bigint): void;
|
||||
isDigitalActionPressed(actionHandle: bigint): boolean;
|
||||
getAnalogActionVector(actionHandle: bigint): AnalogActionVector;
|
||||
}
|
||||
}
|
||||
export namespace localplayer {
|
||||
export function getSteamId(): PlayerSteamId;
|
||||
export function getName(): string;
|
||||
export function getLevel(): number;
|
||||
/** @returns the 2 digit ISO 3166-1-alpha-2 format country code which client is running in, e.g. "US" or "UK". */
|
||||
export function getIpCountry(): string;
|
||||
export function setRichPresence(
|
||||
key: string,
|
||||
value?: string | undefined | null
|
||||
): void;
|
||||
}
|
||||
export namespace matchmaking {
|
||||
export const enum LobbyType {
|
||||
Private = 0,
|
||||
FriendsOnly = 1,
|
||||
Public = 2,
|
||||
Invisible = 3,
|
||||
}
|
||||
export function createLobby(
|
||||
lobbyType: LobbyType,
|
||||
maxMembers: number
|
||||
): Promise<Lobby>;
|
||||
export function joinLobby(lobbyId: bigint): Promise<Lobby>;
|
||||
export function getLobbies(): Promise<Array<Lobby>>;
|
||||
export class Lobby {
|
||||
id: bigint;
|
||||
join(): Promise<Lobby>;
|
||||
leave(): void;
|
||||
openInviteDialog(): void;
|
||||
getMemberCount(): bigint;
|
||||
getMemberLimit(): bigint | null;
|
||||
getMembers(): Array<PlayerSteamId>;
|
||||
getOwner(): PlayerSteamId;
|
||||
setJoinable(joinable: boolean): boolean;
|
||||
getData(key: string): string | null;
|
||||
setData(key: string, value: string): boolean;
|
||||
deleteData(key: string): boolean;
|
||||
/** Get an object containing all the lobby data */
|
||||
getFullData(): Record<string, string>;
|
||||
/**
|
||||
* Merge current lobby data with provided data in a single batch
|
||||
* @returns true if all data was set successfully
|
||||
*/
|
||||
mergeFullData(data: Record<string, string>): boolean;
|
||||
}
|
||||
}
|
||||
export namespace networking {
|
||||
export interface P2PPacket {
|
||||
data: Buffer;
|
||||
size: number;
|
||||
steamId: PlayerSteamId;
|
||||
}
|
||||
/** The method used to send a packet */
|
||||
export const enum SendType {
|
||||
/**
|
||||
* Send the packet directly over udp.
|
||||
*
|
||||
* Can't be larger than 1200 bytes
|
||||
*/
|
||||
Unreliable = 0,
|
||||
/**
|
||||
* Like `Unreliable` but doesn't buffer packets
|
||||
* sent before the connection has started.
|
||||
*/
|
||||
UnreliableNoDelay = 1,
|
||||
/**
|
||||
* Reliable packet sending.
|
||||
*
|
||||
* Can't be larger than 1 megabyte.
|
||||
*/
|
||||
Reliable = 2,
|
||||
/**
|
||||
* Like `Reliable` but applies the nagle
|
||||
* algorithm to packets being sent
|
||||
*/
|
||||
ReliableWithBuffering = 3,
|
||||
}
|
||||
export function sendP2PPacket(
|
||||
steamId64: bigint,
|
||||
sendType: SendType,
|
||||
data: Buffer
|
||||
): boolean;
|
||||
export function isP2PPacketAvailable(): number;
|
||||
export function readP2PPacket(size: number): P2PPacket;
|
||||
export function acceptP2PSession(steamId64: bigint): void;
|
||||
}
|
||||
export namespace overlay {
|
||||
export const enum Dialog {
|
||||
Friends = 0,
|
||||
Community = 1,
|
||||
Players = 2,
|
||||
Settings = 3,
|
||||
OfficialGameGroup = 4,
|
||||
Stats = 5,
|
||||
Achievements = 6,
|
||||
}
|
||||
export const enum StoreFlag {
|
||||
None = 0,
|
||||
AddToCart = 1,
|
||||
AddToCartAndShow = 2,
|
||||
}
|
||||
export function activateDialog(dialog: Dialog): void;
|
||||
export function activateDialogToUser(
|
||||
dialog: Dialog,
|
||||
steamId64: bigint
|
||||
): void;
|
||||
export function activateInviteDialog(lobbyId: bigint): void;
|
||||
export function activateToWebPage(url: string): void;
|
||||
export function activateToStore(appId: number, flag: StoreFlag): void;
|
||||
}
|
||||
export namespace stats {
|
||||
export function getInt(name: string): number | null;
|
||||
export function setInt(name: string, value: number): boolean;
|
||||
export function store(): boolean;
|
||||
export function resetAll(achievementsToo: boolean): boolean;
|
||||
}
|
||||
export namespace utils {
|
||||
export function getAppId(): number;
|
||||
export function getServerRealTime(): number;
|
||||
export function isSteamRunningOnSteamDeck(): boolean;
|
||||
}
|
||||
export namespace workshop {
|
||||
export interface UgcResult {
|
||||
itemId: bigint;
|
||||
needsToAcceptAgreement: boolean;
|
||||
}
|
||||
export const enum UgcItemVisibility {
|
||||
Public = 0,
|
||||
FriendsOnly = 1,
|
||||
Private = 2,
|
||||
Unlisted = 3,
|
||||
}
|
||||
export interface UgcUpdate {
|
||||
title?: string;
|
||||
description?: string;
|
||||
changeNote?: string;
|
||||
previewPath?: string;
|
||||
contentPath?: string;
|
||||
tags?: Array<string>;
|
||||
visibility?: UgcItemVisibility;
|
||||
}
|
||||
export interface InstallInfo {
|
||||
folder: string;
|
||||
sizeOnDisk: bigint;
|
||||
timestamp: number;
|
||||
}
|
||||
export interface DownloadInfo {
|
||||
current: bigint;
|
||||
total: bigint;
|
||||
}
|
||||
export function createItem(
|
||||
appId?: number | undefined | null
|
||||
): Promise<UgcResult>;
|
||||
export function updateItem(
|
||||
itemId: bigint,
|
||||
updateDetails: UgcUpdate,
|
||||
appId?: number | undefined | null
|
||||
): Promise<UgcResult>;
|
||||
/**
|
||||
* Subscribe to a workshop item. It will be downloaded and installed as soon as possible.
|
||||
*
|
||||
* {@link https://partner.steamgames.com/doc/api/ISteamUGC#SubscribeItem}
|
||||
*/
|
||||
export function subscribe(itemId: bigint): Promise<void>;
|
||||
/**
|
||||
* Unsubscribe from a workshop item. This will result in the item being removed after the game quits.
|
||||
*
|
||||
* {@link https://partner.steamgames.com/doc/api/ISteamUGC#UnsubscribeItem}
|
||||
*/
|
||||
export function unsubscribe(itemId: bigint): Promise<void>;
|
||||
/**
|
||||
* Gets the current state of a workshop item on this client. States can be combined.
|
||||
*
|
||||
* @returns a number with the current item state, e.g. 9
|
||||
* 9 = 1 (The current user is subscribed to this item) + 8 (The item needs an update)
|
||||
*
|
||||
* {@link https://partner.steamgames.com/doc/api/ISteamUGC#GetItemState}
|
||||
* {@link https://partner.steamgames.com/doc/api/ISteamUGC#EItemState}
|
||||
*/
|
||||
export function state(itemId: bigint): number;
|
||||
/**
|
||||
* Gets info about currently installed content on the disc for workshop item.
|
||||
*
|
||||
* @returns an object with the the properties {folder, size_on_disk, timestamp}
|
||||
*
|
||||
* {@link https://partner.steamgames.com/doc/api/ISteamUGC#GetItemInstallInfo}
|
||||
*/
|
||||
export function installInfo(itemId: bigint): InstallInfo | null;
|
||||
/**
|
||||
* Get info about a pending download of a workshop item.
|
||||
*
|
||||
* @returns an object with the properties {current, total}
|
||||
*
|
||||
* {@link https://partner.steamgames.com/doc/api/ISteamUGC#GetItemDownloadInfo}
|
||||
*/
|
||||
export function downloadInfo(itemId: bigint): DownloadInfo | null;
|
||||
/**
|
||||
* Download or update a workshop item.
|
||||
*
|
||||
* @param highPriority - If high priority is true, start the download in high priority mode, pausing any existing in-progress Steam downloads and immediately begin downloading this workshop item.
|
||||
* @returns true or false
|
||||
*
|
||||
* {@link https://partner.steamgames.com/doc/api/ISteamUGC#DownloadItem}
|
||||
*/
|
||||
export function download(itemId: bigint, highPriority: boolean): boolean;
|
||||
}
|
||||
}
|
||||
|
||||
declare module 'steamworks.js' {
|
||||
export function init(appId?: number): Client;
|
||||
export function restartAppIfNecessary(appId: number): boolean;
|
||||
export function electronEnableSteamOverlay(
|
||||
disableEachFrameInvalidation?: boolean
|
||||
): void;
|
||||
export type Client = Omit<
|
||||
typeof import('steamworks.js/client'),
|
||||
'init' | 'runCallbacks'
|
||||
>;
|
||||
export const SteamCallback: typeof import('steamworks.js/client').callback.SteamCallback;
|
||||
}
|
@@ -5,47 +5,7 @@
|
||||
namespace gdjs {
|
||||
export namespace evtTools {
|
||||
export namespace systemInfo {
|
||||
let cachedIsMobile: boolean | null = null;
|
||||
let cachedHasTouchScreen: boolean | null = null;
|
||||
const checkIsMobile = (): boolean => {
|
||||
if (typeof cc !== 'undefined' && cc.sys) {
|
||||
return cc.sys.isMobile;
|
||||
}
|
||||
// @ts-expect-error ts-migrate(2304) FIXME: Cannot find name 'Cocoon'.
|
||||
else if (typeof Cocoon !== 'undefined' && Cocoon.App) {
|
||||
return true;
|
||||
} else if (typeof window !== 'undefined' && (window as any).cordova) {
|
||||
return true;
|
||||
} else if (typeof window !== 'undefined') {
|
||||
// Try to detect mobile device browsers.
|
||||
if (
|
||||
/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|ipad|iris|kindle|Android|Silk|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(
|
||||
navigator.userAgent
|
||||
) ||
|
||||
/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(
|
||||
navigator.userAgent.substr(0, 4)
|
||||
)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Try to detect iOS
|
||||
if (/iPad|iPhone|iPod/.test(navigator.platform)) {
|
||||
return true;
|
||||
} else {
|
||||
if (/MacIntel/.test(navigator.platform)) {
|
||||
// Work around for recent iPads that are "desktop-class browsing".
|
||||
// We can still detect them using their touchscreen, but this is a hack.
|
||||
// If mac laptops start to support touchscreens, this won't work anymore. Hence it's better
|
||||
// to test for the presence of a touchscreen if needed rather than checking if the device
|
||||
// is "mobile".
|
||||
return !!navigator.maxTouchPoints && navigator.maxTouchPoints > 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if the game runs on a mobile device (iPhone, iPad, Android).
|
||||
@@ -54,10 +14,7 @@ namespace gdjs {
|
||||
* prefer to check if the device has touchscreen support.
|
||||
*/
|
||||
export const isMobile = (): boolean => {
|
||||
if (cachedIsMobile !== null) {
|
||||
return cachedIsMobile;
|
||||
}
|
||||
return (cachedIsMobile = checkIsMobile());
|
||||
return gdjs.evtTools.common.isMobile();
|
||||
};
|
||||
|
||||
/**
|
||||
|
@@ -714,8 +714,8 @@ module.exports = {
|
||||
let width = DEFAULT_WIDTH;
|
||||
let height = DEFAULT_HEIGHT;
|
||||
if (instance.hasCustomSize()) {
|
||||
width = instance.getCustomWidth();
|
||||
height = instance.getCustomHeight();
|
||||
width = this.getCustomWidth();
|
||||
height = this.getCustomHeight();
|
||||
}
|
||||
|
||||
this._pixiObject.pivot.x = width / 2;
|
||||
|
@@ -387,7 +387,7 @@ const defineTileMap = function (
|
||||
)
|
||||
.addParameter('object', _('Tile map'), 'TileMap', false)
|
||||
.useStandardParameters('number', gd.ParameterOptions.makeNewOptions())
|
||||
.setFunctionName('getLevelndex');
|
||||
.setFunctionName('getLevelIndex');
|
||||
|
||||
object
|
||||
.addCondition(
|
||||
@@ -1347,9 +1347,9 @@ module.exports = {
|
||||
*/
|
||||
RenderedTileMapInstance.prototype.update = function () {
|
||||
if (this._instance.hasCustomSize()) {
|
||||
this._pixiObject.scale.x = this._instance.getCustomWidth() / this.width;
|
||||
this._pixiObject.scale.x = this.getCustomWidth() / this.width;
|
||||
this._pixiObject.scale.y =
|
||||
this._instance.getCustomHeight() / this.height;
|
||||
this.getCustomHeight() / this.height;
|
||||
} else {
|
||||
this._pixiObject.scale.x = 1;
|
||||
this._pixiObject.scale.y = 1;
|
||||
@@ -1531,7 +1531,7 @@ module.exports = {
|
||||
this._loadTiledMapWithCallback.bind(this),
|
||||
tilemapJsonFile,
|
||||
tilesetJsonFile,
|
||||
0, // leveIndex
|
||||
0, // levelIndex
|
||||
pako,
|
||||
(tileMap) => {
|
||||
if (!tileMap) {
|
||||
@@ -1599,9 +1599,9 @@ module.exports = {
|
||||
*/
|
||||
RenderedCollisionMaskInstance.prototype.update = function () {
|
||||
if (this._instance.hasCustomSize()) {
|
||||
this._pixiObject.scale.x = this._instance.getCustomWidth() / this.width;
|
||||
this._pixiObject.scale.x = this.getCustomWidth() / this.width;
|
||||
this._pixiObject.scale.y =
|
||||
this._instance.getCustomHeight() / this.height;
|
||||
this.getCustomHeight() / this.height;
|
||||
} else {
|
||||
this._pixiObject.scale.x = 1;
|
||||
this._pixiObject.scale.y = 1;
|
||||
|
@@ -362,7 +362,7 @@ namespace gdjs {
|
||||
destroyObjectWhenFinished: boolean
|
||||
) {
|
||||
const { owner } = this;
|
||||
if (!(owner instanceof gdjs.Cube3DRuntimeObject)) return;
|
||||
if (!(owner instanceof gdjs.RuntimeObject3D)) return;
|
||||
|
||||
this._addTween(
|
||||
identifier,
|
||||
|
@@ -664,8 +664,8 @@ module.exports = {
|
||||
);
|
||||
|
||||
if (this._instance.hasCustomSize()) {
|
||||
this._pixiObject.width = this._instance.getCustomWidth();
|
||||
this._pixiObject.height = this._instance.getCustomHeight();
|
||||
this._pixiObject.width = this.getCustomWidth();
|
||||
this._pixiObject.height = this.getCustomHeight();
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -684,15 +684,15 @@ gd::String EventsCodeGenerator::GenerateFreeCondition(
|
||||
bool conditionInverted,
|
||||
gd::EventsCodeGenerationContext& context) {
|
||||
// Generate call
|
||||
gd::String predicat;
|
||||
gd::String predicate;
|
||||
if (instrInfos.codeExtraInformation.type == "number" ||
|
||||
instrInfos.codeExtraInformation.type == "string") {
|
||||
predicat = GenerateRelationalOperatorCall(
|
||||
predicate = GenerateRelationalOperatorCall(
|
||||
instrInfos,
|
||||
arguments,
|
||||
instrInfos.codeExtraInformation.functionCallName);
|
||||
} else {
|
||||
predicat = instrInfos.codeExtraInformation.functionCallName + "(" +
|
||||
predicate = instrInfos.codeExtraInformation.functionCallName + "(" +
|
||||
GenerateArgumentsList(arguments) + ")";
|
||||
}
|
||||
|
||||
@@ -705,11 +705,11 @@ gd::String EventsCodeGenerator::GenerateFreeCondition(
|
||||
conditionAlreadyTakeCareOfInversion = true;
|
||||
}
|
||||
if (!conditionAlreadyTakeCareOfInversion && conditionInverted)
|
||||
predicat = GenerateNegatedPredicat(predicat);
|
||||
predicate = GenerateNegatedPredicate(predicate);
|
||||
|
||||
// Generate condition code
|
||||
return GenerateBooleanFullName(returnBoolean, context) +
|
||||
" = " + predicat + ";\n";
|
||||
" = " + predicate + ";\n";
|
||||
}
|
||||
|
||||
gd::String EventsCodeGenerator::GenerateObjectCondition(
|
||||
@@ -728,22 +728,22 @@ gd::String EventsCodeGenerator::GenerateObjectCondition(
|
||||
instrInfos.codeExtraInformation.functionCallName;
|
||||
|
||||
// Create call
|
||||
gd::String predicat;
|
||||
gd::String predicate;
|
||||
if ((instrInfos.codeExtraInformation.type == "number" ||
|
||||
instrInfos.codeExtraInformation.type == "string")) {
|
||||
predicat = GenerateRelationalOperatorCall(
|
||||
predicate = GenerateRelationalOperatorCall(
|
||||
instrInfos, arguments, objectFunctionCallNamePart, 1);
|
||||
} else {
|
||||
predicat = objectFunctionCallNamePart + "(" +
|
||||
predicate = objectFunctionCallNamePart + "(" +
|
||||
GenerateArgumentsList(arguments, 1) + ")";
|
||||
}
|
||||
if (conditionInverted) predicat = GenerateNegatedPredicat(predicat);
|
||||
if (conditionInverted) predicate = GenerateNegatedPredicate(predicate);
|
||||
|
||||
// Generate whole condition code
|
||||
conditionCode +=
|
||||
"for (var i = 0, k = 0, l = " + GetObjectListName(objectName, context) +
|
||||
".length;i<l;++i) {\n";
|
||||
conditionCode += " if ( " + predicat + " ) {\n";
|
||||
conditionCode += " if ( " + predicate + " ) {\n";
|
||||
conditionCode += " " +
|
||||
GenerateBooleanFullName(returnBoolean, context) +
|
||||
" = true;\n";
|
||||
@@ -775,16 +775,16 @@ gd::String EventsCodeGenerator::GenerateBehaviorCondition(
|
||||
instrInfos.codeExtraInformation.functionCallName;
|
||||
|
||||
// Create call
|
||||
gd::String predicat;
|
||||
gd::String predicate;
|
||||
if ((instrInfos.codeExtraInformation.type == "number" ||
|
||||
instrInfos.codeExtraInformation.type == "string")) {
|
||||
predicat = GenerateRelationalOperatorCall(
|
||||
predicate = GenerateRelationalOperatorCall(
|
||||
instrInfos, arguments, objectFunctionCallNamePart, 2);
|
||||
} else {
|
||||
predicat = objectFunctionCallNamePart + "(" +
|
||||
predicate = objectFunctionCallNamePart + "(" +
|
||||
GenerateArgumentsList(arguments, 2) + ")";
|
||||
}
|
||||
if (conditionInverted) predicat = GenerateNegatedPredicat(predicat);
|
||||
if (conditionInverted) predicate = GenerateNegatedPredicate(predicate);
|
||||
|
||||
// Verify that object has behavior.
|
||||
vector<gd::String> behaviors = gd::GetBehaviorsOfObject(
|
||||
@@ -798,7 +798,7 @@ gd::String EventsCodeGenerator::GenerateBehaviorCondition(
|
||||
conditionCode +=
|
||||
"for (var i = 0, k = 0, l = " + GetObjectListName(objectName, context) +
|
||||
".length;i<l;++i) {\n";
|
||||
conditionCode += " if ( " + predicat + " ) {\n";
|
||||
conditionCode += " if ( " + predicate + " ) {\n";
|
||||
conditionCode += " " +
|
||||
GenerateBooleanFullName(returnBoolean, context) +
|
||||
" = true;\n";
|
||||
|
@@ -319,8 +319,8 @@ class EventsCodeGenerator : public gd::EventsCodeGenerator {
|
||||
const gd::String& type,
|
||||
gd::EventsCodeGenerationContext& context);
|
||||
|
||||
virtual gd::String GenerateNegatedPredicat(const gd::String& predicat) const {
|
||||
return "!(" + predicat + ")";
|
||||
virtual gd::String GenerateNegatedPredicate(const gd::String& predicate) const {
|
||||
return "!(" + predicate + ")";
|
||||
};
|
||||
|
||||
virtual gd::String GenerateObjectsDeclarationCode(
|
||||
|
@@ -133,7 +133,7 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
|
||||
|
||||
gd::String conditionsCode = codeGenerator.GenerateConditionsListCode(
|
||||
event.GetConditions(), context);
|
||||
gd::String ifPredicat =
|
||||
gd::String ifPredicate =
|
||||
event.GetConditions().empty()
|
||||
? ""
|
||||
: codeGenerator.GenerateBooleanFullName(
|
||||
@@ -156,7 +156,7 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
|
||||
|
||||
gd::String outputCode;
|
||||
outputCode += conditionsCode;
|
||||
if (!ifPredicat.empty()) outputCode += "if (" + ifPredicat + ") ";
|
||||
if (!ifPredicate.empty()) outputCode += "if (" + ifPredicate + ") ";
|
||||
outputCode += "{\n";
|
||||
outputCode += actionsDeclarationsCode;
|
||||
outputCode += actionsCode;
|
||||
@@ -391,18 +391,18 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
|
||||
gd::String whileConditionsStr =
|
||||
codeGenerator.GenerateConditionsListCode(event.GetWhileConditions(),
|
||||
context);
|
||||
gd::String whileIfPredicat = "true";
|
||||
gd::String whileIfPredicate = "true";
|
||||
if (!event.GetWhileConditions().empty())
|
||||
whileIfPredicat =
|
||||
whileIfPredicate =
|
||||
codeGenerator.GenerateBooleanFullName("isConditionTrue", context);
|
||||
|
||||
gd::String conditionsCode = codeGenerator.GenerateConditionsListCode(
|
||||
event.GetConditions(), context);
|
||||
gd::String actionsCode =
|
||||
codeGenerator.GenerateActionsListCode(event.GetActions(), context);
|
||||
gd::String ifPredicat = "true";
|
||||
gd::String ifPredicate = "true";
|
||||
if (!event.GetConditions().empty())
|
||||
ifPredicat =
|
||||
ifPredicate =
|
||||
codeGenerator.GenerateBooleanFullName("isConditionTrue", context);
|
||||
|
||||
// Write final code
|
||||
@@ -412,9 +412,9 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
|
||||
outputCode += "do {\n";
|
||||
outputCode += codeGenerator.GenerateObjectsDeclarationCode(context);
|
||||
outputCode += whileConditionsStr;
|
||||
outputCode += "if (" + whileIfPredicat + ") {\n";
|
||||
outputCode += "if (" + whileIfPredicate + ") {\n";
|
||||
outputCode += conditionsCode;
|
||||
outputCode += "if (" + ifPredicat + ") {\n";
|
||||
outputCode += "if (" + ifPredicate + ") {\n";
|
||||
outputCode += actionsCode;
|
||||
outputCode += "\n{ //Subevents: \n";
|
||||
// TODO: check (and heavily test) if sub events should be generated before
|
||||
@@ -448,7 +448,7 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
|
||||
event.GetConditions(), context);
|
||||
gd::String actionsCode =
|
||||
codeGenerator.GenerateActionsListCode(event.GetActions(), context);
|
||||
gd::String ifPredicat = event.GetConditions().empty()
|
||||
gd::String ifPredicate = event.GetConditions().empty()
|
||||
? "true"
|
||||
: codeGenerator.GenerateBooleanFullName(
|
||||
"isConditionTrue", context);
|
||||
@@ -524,7 +524,7 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
|
||||
// Now do the rest of standard event code generation
|
||||
outputCode += objectDeclaration;
|
||||
outputCode += conditionsCode;
|
||||
outputCode += "if (" + ifPredicat + ")\n";
|
||||
outputCode += "if (" + ifPredicate + ")\n";
|
||||
outputCode += "{\n";
|
||||
outputCode += actionsCode;
|
||||
if (event.HasSubEvents()) {
|
||||
@@ -613,9 +613,9 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
|
||||
event.GetConditions(), context);
|
||||
gd::String actionsCode =
|
||||
codeGenerator.GenerateActionsListCode(event.GetActions(), context);
|
||||
gd::String ifPredicat = "true";
|
||||
gd::String ifPredicate = "true";
|
||||
if (!event.GetConditions().empty())
|
||||
ifPredicat =
|
||||
ifPredicate =
|
||||
codeGenerator.GenerateBooleanFullName("isConditionTrue", context);
|
||||
|
||||
// Prepare object declaration and sub events
|
||||
@@ -634,7 +634,7 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
|
||||
" < " + repeatCountVar + ";++" + repeatIndexVar + ") {\n";
|
||||
outputCode += objectDeclaration;
|
||||
outputCode += conditionsCode;
|
||||
outputCode += "if (" + ifPredicat + ")\n";
|
||||
outputCode += "if (" + ifPredicate + ")\n";
|
||||
outputCode += "{\n";
|
||||
outputCode += actionsCode;
|
||||
if (event.HasSubEvents()) {
|
||||
@@ -677,9 +677,9 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
|
||||
event.GetConditions(), context);
|
||||
gd::String actionsCode =
|
||||
codeGenerator.GenerateActionsListCode(event.GetActions(), context);
|
||||
gd::String ifPredicat = "true";
|
||||
gd::String ifPredicate = "true";
|
||||
if (!event.GetConditions().empty())
|
||||
ifPredicat =
|
||||
ifPredicate =
|
||||
codeGenerator.GenerateBooleanFullName("isConditionTrue", context);
|
||||
|
||||
// Prepare object declaration and sub events
|
||||
@@ -787,7 +787,7 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
|
||||
}
|
||||
|
||||
outputCode += conditionsCode;
|
||||
outputCode += "if (" + ifPredicat + ") {\n";
|
||||
outputCode += "if (" + ifPredicate + ") {\n";
|
||||
outputCode += actionsCode;
|
||||
if (event.HasSubEvents()) {
|
||||
outputCode += "\n{ //Subevents: \n";
|
||||
|
@@ -36,6 +36,8 @@ SceneExtension::SceneExtension() {
|
||||
"gdjs.evtTools.runtimeScene.stopGame");
|
||||
GetAllConditions()["HasGameJustResumed"].SetFunctionName(
|
||||
"gdjs.evtTools.runtimeScene.hasGameJustResumed");
|
||||
GetAllConditions()["DoesSceneExist"].SetFunctionName(
|
||||
"gdjs.evtTools.runtimeScene.doesSceneExist");
|
||||
|
||||
StripUnimplementedInstructionsAndExpressions();
|
||||
}
|
||||
|
@@ -686,6 +686,8 @@ void ExporterHelper::AddLibsInclude(bool pixiRenderers,
|
||||
if (pixiInThreeRenderers) {
|
||||
InsertUnique(includesFiles, "pixi-renderers/three.js");
|
||||
InsertUnique(includesFiles, "pixi-renderers/ThreeAddons.js");
|
||||
InsertUnique(includesFiles, "pixi-renderers/draco/gltf/draco_decoder.wasm");
|
||||
InsertUnique(includesFiles, "pixi-renderers/draco/gltf/draco_wasm_wrapper.js");
|
||||
}
|
||||
if (pixiRenderers) {
|
||||
InsertUnique(includesFiles, "pixi-renderers/pixi.js");
|
||||
|
@@ -16,14 +16,16 @@ namespace gdjs {
|
||||
/**
|
||||
* Map associating a resource name to the loaded Three.js model.
|
||||
*/
|
||||
private _loadedThreeModels = new Map<String, THREE.Object3D>();
|
||||
private _loadedThreeModels = new Map<String, THREE_ADDONS.GLTF>();
|
||||
|
||||
_resourcesLoader: RuntimeGameResourcesLoader;
|
||||
_resources: ResourceData[];
|
||||
|
||||
_loader: THREE_ADDONS.GLTFLoader | null = null;
|
||||
_dracoLoader: THREE_ADDONS.DRACOLoader | null = null;
|
||||
|
||||
_invalidModel: THREE.Object3D | null = null;
|
||||
//@ts-ignore Can only be null if THREE is not loaded.
|
||||
_invalidModel: THREE_ADDONS.GLTF;
|
||||
|
||||
/**
|
||||
* @param resources The resources data of the game.
|
||||
@@ -39,8 +41,31 @@ namespace gdjs {
|
||||
if (typeof THREE !== 'undefined') {
|
||||
this._loader = new THREE_ADDONS.GLTFLoader();
|
||||
|
||||
const geometry = new THREE.BoxGeometry(1, 1, 1);
|
||||
this._invalidModel = new THREE.Mesh(geometry);
|
||||
this._dracoLoader = new THREE_ADDONS.DRACOLoader();
|
||||
this._dracoLoader.setDecoderPath('./pixi-renderers/draco/gltf/');
|
||||
this._loader.setDRACOLoader(this._dracoLoader);
|
||||
|
||||
/**
|
||||
* The invalid model is a box with magenta (#ff00ff) faces, to be
|
||||
* easily spotted if rendered on screen.
|
||||
*/
|
||||
const group = new THREE.Group();
|
||||
group.add(
|
||||
new THREE.Mesh(
|
||||
new THREE.BoxGeometry(1, 1, 1),
|
||||
new THREE.MeshBasicMaterial({ color: '#ff00ff' })
|
||||
)
|
||||
);
|
||||
this._invalidModel = {
|
||||
scene: group,
|
||||
animations: [],
|
||||
cameras: [],
|
||||
scenes: [],
|
||||
asset: {},
|
||||
userData: {},
|
||||
//@ts-ignore
|
||||
parser: null,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,12 +102,15 @@ namespace gdjs {
|
||||
let loaded = 0;
|
||||
for (let i = 0; i < model3DResources.length; ++i) {
|
||||
const resource = model3DResources[i];
|
||||
const url = this._resourcesLoader.getFullUrl(resource.file);
|
||||
|
||||
this._loader.withCredentials = this._resourcesLoader.checkIfCredentialsRequired(
|
||||
url
|
||||
);
|
||||
this._loader.load(
|
||||
resource.file,
|
||||
(gltf) => {
|
||||
gltf.scene.rotation.order = 'ZYX';
|
||||
this._loadedThreeModels.set(resource.name, gltf.scene);
|
||||
url,
|
||||
(gltf: THREE_ADDONS.GLTF) => {
|
||||
this._loadedThreeModels.set(resource.name, gltf);
|
||||
|
||||
loaded++;
|
||||
if (loaded === model3DResources.length) {
|
||||
@@ -114,7 +142,7 @@ namespace gdjs {
|
||||
* @param resourceName The name of the json resource.
|
||||
* @returns a 3D model if it exists.
|
||||
*/
|
||||
getModel(resourceName: string): THREE.Object3D | null {
|
||||
getModel(resourceName: string): THREE_ADDONS.GLTF {
|
||||
return this._loadedThreeModels.get(resourceName) || this._invalidModel;
|
||||
}
|
||||
}
|
||||
|
@@ -257,8 +257,19 @@ namespace gdjs {
|
||||
newObject.persistentUuid = instanceData.persistentUuid || null;
|
||||
}
|
||||
newObject.setPosition(instanceData.x + xPos, instanceData.y + yPos);
|
||||
newObject.setZOrder(instanceData.zOrder);
|
||||
newObject.setAngle(instanceData.angle);
|
||||
if (
|
||||
gdjs.RuntimeObject3D &&
|
||||
newObject instanceof gdjs.RuntimeObject3D
|
||||
) {
|
||||
if (instanceData.z !== undefined) newObject.setZ(instanceData.z);
|
||||
if (instanceData.rotationX !== undefined)
|
||||
newObject.setRotationX(instanceData.rotationX);
|
||||
if (instanceData.rotationY !== undefined)
|
||||
newObject.setRotationY(instanceData.rotationY);
|
||||
}
|
||||
|
||||
newObject.setZOrder(instanceData.zOrder);
|
||||
newObject.setLayer(instanceData.layer);
|
||||
newObject
|
||||
.getVariables()
|
||||
|
@@ -1252,6 +1252,29 @@ namespace gdjs {
|
||||
runtimeObject.setLayer(newInstance.layer);
|
||||
somethingChanged = true;
|
||||
}
|
||||
if (
|
||||
gdjs.RuntimeObject3D &&
|
||||
runtimeObject instanceof gdjs.RuntimeObject3D
|
||||
) {
|
||||
if (oldInstance.z !== newInstance.z && newInstance.z !== undefined) {
|
||||
runtimeObject.setZ(newInstance.z);
|
||||
somethingChanged = true;
|
||||
}
|
||||
if (
|
||||
oldInstance.rotationX !== newInstance.rotationX &&
|
||||
newInstance.rotationX !== undefined
|
||||
) {
|
||||
runtimeObject.setRotationX(newInstance.rotationX);
|
||||
somethingChanged = true;
|
||||
}
|
||||
if (
|
||||
oldInstance.rotationY !== newInstance.rotationY &&
|
||||
newInstance.rotationY !== undefined
|
||||
) {
|
||||
runtimeObject.setRotationY(newInstance.rotationY);
|
||||
somethingChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if size changed
|
||||
let sizeChanged = false;
|
||||
@@ -1283,6 +1306,28 @@ namespace gdjs {
|
||||
sizeChanged = true;
|
||||
}
|
||||
}
|
||||
if (
|
||||
gdjs.RuntimeObject3D &&
|
||||
runtimeObject instanceof gdjs.RuntimeObject3D
|
||||
) {
|
||||
// A custom depth was set or changed
|
||||
if (
|
||||
oldInstance.depth !== newInstance.depth &&
|
||||
newInstance.depth !== undefined
|
||||
) {
|
||||
runtimeObject.setDepth(newInstance.depth);
|
||||
somethingChanged = true;
|
||||
sizeChanged = true;
|
||||
} else if (
|
||||
newInstance.depth === undefined &&
|
||||
oldInstance.depth !== undefined
|
||||
) {
|
||||
// The custom depth was removed. Just flag the depth as changed
|
||||
// and hope the object will handle this in
|
||||
// `extraInitializationFromInitialInstance`.
|
||||
sizeChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Update variables
|
||||
this._hotReloadVariablesContainer(
|
||||
|
@@ -396,6 +396,60 @@ namespace gdjs {
|
||||
)
|
||||
eventsFunctionContext.task.resolve();
|
||||
};
|
||||
|
||||
const checkIsMobile = (): boolean => {
|
||||
if (typeof cc !== 'undefined' && cc.sys) {
|
||||
return cc.sys.isMobile;
|
||||
}
|
||||
// @ts-expect-error ts-migrate(2304) FIXME: Cannot find name 'Cocoon'.
|
||||
else if (typeof Cocoon !== 'undefined' && Cocoon.App) {
|
||||
return true;
|
||||
} else if (typeof window !== 'undefined' && (window as any).cordova) {
|
||||
return true;
|
||||
} else if (typeof window !== 'undefined') {
|
||||
// Try to detect mobile device browsers.
|
||||
if (
|
||||
/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|ipad|iris|kindle|Android|Silk|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(
|
||||
navigator.userAgent
|
||||
) ||
|
||||
/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(
|
||||
navigator.userAgent.substr(0, 4)
|
||||
)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Try to detect iOS
|
||||
if (/iPad|iPhone|iPod/.test(navigator.platform)) {
|
||||
return true;
|
||||
} else {
|
||||
if (/MacIntel/.test(navigator.platform)) {
|
||||
// Work around for recent iPads that are "desktop-class browsing".
|
||||
// We can still detect them using their touchscreen, but this is a hack.
|
||||
// If mac laptops start to support touchscreens, this won't work anymore. Hence it's better
|
||||
// to test for the presence of a touchscreen if needed rather than checking if the device
|
||||
// is "mobile".
|
||||
return !!navigator.maxTouchPoints && navigator.maxTouchPoints > 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
let cachedIsMobile: boolean | null = null;
|
||||
/**
|
||||
* Check if the game runs on a mobile device (iPhone, iPad, Android).
|
||||
* Note that the distinction between what is a mobile device and what is not
|
||||
* is becoming blurry. If you use this for mobile controls,
|
||||
* prefer to check if the device has touchscreen support.
|
||||
*/
|
||||
export const isMobile = (): boolean => {
|
||||
if (cachedIsMobile !== null) {
|
||||
return cachedIsMobile;
|
||||
}
|
||||
return (cachedIsMobile = checkIsMobile());
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -309,6 +309,16 @@ namespace gdjs {
|
||||
): boolean => {
|
||||
return instanceContainer.getGame().hasJustResumed();
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if a scene exists.
|
||||
*/
|
||||
export const doesSceneExist = (
|
||||
runtimeScene: gdjs.RuntimeScene,
|
||||
sceneName: string
|
||||
): boolean => {
|
||||
return runtimeScene.getGame().hasScene(sceneName);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -120,7 +120,7 @@ namespace gdjs {
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert a Hex number to a RGB color array([r,g,b] with each component going from 0 to 255).
|
||||
* Convert a Hex number to a RGB color object ({r,g,b,a} with each component going from 0 to 255 and alpha set to 255).
|
||||
* @param hex Hex color
|
||||
*/
|
||||
export const hexNumberToRGB = (
|
||||
@@ -134,6 +134,20 @@ namespace gdjs {
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert a Hex number to a RGB color array([r,g,b] with each component going from 0 to 255).
|
||||
* @param hex Hex color
|
||||
*/
|
||||
export const hexNumberToRGBArray = (
|
||||
hexNumber: number
|
||||
): [integer, integer, integer] => {
|
||||
return [
|
||||
(hexNumber >> 16) & 0xff,
|
||||
(hexNumber >> 8) & 0xff,
|
||||
hexNumber & 0xff,
|
||||
];
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a random integer between 0 and max.
|
||||
* @param max The maximum value (inclusive).
|
||||
|
@@ -223,6 +223,8 @@ namespace gdjs {
|
||||
* Convert a point from the canvas coordinates (for example,
|
||||
* the mouse position) to the container coordinates.
|
||||
*
|
||||
* This method handles 3D rotations.
|
||||
*
|
||||
* @param x The x position, in canvas coordinates.
|
||||
* @param y The y position, in canvas coordinates.
|
||||
* @param cameraId The camera number. Currently ignored.
|
||||
@@ -238,6 +240,11 @@ namespace gdjs {
|
||||
|
||||
// The result parameter used to be optional.
|
||||
let position = result || [0, 0];
|
||||
|
||||
if (this._renderer.isCameraRotatedIn3D()) {
|
||||
return this._renderer.transformTo3DWorld(x, y, 0, cameraId, result);
|
||||
}
|
||||
|
||||
x -= this.getRuntimeScene()._cachedGameResolutionWidth / 2;
|
||||
y -= this.getRuntimeScene()._cachedGameResolutionHeight / 2;
|
||||
x /= Math.abs(this._zoomFactor);
|
||||
@@ -261,6 +268,8 @@ namespace gdjs {
|
||||
*
|
||||
* All transformations (scale, rotation) are supported.
|
||||
*
|
||||
* This method doesn't handle 3D rotations.
|
||||
*
|
||||
* @param x The X position of the point, in parent coordinates.
|
||||
* @param y The Y position of the point, in parent coordinates.
|
||||
* @param result Array that will be updated with the result
|
||||
@@ -295,6 +304,8 @@ namespace gdjs {
|
||||
* Convert a point from the container coordinates (for example,
|
||||
* an object position) to the canvas coordinates.
|
||||
*
|
||||
* This method doesn't handle 3D rotations.
|
||||
*
|
||||
* @param x The x position, in container coordinates.
|
||||
* @param y The y position, in container coordinates.
|
||||
* @param cameraId The camera number. Currently ignored.
|
||||
@@ -333,6 +344,8 @@ namespace gdjs {
|
||||
*
|
||||
* All transformations (scale, rotation) are supported.
|
||||
*
|
||||
* This method doesn't handle 3D rotations.
|
||||
*
|
||||
* @param x The X position of the point, in layer coordinates.
|
||||
* @param y The Y position of the point, in layer coordinates.
|
||||
* @param result Array that will be updated with the result
|
||||
|
File diff suppressed because one or more lines are too long
BIN
GDJS/Runtime/pixi-renderers/draco/gltf/draco_decoder.wasm
Normal file
BIN
GDJS/Runtime/pixi-renderers/draco/gltf/draco_decoder.wasm
Normal file
Binary file not shown.
116
GDJS/Runtime/pixi-renderers/draco/gltf/draco_wasm_wrapper.js
Normal file
116
GDJS/Runtime/pixi-renderers/draco/gltf/draco_wasm_wrapper.js
Normal file
@@ -0,0 +1,116 @@
|
||||
var $jscomp=$jscomp||{};$jscomp.scope={};$jscomp.arrayIteratorImpl=function(h){var n=0;return function(){return n<h.length?{done:!1,value:h[n++]}:{done:!0}}};$jscomp.arrayIterator=function(h){return{next:$jscomp.arrayIteratorImpl(h)}};$jscomp.makeIterator=function(h){var n="undefined"!=typeof Symbol&&Symbol.iterator&&h[Symbol.iterator];return n?n.call(h):$jscomp.arrayIterator(h)};$jscomp.ASSUME_ES5=!1;$jscomp.ASSUME_NO_NATIVE_MAP=!1;$jscomp.ASSUME_NO_NATIVE_SET=!1;$jscomp.SIMPLE_FROUND_POLYFILL=!1;
|
||||
$jscomp.ISOLATE_POLYFILLS=!1;$jscomp.FORCE_POLYFILL_PROMISE=!1;$jscomp.FORCE_POLYFILL_PROMISE_WHEN_NO_UNHANDLED_REJECTION=!1;$jscomp.getGlobal=function(h){h=["object"==typeof globalThis&&globalThis,h,"object"==typeof window&&window,"object"==typeof self&&self,"object"==typeof global&&global];for(var n=0;n<h.length;++n){var k=h[n];if(k&&k.Math==Math)return k}throw Error("Cannot find global object");};$jscomp.global=$jscomp.getGlobal(this);
|
||||
$jscomp.defineProperty=$jscomp.ASSUME_ES5||"function"==typeof Object.defineProperties?Object.defineProperty:function(h,n,k){if(h==Array.prototype||h==Object.prototype)return h;h[n]=k.value;return h};$jscomp.IS_SYMBOL_NATIVE="function"===typeof Symbol&&"symbol"===typeof Symbol("x");$jscomp.TRUST_ES6_POLYFILLS=!$jscomp.ISOLATE_POLYFILLS||$jscomp.IS_SYMBOL_NATIVE;$jscomp.polyfills={};$jscomp.propertyToPolyfillSymbol={};$jscomp.POLYFILL_PREFIX="$jscp$";
|
||||
var $jscomp$lookupPolyfilledValue=function(h,n){var k=$jscomp.propertyToPolyfillSymbol[n];if(null==k)return h[n];k=h[k];return void 0!==k?k:h[n]};$jscomp.polyfill=function(h,n,k,p){n&&($jscomp.ISOLATE_POLYFILLS?$jscomp.polyfillIsolated(h,n,k,p):$jscomp.polyfillUnisolated(h,n,k,p))};
|
||||
$jscomp.polyfillUnisolated=function(h,n,k,p){k=$jscomp.global;h=h.split(".");for(p=0;p<h.length-1;p++){var l=h[p];if(!(l in k))return;k=k[l]}h=h[h.length-1];p=k[h];n=n(p);n!=p&&null!=n&&$jscomp.defineProperty(k,h,{configurable:!0,writable:!0,value:n})};
|
||||
$jscomp.polyfillIsolated=function(h,n,k,p){var l=h.split(".");h=1===l.length;p=l[0];p=!h&&p in $jscomp.polyfills?$jscomp.polyfills:$jscomp.global;for(var y=0;y<l.length-1;y++){var f=l[y];if(!(f in p))return;p=p[f]}l=l[l.length-1];k=$jscomp.IS_SYMBOL_NATIVE&&"es6"===k?p[l]:null;n=n(k);null!=n&&(h?$jscomp.defineProperty($jscomp.polyfills,l,{configurable:!0,writable:!0,value:n}):n!==k&&(void 0===$jscomp.propertyToPolyfillSymbol[l]&&(k=1E9*Math.random()>>>0,$jscomp.propertyToPolyfillSymbol[l]=$jscomp.IS_SYMBOL_NATIVE?
|
||||
$jscomp.global.Symbol(l):$jscomp.POLYFILL_PREFIX+k+"$"+l),$jscomp.defineProperty(p,$jscomp.propertyToPolyfillSymbol[l],{configurable:!0,writable:!0,value:n})))};
|
||||
$jscomp.polyfill("Promise",function(h){function n(){this.batch_=null}function k(f){return f instanceof l?f:new l(function(q,u){q(f)})}if(h&&(!($jscomp.FORCE_POLYFILL_PROMISE||$jscomp.FORCE_POLYFILL_PROMISE_WHEN_NO_UNHANDLED_REJECTION&&"undefined"===typeof $jscomp.global.PromiseRejectionEvent)||!$jscomp.global.Promise||-1===$jscomp.global.Promise.toString().indexOf("[native code]")))return h;n.prototype.asyncExecute=function(f){if(null==this.batch_){this.batch_=[];var q=this;this.asyncExecuteFunction(function(){q.executeBatch_()})}this.batch_.push(f)};
|
||||
var p=$jscomp.global.setTimeout;n.prototype.asyncExecuteFunction=function(f){p(f,0)};n.prototype.executeBatch_=function(){for(;this.batch_&&this.batch_.length;){var f=this.batch_;this.batch_=[];for(var q=0;q<f.length;++q){var u=f[q];f[q]=null;try{u()}catch(A){this.asyncThrow_(A)}}}this.batch_=null};n.prototype.asyncThrow_=function(f){this.asyncExecuteFunction(function(){throw f;})};var l=function(f){this.state_=0;this.result_=void 0;this.onSettledCallbacks_=[];this.isRejectionHandled_=!1;var q=this.createResolveAndReject_();
|
||||
try{f(q.resolve,q.reject)}catch(u){q.reject(u)}};l.prototype.createResolveAndReject_=function(){function f(A){return function(F){u||(u=!0,A.call(q,F))}}var q=this,u=!1;return{resolve:f(this.resolveTo_),reject:f(this.reject_)}};l.prototype.resolveTo_=function(f){if(f===this)this.reject_(new TypeError("A Promise cannot resolve to itself"));else if(f instanceof l)this.settleSameAsPromise_(f);else{a:switch(typeof f){case "object":var q=null!=f;break a;case "function":q=!0;break a;default:q=!1}q?this.resolveToNonPromiseObj_(f):
|
||||
this.fulfill_(f)}};l.prototype.resolveToNonPromiseObj_=function(f){var q=void 0;try{q=f.then}catch(u){this.reject_(u);return}"function"==typeof q?this.settleSameAsThenable_(q,f):this.fulfill_(f)};l.prototype.reject_=function(f){this.settle_(2,f)};l.prototype.fulfill_=function(f){this.settle_(1,f)};l.prototype.settle_=function(f,q){if(0!=this.state_)throw Error("Cannot settle("+f+", "+q+"): Promise already settled in state"+this.state_);this.state_=f;this.result_=q;2===this.state_&&this.scheduleUnhandledRejectionCheck_();
|
||||
this.executeOnSettledCallbacks_()};l.prototype.scheduleUnhandledRejectionCheck_=function(){var f=this;p(function(){if(f.notifyUnhandledRejection_()){var q=$jscomp.global.console;"undefined"!==typeof q&&q.error(f.result_)}},1)};l.prototype.notifyUnhandledRejection_=function(){if(this.isRejectionHandled_)return!1;var f=$jscomp.global.CustomEvent,q=$jscomp.global.Event,u=$jscomp.global.dispatchEvent;if("undefined"===typeof u)return!0;"function"===typeof f?f=new f("unhandledrejection",{cancelable:!0}):
|
||||
"function"===typeof q?f=new q("unhandledrejection",{cancelable:!0}):(f=$jscomp.global.document.createEvent("CustomEvent"),f.initCustomEvent("unhandledrejection",!1,!0,f));f.promise=this;f.reason=this.result_;return u(f)};l.prototype.executeOnSettledCallbacks_=function(){if(null!=this.onSettledCallbacks_){for(var f=0;f<this.onSettledCallbacks_.length;++f)y.asyncExecute(this.onSettledCallbacks_[f]);this.onSettledCallbacks_=null}};var y=new n;l.prototype.settleSameAsPromise_=function(f){var q=this.createResolveAndReject_();
|
||||
f.callWhenSettled_(q.resolve,q.reject)};l.prototype.settleSameAsThenable_=function(f,q){var u=this.createResolveAndReject_();try{f.call(q,u.resolve,u.reject)}catch(A){u.reject(A)}};l.prototype.then=function(f,q){function u(w,B){return"function"==typeof w?function(R){try{A(w(R))}catch(Z){F(Z)}}:B}var A,F,v=new l(function(w,B){A=w;F=B});this.callWhenSettled_(u(f,A),u(q,F));return v};l.prototype.catch=function(f){return this.then(void 0,f)};l.prototype.callWhenSettled_=function(f,q){function u(){switch(A.state_){case 1:f(A.result_);
|
||||
break;case 2:q(A.result_);break;default:throw Error("Unexpected state: "+A.state_);}}var A=this;null==this.onSettledCallbacks_?y.asyncExecute(u):this.onSettledCallbacks_.push(u);this.isRejectionHandled_=!0};l.resolve=k;l.reject=function(f){return new l(function(q,u){u(f)})};l.race=function(f){return new l(function(q,u){for(var A=$jscomp.makeIterator(f),F=A.next();!F.done;F=A.next())k(F.value).callWhenSettled_(q,u)})};l.all=function(f){var q=$jscomp.makeIterator(f),u=q.next();return u.done?k([]):new l(function(A,
|
||||
F){function v(R){return function(Z){w[R]=Z;B--;0==B&&A(w)}}var w=[],B=0;do w.push(void 0),B++,k(u.value).callWhenSettled_(v(w.length-1),F),u=q.next();while(!u.done)})};return l},"es6","es3");$jscomp.owns=function(h,n){return Object.prototype.hasOwnProperty.call(h,n)};$jscomp.assign=$jscomp.TRUST_ES6_POLYFILLS&&"function"==typeof Object.assign?Object.assign:function(h,n){for(var k=1;k<arguments.length;k++){var p=arguments[k];if(p)for(var l in p)$jscomp.owns(p,l)&&(h[l]=p[l])}return h};
|
||||
$jscomp.polyfill("Object.assign",function(h){return h||$jscomp.assign},"es6","es3");$jscomp.checkStringArgs=function(h,n,k){if(null==h)throw new TypeError("The 'this' value for String.prototype."+k+" must not be null or undefined");if(n instanceof RegExp)throw new TypeError("First argument to String.prototype."+k+" must not be a regular expression");return h+""};
|
||||
$jscomp.polyfill("String.prototype.startsWith",function(h){return h?h:function(n,k){var p=$jscomp.checkStringArgs(this,n,"startsWith");n+="";var l=p.length,y=n.length;k=Math.max(0,Math.min(k|0,p.length));for(var f=0;f<y&&k<l;)if(p[k++]!=n[f++])return!1;return f>=y}},"es6","es3");
|
||||
$jscomp.polyfill("Array.prototype.copyWithin",function(h){function n(k){k=Number(k);return Infinity===k||-Infinity===k?k:k|0}return h?h:function(k,p,l){var y=this.length;k=n(k);p=n(p);l=void 0===l?y:n(l);k=0>k?Math.max(y+k,0):Math.min(k,y);p=0>p?Math.max(y+p,0):Math.min(p,y);l=0>l?Math.max(y+l,0):Math.min(l,y);if(k<p)for(;p<l;)p in this?this[k++]=this[p++]:(delete this[k++],p++);else for(l=Math.min(l,y+p-k),k+=l-p;l>p;)--l in this?this[--k]=this[l]:delete this[--k];return this}},"es6","es3");
|
||||
$jscomp.typedArrayCopyWithin=function(h){return h?h:Array.prototype.copyWithin};$jscomp.polyfill("Int8Array.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5");$jscomp.polyfill("Uint8Array.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5");$jscomp.polyfill("Uint8ClampedArray.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5");$jscomp.polyfill("Int16Array.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5");
|
||||
$jscomp.polyfill("Uint16Array.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5");$jscomp.polyfill("Int32Array.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5");$jscomp.polyfill("Uint32Array.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5");$jscomp.polyfill("Float32Array.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5");$jscomp.polyfill("Float64Array.prototype.copyWithin",$jscomp.typedArrayCopyWithin,"es6","es5");
|
||||
var DracoDecoderModule=function(){var h="undefined"!==typeof document&&document.currentScript?document.currentScript.src:void 0;"undefined"!==typeof __filename&&(h=h||__filename);return function(n){function k(e){return a.locateFile?a.locateFile(e,U):U+e}function p(e,b){if(e){var c=ia;var d=e+b;for(b=e;c[b]&&!(b>=d);)++b;if(16<b-e&&c.buffer&&ra)c=ra.decode(c.subarray(e,b));else{for(d="";e<b;){var g=c[e++];if(g&128){var t=c[e++]&63;if(192==(g&224))d+=String.fromCharCode((g&31)<<6|t);else{var aa=c[e++]&
|
||||
63;g=224==(g&240)?(g&15)<<12|t<<6|aa:(g&7)<<18|t<<12|aa<<6|c[e++]&63;65536>g?d+=String.fromCharCode(g):(g-=65536,d+=String.fromCharCode(55296|g>>10,56320|g&1023))}}else d+=String.fromCharCode(g)}c=d}}else c="";return c}function l(){var e=ja.buffer;a.HEAP8=W=new Int8Array(e);a.HEAP16=new Int16Array(e);a.HEAP32=ca=new Int32Array(e);a.HEAPU8=ia=new Uint8Array(e);a.HEAPU16=new Uint16Array(e);a.HEAPU32=Y=new Uint32Array(e);a.HEAPF32=new Float32Array(e);a.HEAPF64=new Float64Array(e)}function y(e){if(a.onAbort)a.onAbort(e);
|
||||
e="Aborted("+e+")";da(e);sa=!0;e=new WebAssembly.RuntimeError(e+". Build with -sASSERTIONS for more info.");ka(e);throw e;}function f(e){try{if(e==P&&ea)return new Uint8Array(ea);if(ma)return ma(e);throw"both async and sync fetching of the wasm failed";}catch(b){y(b)}}function q(){if(!ea&&(ta||fa)){if("function"==typeof fetch&&!P.startsWith("file://"))return fetch(P,{credentials:"same-origin"}).then(function(e){if(!e.ok)throw"failed to load wasm binary file at '"+P+"'";return e.arrayBuffer()}).catch(function(){return f(P)});
|
||||
if(na)return new Promise(function(e,b){na(P,function(c){e(new Uint8Array(c))},b)})}return Promise.resolve().then(function(){return f(P)})}function u(e){for(;0<e.length;)e.shift()(a)}function A(e){this.excPtr=e;this.ptr=e-24;this.set_type=function(b){Y[this.ptr+4>>2]=b};this.get_type=function(){return Y[this.ptr+4>>2]};this.set_destructor=function(b){Y[this.ptr+8>>2]=b};this.get_destructor=function(){return Y[this.ptr+8>>2]};this.set_refcount=function(b){ca[this.ptr>>2]=b};this.set_caught=function(b){W[this.ptr+
|
||||
12>>0]=b?1:0};this.get_caught=function(){return 0!=W[this.ptr+12>>0]};this.set_rethrown=function(b){W[this.ptr+13>>0]=b?1:0};this.get_rethrown=function(){return 0!=W[this.ptr+13>>0]};this.init=function(b,c){this.set_adjusted_ptr(0);this.set_type(b);this.set_destructor(c);this.set_refcount(0);this.set_caught(!1);this.set_rethrown(!1)};this.add_ref=function(){ca[this.ptr>>2]+=1};this.release_ref=function(){var b=ca[this.ptr>>2];ca[this.ptr>>2]=b-1;return 1===b};this.set_adjusted_ptr=function(b){Y[this.ptr+
|
||||
16>>2]=b};this.get_adjusted_ptr=function(){return Y[this.ptr+16>>2]};this.get_exception_ptr=function(){if(ua(this.get_type()))return Y[this.excPtr>>2];var b=this.get_adjusted_ptr();return 0!==b?b:this.excPtr}}function F(){function e(){if(!la&&(la=!0,a.calledRun=!0,!sa)){va=!0;u(oa);wa(a);if(a.onRuntimeInitialized)a.onRuntimeInitialized();if(a.postRun)for("function"==typeof a.postRun&&(a.postRun=[a.postRun]);a.postRun.length;)xa.unshift(a.postRun.shift());u(xa)}}if(!(0<ba)){if(a.preRun)for("function"==
|
||||
typeof a.preRun&&(a.preRun=[a.preRun]);a.preRun.length;)ya.unshift(a.preRun.shift());u(ya);0<ba||(a.setStatus?(a.setStatus("Running..."),setTimeout(function(){setTimeout(function(){a.setStatus("")},1);e()},1)):e())}}function v(){}function w(e){return(e||v).__cache__}function B(e,b){var c=w(b),d=c[e];if(d)return d;d=Object.create((b||v).prototype);d.ptr=e;return c[e]=d}function R(e){if("string"===typeof e){for(var b=0,c=0;c<e.length;++c){var d=e.charCodeAt(c);127>=d?b++:2047>=d?b+=2:55296<=d&&57343>=
|
||||
d?(b+=4,++c):b+=3}b=Array(b+1);c=0;d=b.length;if(0<d){d=c+d-1;for(var g=0;g<e.length;++g){var t=e.charCodeAt(g);if(55296<=t&&57343>=t){var aa=e.charCodeAt(++g);t=65536+((t&1023)<<10)|aa&1023}if(127>=t){if(c>=d)break;b[c++]=t}else{if(2047>=t){if(c+1>=d)break;b[c++]=192|t>>6}else{if(65535>=t){if(c+2>=d)break;b[c++]=224|t>>12}else{if(c+3>=d)break;b[c++]=240|t>>18;b[c++]=128|t>>12&63}b[c++]=128|t>>6&63}b[c++]=128|t&63}}b[c]=0}e=r.alloc(b,W);r.copy(b,W,e);return e}return e}function Z(e){if("object"===
|
||||
typeof e){var b=r.alloc(e,W);r.copy(e,W,b);return b}return e}function X(){throw"cannot construct a VoidPtr, no constructor in IDL";}function S(){this.ptr=za();w(S)[this.ptr]=this}function Q(){this.ptr=Aa();w(Q)[this.ptr]=this}function V(){this.ptr=Ba();w(V)[this.ptr]=this}function x(){this.ptr=Ca();w(x)[this.ptr]=this}function D(){this.ptr=Da();w(D)[this.ptr]=this}function G(){this.ptr=Ea();w(G)[this.ptr]=this}function H(){this.ptr=Fa();w(H)[this.ptr]=this}function E(){this.ptr=Ga();w(E)[this.ptr]=
|
||||
this}function T(){this.ptr=Ha();w(T)[this.ptr]=this}function C(){throw"cannot construct a Status, no constructor in IDL";}function I(){this.ptr=Ia();w(I)[this.ptr]=this}function J(){this.ptr=Ja();w(J)[this.ptr]=this}function K(){this.ptr=Ka();w(K)[this.ptr]=this}function L(){this.ptr=La();w(L)[this.ptr]=this}function M(){this.ptr=Ma();w(M)[this.ptr]=this}function N(){this.ptr=Na();w(N)[this.ptr]=this}function O(){this.ptr=Oa();w(O)[this.ptr]=this}function z(){this.ptr=Pa();w(z)[this.ptr]=this}function m(){this.ptr=
|
||||
Qa();w(m)[this.ptr]=this}n=void 0===n?{}:n;var a="undefined"!=typeof n?n:{},wa,ka;a.ready=new Promise(function(e,b){wa=e;ka=b});var Ra=!1,Sa=!1;a.onRuntimeInitialized=function(){Ra=!0;if(Sa&&"function"===typeof a.onModuleLoaded)a.onModuleLoaded(a)};a.onModuleParsed=function(){Sa=!0;if(Ra&&"function"===typeof a.onModuleLoaded)a.onModuleLoaded(a)};a.isVersionSupported=function(e){if("string"!==typeof e)return!1;e=e.split(".");return 2>e.length||3<e.length?!1:1==e[0]&&0<=e[1]&&5>=e[1]?!0:0!=e[0]||10<
|
||||
e[1]?!1:!0};var Ta=Object.assign({},a),ta="object"==typeof window,fa="function"==typeof importScripts,Ua="object"==typeof process&&"object"==typeof process.versions&&"string"==typeof process.versions.node,U="";if(Ua){var Va=require("fs"),pa=require("path");U=fa?pa.dirname(U)+"/":__dirname+"/";var Wa=function(e,b){e=e.startsWith("file://")?new URL(e):pa.normalize(e);return Va.readFileSync(e,b?void 0:"utf8")};var ma=function(e){e=Wa(e,!0);e.buffer||(e=new Uint8Array(e));return e};var na=function(e,
|
||||
b,c){e=e.startsWith("file://")?new URL(e):pa.normalize(e);Va.readFile(e,function(d,g){d?c(d):b(g.buffer)})};1<process.argv.length&&process.argv[1].replace(/\\/g,"/");process.argv.slice(2);a.inspect=function(){return"[Emscripten Module object]"}}else if(ta||fa)fa?U=self.location.href:"undefined"!=typeof document&&document.currentScript&&(U=document.currentScript.src),h&&(U=h),U=0!==U.indexOf("blob:")?U.substr(0,U.replace(/[?#].*/,"").lastIndexOf("/")+1):"",Wa=function(e){var b=new XMLHttpRequest;b.open("GET",
|
||||
e,!1);b.send(null);return b.responseText},fa&&(ma=function(e){var b=new XMLHttpRequest;b.open("GET",e,!1);b.responseType="arraybuffer";b.send(null);return new Uint8Array(b.response)}),na=function(e,b,c){var d=new XMLHttpRequest;d.open("GET",e,!0);d.responseType="arraybuffer";d.onload=function(){200==d.status||0==d.status&&d.response?b(d.response):c()};d.onerror=c;d.send(null)};a.print||console.log.bind(console);var da=a.printErr||console.warn.bind(console);Object.assign(a,Ta);Ta=null;var ea;a.wasmBinary&&
|
||||
(ea=a.wasmBinary);"object"!=typeof WebAssembly&&y("no native wasm support detected");var ja,sa=!1,ra="undefined"!=typeof TextDecoder?new TextDecoder("utf8"):void 0,W,ia,ca,Y,ya=[],oa=[],xa=[],va=!1,ba=0,qa=null,ha=null;var P="draco_decoder_gltf.wasm";P.startsWith("data:application/octet-stream;base64,")||(P=k(P));var pd=0,qd={b:function(e,b,c){(new A(e)).init(b,c);pd++;throw e;},a:function(){y("")},d:function(e,b,c){ia.copyWithin(e,b,b+c)},c:function(e){var b=ia.length;e>>>=0;if(2147483648<e)return!1;
|
||||
for(var c=1;4>=c;c*=2){var d=b*(1+.2/c);d=Math.min(d,e+100663296);var g=Math;d=Math.max(e,d);g=g.min.call(g,2147483648,d+(65536-d%65536)%65536);a:{d=ja.buffer;try{ja.grow(g-d.byteLength+65535>>>16);l();var t=1;break a}catch(aa){}t=void 0}if(t)return!0}return!1}};(function(){function e(g,t){a.asm=g.exports;ja=a.asm.e;l();oa.unshift(a.asm.f);ba--;a.monitorRunDependencies&&a.monitorRunDependencies(ba);0==ba&&(null!==qa&&(clearInterval(qa),qa=null),ha&&(g=ha,ha=null,g()))}function b(g){e(g.instance)}
|
||||
function c(g){return q().then(function(t){return WebAssembly.instantiate(t,d)}).then(function(t){return t}).then(g,function(t){da("failed to asynchronously prepare wasm: "+t);y(t)})}var d={a:qd};ba++;a.monitorRunDependencies&&a.monitorRunDependencies(ba);if(a.instantiateWasm)try{return a.instantiateWasm(d,e)}catch(g){da("Module.instantiateWasm callback failed with error: "+g),ka(g)}(function(){return ea||"function"!=typeof WebAssembly.instantiateStreaming||P.startsWith("data:application/octet-stream;base64,")||
|
||||
P.startsWith("file://")||Ua||"function"!=typeof fetch?c(b):fetch(P,{credentials:"same-origin"}).then(function(g){return WebAssembly.instantiateStreaming(g,d).then(b,function(t){da("wasm streaming compile failed: "+t);da("falling back to ArrayBuffer instantiation");return c(b)})})})().catch(ka);return{}})();var Xa=a._emscripten_bind_VoidPtr___destroy___0=function(){return(Xa=a._emscripten_bind_VoidPtr___destroy___0=a.asm.h).apply(null,arguments)},za=a._emscripten_bind_DecoderBuffer_DecoderBuffer_0=
|
||||
function(){return(za=a._emscripten_bind_DecoderBuffer_DecoderBuffer_0=a.asm.i).apply(null,arguments)},Ya=a._emscripten_bind_DecoderBuffer_Init_2=function(){return(Ya=a._emscripten_bind_DecoderBuffer_Init_2=a.asm.j).apply(null,arguments)},Za=a._emscripten_bind_DecoderBuffer___destroy___0=function(){return(Za=a._emscripten_bind_DecoderBuffer___destroy___0=a.asm.k).apply(null,arguments)},Aa=a._emscripten_bind_AttributeTransformData_AttributeTransformData_0=function(){return(Aa=a._emscripten_bind_AttributeTransformData_AttributeTransformData_0=
|
||||
a.asm.l).apply(null,arguments)},$a=a._emscripten_bind_AttributeTransformData_transform_type_0=function(){return($a=a._emscripten_bind_AttributeTransformData_transform_type_0=a.asm.m).apply(null,arguments)},ab=a._emscripten_bind_AttributeTransformData___destroy___0=function(){return(ab=a._emscripten_bind_AttributeTransformData___destroy___0=a.asm.n).apply(null,arguments)},Ba=a._emscripten_bind_GeometryAttribute_GeometryAttribute_0=function(){return(Ba=a._emscripten_bind_GeometryAttribute_GeometryAttribute_0=
|
||||
a.asm.o).apply(null,arguments)},bb=a._emscripten_bind_GeometryAttribute___destroy___0=function(){return(bb=a._emscripten_bind_GeometryAttribute___destroy___0=a.asm.p).apply(null,arguments)},Ca=a._emscripten_bind_PointAttribute_PointAttribute_0=function(){return(Ca=a._emscripten_bind_PointAttribute_PointAttribute_0=a.asm.q).apply(null,arguments)},cb=a._emscripten_bind_PointAttribute_size_0=function(){return(cb=a._emscripten_bind_PointAttribute_size_0=a.asm.r).apply(null,arguments)},db=a._emscripten_bind_PointAttribute_GetAttributeTransformData_0=
|
||||
function(){return(db=a._emscripten_bind_PointAttribute_GetAttributeTransformData_0=a.asm.s).apply(null,arguments)},eb=a._emscripten_bind_PointAttribute_attribute_type_0=function(){return(eb=a._emscripten_bind_PointAttribute_attribute_type_0=a.asm.t).apply(null,arguments)},fb=a._emscripten_bind_PointAttribute_data_type_0=function(){return(fb=a._emscripten_bind_PointAttribute_data_type_0=a.asm.u).apply(null,arguments)},gb=a._emscripten_bind_PointAttribute_num_components_0=function(){return(gb=a._emscripten_bind_PointAttribute_num_components_0=
|
||||
a.asm.v).apply(null,arguments)},hb=a._emscripten_bind_PointAttribute_normalized_0=function(){return(hb=a._emscripten_bind_PointAttribute_normalized_0=a.asm.w).apply(null,arguments)},ib=a._emscripten_bind_PointAttribute_byte_stride_0=function(){return(ib=a._emscripten_bind_PointAttribute_byte_stride_0=a.asm.x).apply(null,arguments)},jb=a._emscripten_bind_PointAttribute_byte_offset_0=function(){return(jb=a._emscripten_bind_PointAttribute_byte_offset_0=a.asm.y).apply(null,arguments)},kb=a._emscripten_bind_PointAttribute_unique_id_0=
|
||||
function(){return(kb=a._emscripten_bind_PointAttribute_unique_id_0=a.asm.z).apply(null,arguments)},lb=a._emscripten_bind_PointAttribute___destroy___0=function(){return(lb=a._emscripten_bind_PointAttribute___destroy___0=a.asm.A).apply(null,arguments)},Da=a._emscripten_bind_AttributeQuantizationTransform_AttributeQuantizationTransform_0=function(){return(Da=a._emscripten_bind_AttributeQuantizationTransform_AttributeQuantizationTransform_0=a.asm.B).apply(null,arguments)},mb=a._emscripten_bind_AttributeQuantizationTransform_InitFromAttribute_1=
|
||||
function(){return(mb=a._emscripten_bind_AttributeQuantizationTransform_InitFromAttribute_1=a.asm.C).apply(null,arguments)},nb=a._emscripten_bind_AttributeQuantizationTransform_quantization_bits_0=function(){return(nb=a._emscripten_bind_AttributeQuantizationTransform_quantization_bits_0=a.asm.D).apply(null,arguments)},ob=a._emscripten_bind_AttributeQuantizationTransform_min_value_1=function(){return(ob=a._emscripten_bind_AttributeQuantizationTransform_min_value_1=a.asm.E).apply(null,arguments)},pb=
|
||||
a._emscripten_bind_AttributeQuantizationTransform_range_0=function(){return(pb=a._emscripten_bind_AttributeQuantizationTransform_range_0=a.asm.F).apply(null,arguments)},qb=a._emscripten_bind_AttributeQuantizationTransform___destroy___0=function(){return(qb=a._emscripten_bind_AttributeQuantizationTransform___destroy___0=a.asm.G).apply(null,arguments)},Ea=a._emscripten_bind_AttributeOctahedronTransform_AttributeOctahedronTransform_0=function(){return(Ea=a._emscripten_bind_AttributeOctahedronTransform_AttributeOctahedronTransform_0=
|
||||
a.asm.H).apply(null,arguments)},rb=a._emscripten_bind_AttributeOctahedronTransform_InitFromAttribute_1=function(){return(rb=a._emscripten_bind_AttributeOctahedronTransform_InitFromAttribute_1=a.asm.I).apply(null,arguments)},sb=a._emscripten_bind_AttributeOctahedronTransform_quantization_bits_0=function(){return(sb=a._emscripten_bind_AttributeOctahedronTransform_quantization_bits_0=a.asm.J).apply(null,arguments)},tb=a._emscripten_bind_AttributeOctahedronTransform___destroy___0=function(){return(tb=
|
||||
a._emscripten_bind_AttributeOctahedronTransform___destroy___0=a.asm.K).apply(null,arguments)},Fa=a._emscripten_bind_PointCloud_PointCloud_0=function(){return(Fa=a._emscripten_bind_PointCloud_PointCloud_0=a.asm.L).apply(null,arguments)},ub=a._emscripten_bind_PointCloud_num_attributes_0=function(){return(ub=a._emscripten_bind_PointCloud_num_attributes_0=a.asm.M).apply(null,arguments)},vb=a._emscripten_bind_PointCloud_num_points_0=function(){return(vb=a._emscripten_bind_PointCloud_num_points_0=a.asm.N).apply(null,
|
||||
arguments)},wb=a._emscripten_bind_PointCloud___destroy___0=function(){return(wb=a._emscripten_bind_PointCloud___destroy___0=a.asm.O).apply(null,arguments)},Ga=a._emscripten_bind_Mesh_Mesh_0=function(){return(Ga=a._emscripten_bind_Mesh_Mesh_0=a.asm.P).apply(null,arguments)},xb=a._emscripten_bind_Mesh_num_faces_0=function(){return(xb=a._emscripten_bind_Mesh_num_faces_0=a.asm.Q).apply(null,arguments)},yb=a._emscripten_bind_Mesh_num_attributes_0=function(){return(yb=a._emscripten_bind_Mesh_num_attributes_0=
|
||||
a.asm.R).apply(null,arguments)},zb=a._emscripten_bind_Mesh_num_points_0=function(){return(zb=a._emscripten_bind_Mesh_num_points_0=a.asm.S).apply(null,arguments)},Ab=a._emscripten_bind_Mesh___destroy___0=function(){return(Ab=a._emscripten_bind_Mesh___destroy___0=a.asm.T).apply(null,arguments)},Ha=a._emscripten_bind_Metadata_Metadata_0=function(){return(Ha=a._emscripten_bind_Metadata_Metadata_0=a.asm.U).apply(null,arguments)},Bb=a._emscripten_bind_Metadata___destroy___0=function(){return(Bb=a._emscripten_bind_Metadata___destroy___0=
|
||||
a.asm.V).apply(null,arguments)},Cb=a._emscripten_bind_Status_code_0=function(){return(Cb=a._emscripten_bind_Status_code_0=a.asm.W).apply(null,arguments)},Db=a._emscripten_bind_Status_ok_0=function(){return(Db=a._emscripten_bind_Status_ok_0=a.asm.X).apply(null,arguments)},Eb=a._emscripten_bind_Status_error_msg_0=function(){return(Eb=a._emscripten_bind_Status_error_msg_0=a.asm.Y).apply(null,arguments)},Fb=a._emscripten_bind_Status___destroy___0=function(){return(Fb=a._emscripten_bind_Status___destroy___0=
|
||||
a.asm.Z).apply(null,arguments)},Ia=a._emscripten_bind_DracoFloat32Array_DracoFloat32Array_0=function(){return(Ia=a._emscripten_bind_DracoFloat32Array_DracoFloat32Array_0=a.asm._).apply(null,arguments)},Gb=a._emscripten_bind_DracoFloat32Array_GetValue_1=function(){return(Gb=a._emscripten_bind_DracoFloat32Array_GetValue_1=a.asm.$).apply(null,arguments)},Hb=a._emscripten_bind_DracoFloat32Array_size_0=function(){return(Hb=a._emscripten_bind_DracoFloat32Array_size_0=a.asm.aa).apply(null,arguments)},Ib=
|
||||
a._emscripten_bind_DracoFloat32Array___destroy___0=function(){return(Ib=a._emscripten_bind_DracoFloat32Array___destroy___0=a.asm.ba).apply(null,arguments)},Ja=a._emscripten_bind_DracoInt8Array_DracoInt8Array_0=function(){return(Ja=a._emscripten_bind_DracoInt8Array_DracoInt8Array_0=a.asm.ca).apply(null,arguments)},Jb=a._emscripten_bind_DracoInt8Array_GetValue_1=function(){return(Jb=a._emscripten_bind_DracoInt8Array_GetValue_1=a.asm.da).apply(null,arguments)},Kb=a._emscripten_bind_DracoInt8Array_size_0=
|
||||
function(){return(Kb=a._emscripten_bind_DracoInt8Array_size_0=a.asm.ea).apply(null,arguments)},Lb=a._emscripten_bind_DracoInt8Array___destroy___0=function(){return(Lb=a._emscripten_bind_DracoInt8Array___destroy___0=a.asm.fa).apply(null,arguments)},Ka=a._emscripten_bind_DracoUInt8Array_DracoUInt8Array_0=function(){return(Ka=a._emscripten_bind_DracoUInt8Array_DracoUInt8Array_0=a.asm.ga).apply(null,arguments)},Mb=a._emscripten_bind_DracoUInt8Array_GetValue_1=function(){return(Mb=a._emscripten_bind_DracoUInt8Array_GetValue_1=
|
||||
a.asm.ha).apply(null,arguments)},Nb=a._emscripten_bind_DracoUInt8Array_size_0=function(){return(Nb=a._emscripten_bind_DracoUInt8Array_size_0=a.asm.ia).apply(null,arguments)},Ob=a._emscripten_bind_DracoUInt8Array___destroy___0=function(){return(Ob=a._emscripten_bind_DracoUInt8Array___destroy___0=a.asm.ja).apply(null,arguments)},La=a._emscripten_bind_DracoInt16Array_DracoInt16Array_0=function(){return(La=a._emscripten_bind_DracoInt16Array_DracoInt16Array_0=a.asm.ka).apply(null,arguments)},Pb=a._emscripten_bind_DracoInt16Array_GetValue_1=
|
||||
function(){return(Pb=a._emscripten_bind_DracoInt16Array_GetValue_1=a.asm.la).apply(null,arguments)},Qb=a._emscripten_bind_DracoInt16Array_size_0=function(){return(Qb=a._emscripten_bind_DracoInt16Array_size_0=a.asm.ma).apply(null,arguments)},Rb=a._emscripten_bind_DracoInt16Array___destroy___0=function(){return(Rb=a._emscripten_bind_DracoInt16Array___destroy___0=a.asm.na).apply(null,arguments)},Ma=a._emscripten_bind_DracoUInt16Array_DracoUInt16Array_0=function(){return(Ma=a._emscripten_bind_DracoUInt16Array_DracoUInt16Array_0=
|
||||
a.asm.oa).apply(null,arguments)},Sb=a._emscripten_bind_DracoUInt16Array_GetValue_1=function(){return(Sb=a._emscripten_bind_DracoUInt16Array_GetValue_1=a.asm.pa).apply(null,arguments)},Tb=a._emscripten_bind_DracoUInt16Array_size_0=function(){return(Tb=a._emscripten_bind_DracoUInt16Array_size_0=a.asm.qa).apply(null,arguments)},Ub=a._emscripten_bind_DracoUInt16Array___destroy___0=function(){return(Ub=a._emscripten_bind_DracoUInt16Array___destroy___0=a.asm.ra).apply(null,arguments)},Na=a._emscripten_bind_DracoInt32Array_DracoInt32Array_0=
|
||||
function(){return(Na=a._emscripten_bind_DracoInt32Array_DracoInt32Array_0=a.asm.sa).apply(null,arguments)},Vb=a._emscripten_bind_DracoInt32Array_GetValue_1=function(){return(Vb=a._emscripten_bind_DracoInt32Array_GetValue_1=a.asm.ta).apply(null,arguments)},Wb=a._emscripten_bind_DracoInt32Array_size_0=function(){return(Wb=a._emscripten_bind_DracoInt32Array_size_0=a.asm.ua).apply(null,arguments)},Xb=a._emscripten_bind_DracoInt32Array___destroy___0=function(){return(Xb=a._emscripten_bind_DracoInt32Array___destroy___0=
|
||||
a.asm.va).apply(null,arguments)},Oa=a._emscripten_bind_DracoUInt32Array_DracoUInt32Array_0=function(){return(Oa=a._emscripten_bind_DracoUInt32Array_DracoUInt32Array_0=a.asm.wa).apply(null,arguments)},Yb=a._emscripten_bind_DracoUInt32Array_GetValue_1=function(){return(Yb=a._emscripten_bind_DracoUInt32Array_GetValue_1=a.asm.xa).apply(null,arguments)},Zb=a._emscripten_bind_DracoUInt32Array_size_0=function(){return(Zb=a._emscripten_bind_DracoUInt32Array_size_0=a.asm.ya).apply(null,arguments)},$b=a._emscripten_bind_DracoUInt32Array___destroy___0=
|
||||
function(){return($b=a._emscripten_bind_DracoUInt32Array___destroy___0=a.asm.za).apply(null,arguments)},Pa=a._emscripten_bind_MetadataQuerier_MetadataQuerier_0=function(){return(Pa=a._emscripten_bind_MetadataQuerier_MetadataQuerier_0=a.asm.Aa).apply(null,arguments)},ac=a._emscripten_bind_MetadataQuerier_HasEntry_2=function(){return(ac=a._emscripten_bind_MetadataQuerier_HasEntry_2=a.asm.Ba).apply(null,arguments)},bc=a._emscripten_bind_MetadataQuerier_GetIntEntry_2=function(){return(bc=a._emscripten_bind_MetadataQuerier_GetIntEntry_2=
|
||||
a.asm.Ca).apply(null,arguments)},cc=a._emscripten_bind_MetadataQuerier_GetIntEntryArray_3=function(){return(cc=a._emscripten_bind_MetadataQuerier_GetIntEntryArray_3=a.asm.Da).apply(null,arguments)},dc=a._emscripten_bind_MetadataQuerier_GetDoubleEntry_2=function(){return(dc=a._emscripten_bind_MetadataQuerier_GetDoubleEntry_2=a.asm.Ea).apply(null,arguments)},ec=a._emscripten_bind_MetadataQuerier_GetStringEntry_2=function(){return(ec=a._emscripten_bind_MetadataQuerier_GetStringEntry_2=a.asm.Fa).apply(null,
|
||||
arguments)},fc=a._emscripten_bind_MetadataQuerier_NumEntries_1=function(){return(fc=a._emscripten_bind_MetadataQuerier_NumEntries_1=a.asm.Ga).apply(null,arguments)},gc=a._emscripten_bind_MetadataQuerier_GetEntryName_2=function(){return(gc=a._emscripten_bind_MetadataQuerier_GetEntryName_2=a.asm.Ha).apply(null,arguments)},hc=a._emscripten_bind_MetadataQuerier___destroy___0=function(){return(hc=a._emscripten_bind_MetadataQuerier___destroy___0=a.asm.Ia).apply(null,arguments)},Qa=a._emscripten_bind_Decoder_Decoder_0=
|
||||
function(){return(Qa=a._emscripten_bind_Decoder_Decoder_0=a.asm.Ja).apply(null,arguments)},ic=a._emscripten_bind_Decoder_DecodeArrayToPointCloud_3=function(){return(ic=a._emscripten_bind_Decoder_DecodeArrayToPointCloud_3=a.asm.Ka).apply(null,arguments)},jc=a._emscripten_bind_Decoder_DecodeArrayToMesh_3=function(){return(jc=a._emscripten_bind_Decoder_DecodeArrayToMesh_3=a.asm.La).apply(null,arguments)},kc=a._emscripten_bind_Decoder_GetAttributeId_2=function(){return(kc=a._emscripten_bind_Decoder_GetAttributeId_2=
|
||||
a.asm.Ma).apply(null,arguments)},lc=a._emscripten_bind_Decoder_GetAttributeIdByName_2=function(){return(lc=a._emscripten_bind_Decoder_GetAttributeIdByName_2=a.asm.Na).apply(null,arguments)},mc=a._emscripten_bind_Decoder_GetAttributeIdByMetadataEntry_3=function(){return(mc=a._emscripten_bind_Decoder_GetAttributeIdByMetadataEntry_3=a.asm.Oa).apply(null,arguments)},nc=a._emscripten_bind_Decoder_GetAttribute_2=function(){return(nc=a._emscripten_bind_Decoder_GetAttribute_2=a.asm.Pa).apply(null,arguments)},
|
||||
oc=a._emscripten_bind_Decoder_GetAttributeByUniqueId_2=function(){return(oc=a._emscripten_bind_Decoder_GetAttributeByUniqueId_2=a.asm.Qa).apply(null,arguments)},pc=a._emscripten_bind_Decoder_GetMetadata_1=function(){return(pc=a._emscripten_bind_Decoder_GetMetadata_1=a.asm.Ra).apply(null,arguments)},qc=a._emscripten_bind_Decoder_GetAttributeMetadata_2=function(){return(qc=a._emscripten_bind_Decoder_GetAttributeMetadata_2=a.asm.Sa).apply(null,arguments)},rc=a._emscripten_bind_Decoder_GetFaceFromMesh_3=
|
||||
function(){return(rc=a._emscripten_bind_Decoder_GetFaceFromMesh_3=a.asm.Ta).apply(null,arguments)},sc=a._emscripten_bind_Decoder_GetTriangleStripsFromMesh_2=function(){return(sc=a._emscripten_bind_Decoder_GetTriangleStripsFromMesh_2=a.asm.Ua).apply(null,arguments)},tc=a._emscripten_bind_Decoder_GetTrianglesUInt16Array_3=function(){return(tc=a._emscripten_bind_Decoder_GetTrianglesUInt16Array_3=a.asm.Va).apply(null,arguments)},uc=a._emscripten_bind_Decoder_GetTrianglesUInt32Array_3=function(){return(uc=
|
||||
a._emscripten_bind_Decoder_GetTrianglesUInt32Array_3=a.asm.Wa).apply(null,arguments)},vc=a._emscripten_bind_Decoder_GetAttributeFloat_3=function(){return(vc=a._emscripten_bind_Decoder_GetAttributeFloat_3=a.asm.Xa).apply(null,arguments)},wc=a._emscripten_bind_Decoder_GetAttributeFloatForAllPoints_3=function(){return(wc=a._emscripten_bind_Decoder_GetAttributeFloatForAllPoints_3=a.asm.Ya).apply(null,arguments)},xc=a._emscripten_bind_Decoder_GetAttributeIntForAllPoints_3=function(){return(xc=a._emscripten_bind_Decoder_GetAttributeIntForAllPoints_3=
|
||||
a.asm.Za).apply(null,arguments)},yc=a._emscripten_bind_Decoder_GetAttributeInt8ForAllPoints_3=function(){return(yc=a._emscripten_bind_Decoder_GetAttributeInt8ForAllPoints_3=a.asm._a).apply(null,arguments)},zc=a._emscripten_bind_Decoder_GetAttributeUInt8ForAllPoints_3=function(){return(zc=a._emscripten_bind_Decoder_GetAttributeUInt8ForAllPoints_3=a.asm.$a).apply(null,arguments)},Ac=a._emscripten_bind_Decoder_GetAttributeInt16ForAllPoints_3=function(){return(Ac=a._emscripten_bind_Decoder_GetAttributeInt16ForAllPoints_3=
|
||||
a.asm.ab).apply(null,arguments)},Bc=a._emscripten_bind_Decoder_GetAttributeUInt16ForAllPoints_3=function(){return(Bc=a._emscripten_bind_Decoder_GetAttributeUInt16ForAllPoints_3=a.asm.bb).apply(null,arguments)},Cc=a._emscripten_bind_Decoder_GetAttributeInt32ForAllPoints_3=function(){return(Cc=a._emscripten_bind_Decoder_GetAttributeInt32ForAllPoints_3=a.asm.cb).apply(null,arguments)},Dc=a._emscripten_bind_Decoder_GetAttributeUInt32ForAllPoints_3=function(){return(Dc=a._emscripten_bind_Decoder_GetAttributeUInt32ForAllPoints_3=
|
||||
a.asm.db).apply(null,arguments)},Ec=a._emscripten_bind_Decoder_GetAttributeDataArrayForAllPoints_5=function(){return(Ec=a._emscripten_bind_Decoder_GetAttributeDataArrayForAllPoints_5=a.asm.eb).apply(null,arguments)},Fc=a._emscripten_bind_Decoder_SkipAttributeTransform_1=function(){return(Fc=a._emscripten_bind_Decoder_SkipAttributeTransform_1=a.asm.fb).apply(null,arguments)},Gc=a._emscripten_bind_Decoder_GetEncodedGeometryType_Deprecated_1=function(){return(Gc=a._emscripten_bind_Decoder_GetEncodedGeometryType_Deprecated_1=
|
||||
a.asm.gb).apply(null,arguments)},Hc=a._emscripten_bind_Decoder_DecodeBufferToPointCloud_2=function(){return(Hc=a._emscripten_bind_Decoder_DecodeBufferToPointCloud_2=a.asm.hb).apply(null,arguments)},Ic=a._emscripten_bind_Decoder_DecodeBufferToMesh_2=function(){return(Ic=a._emscripten_bind_Decoder_DecodeBufferToMesh_2=a.asm.ib).apply(null,arguments)},Jc=a._emscripten_bind_Decoder___destroy___0=function(){return(Jc=a._emscripten_bind_Decoder___destroy___0=a.asm.jb).apply(null,arguments)},Kc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_INVALID_TRANSFORM=
|
||||
function(){return(Kc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_INVALID_TRANSFORM=a.asm.kb).apply(null,arguments)},Lc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_NO_TRANSFORM=function(){return(Lc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_NO_TRANSFORM=a.asm.lb).apply(null,arguments)},Mc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_QUANTIZATION_TRANSFORM=function(){return(Mc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_QUANTIZATION_TRANSFORM=
|
||||
a.asm.mb).apply(null,arguments)},Nc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_OCTAHEDRON_TRANSFORM=function(){return(Nc=a._emscripten_enum_draco_AttributeTransformType_ATTRIBUTE_OCTAHEDRON_TRANSFORM=a.asm.nb).apply(null,arguments)},Oc=a._emscripten_enum_draco_GeometryAttribute_Type_INVALID=function(){return(Oc=a._emscripten_enum_draco_GeometryAttribute_Type_INVALID=a.asm.ob).apply(null,arguments)},Pc=a._emscripten_enum_draco_GeometryAttribute_Type_POSITION=function(){return(Pc=a._emscripten_enum_draco_GeometryAttribute_Type_POSITION=
|
||||
a.asm.pb).apply(null,arguments)},Qc=a._emscripten_enum_draco_GeometryAttribute_Type_NORMAL=function(){return(Qc=a._emscripten_enum_draco_GeometryAttribute_Type_NORMAL=a.asm.qb).apply(null,arguments)},Rc=a._emscripten_enum_draco_GeometryAttribute_Type_COLOR=function(){return(Rc=a._emscripten_enum_draco_GeometryAttribute_Type_COLOR=a.asm.rb).apply(null,arguments)},Sc=a._emscripten_enum_draco_GeometryAttribute_Type_TEX_COORD=function(){return(Sc=a._emscripten_enum_draco_GeometryAttribute_Type_TEX_COORD=
|
||||
a.asm.sb).apply(null,arguments)},Tc=a._emscripten_enum_draco_GeometryAttribute_Type_GENERIC=function(){return(Tc=a._emscripten_enum_draco_GeometryAttribute_Type_GENERIC=a.asm.tb).apply(null,arguments)},Uc=a._emscripten_enum_draco_EncodedGeometryType_INVALID_GEOMETRY_TYPE=function(){return(Uc=a._emscripten_enum_draco_EncodedGeometryType_INVALID_GEOMETRY_TYPE=a.asm.ub).apply(null,arguments)},Vc=a._emscripten_enum_draco_EncodedGeometryType_POINT_CLOUD=function(){return(Vc=a._emscripten_enum_draco_EncodedGeometryType_POINT_CLOUD=
|
||||
a.asm.vb).apply(null,arguments)},Wc=a._emscripten_enum_draco_EncodedGeometryType_TRIANGULAR_MESH=function(){return(Wc=a._emscripten_enum_draco_EncodedGeometryType_TRIANGULAR_MESH=a.asm.wb).apply(null,arguments)},Xc=a._emscripten_enum_draco_DataType_DT_INVALID=function(){return(Xc=a._emscripten_enum_draco_DataType_DT_INVALID=a.asm.xb).apply(null,arguments)},Yc=a._emscripten_enum_draco_DataType_DT_INT8=function(){return(Yc=a._emscripten_enum_draco_DataType_DT_INT8=a.asm.yb).apply(null,arguments)},Zc=
|
||||
a._emscripten_enum_draco_DataType_DT_UINT8=function(){return(Zc=a._emscripten_enum_draco_DataType_DT_UINT8=a.asm.zb).apply(null,arguments)},$c=a._emscripten_enum_draco_DataType_DT_INT16=function(){return($c=a._emscripten_enum_draco_DataType_DT_INT16=a.asm.Ab).apply(null,arguments)},ad=a._emscripten_enum_draco_DataType_DT_UINT16=function(){return(ad=a._emscripten_enum_draco_DataType_DT_UINT16=a.asm.Bb).apply(null,arguments)},bd=a._emscripten_enum_draco_DataType_DT_INT32=function(){return(bd=a._emscripten_enum_draco_DataType_DT_INT32=
|
||||
a.asm.Cb).apply(null,arguments)},cd=a._emscripten_enum_draco_DataType_DT_UINT32=function(){return(cd=a._emscripten_enum_draco_DataType_DT_UINT32=a.asm.Db).apply(null,arguments)},dd=a._emscripten_enum_draco_DataType_DT_INT64=function(){return(dd=a._emscripten_enum_draco_DataType_DT_INT64=a.asm.Eb).apply(null,arguments)},ed=a._emscripten_enum_draco_DataType_DT_UINT64=function(){return(ed=a._emscripten_enum_draco_DataType_DT_UINT64=a.asm.Fb).apply(null,arguments)},fd=a._emscripten_enum_draco_DataType_DT_FLOAT32=
|
||||
function(){return(fd=a._emscripten_enum_draco_DataType_DT_FLOAT32=a.asm.Gb).apply(null,arguments)},gd=a._emscripten_enum_draco_DataType_DT_FLOAT64=function(){return(gd=a._emscripten_enum_draco_DataType_DT_FLOAT64=a.asm.Hb).apply(null,arguments)},hd=a._emscripten_enum_draco_DataType_DT_BOOL=function(){return(hd=a._emscripten_enum_draco_DataType_DT_BOOL=a.asm.Ib).apply(null,arguments)},id=a._emscripten_enum_draco_DataType_DT_TYPES_COUNT=function(){return(id=a._emscripten_enum_draco_DataType_DT_TYPES_COUNT=
|
||||
a.asm.Jb).apply(null,arguments)},jd=a._emscripten_enum_draco_StatusCode_OK=function(){return(jd=a._emscripten_enum_draco_StatusCode_OK=a.asm.Kb).apply(null,arguments)},kd=a._emscripten_enum_draco_StatusCode_DRACO_ERROR=function(){return(kd=a._emscripten_enum_draco_StatusCode_DRACO_ERROR=a.asm.Lb).apply(null,arguments)},ld=a._emscripten_enum_draco_StatusCode_IO_ERROR=function(){return(ld=a._emscripten_enum_draco_StatusCode_IO_ERROR=a.asm.Mb).apply(null,arguments)},md=a._emscripten_enum_draco_StatusCode_INVALID_PARAMETER=
|
||||
function(){return(md=a._emscripten_enum_draco_StatusCode_INVALID_PARAMETER=a.asm.Nb).apply(null,arguments)},nd=a._emscripten_enum_draco_StatusCode_UNSUPPORTED_VERSION=function(){return(nd=a._emscripten_enum_draco_StatusCode_UNSUPPORTED_VERSION=a.asm.Ob).apply(null,arguments)},od=a._emscripten_enum_draco_StatusCode_UNKNOWN_VERSION=function(){return(od=a._emscripten_enum_draco_StatusCode_UNKNOWN_VERSION=a.asm.Pb).apply(null,arguments)};a._malloc=function(){return(a._malloc=a.asm.Qb).apply(null,arguments)};
|
||||
a._free=function(){return(a._free=a.asm.Rb).apply(null,arguments)};var ua=function(){return(ua=a.asm.Sb).apply(null,arguments)};a.___start_em_js=11660;a.___stop_em_js=11758;var la;ha=function b(){la||F();la||(ha=b)};if(a.preInit)for("function"==typeof a.preInit&&(a.preInit=[a.preInit]);0<a.preInit.length;)a.preInit.pop()();F();v.prototype=Object.create(v.prototype);v.prototype.constructor=v;v.prototype.__class__=v;v.__cache__={};a.WrapperObject=v;a.getCache=w;a.wrapPointer=B;a.castObject=function(b,
|
||||
c){return B(b.ptr,c)};a.NULL=B(0);a.destroy=function(b){if(!b.__destroy__)throw"Error: Cannot destroy object. (Did you create it yourself?)";b.__destroy__();delete w(b.__class__)[b.ptr]};a.compare=function(b,c){return b.ptr===c.ptr};a.getPointer=function(b){return b.ptr};a.getClass=function(b){return b.__class__};var r={buffer:0,size:0,pos:0,temps:[],needed:0,prepare:function(){if(r.needed){for(var b=0;b<r.temps.length;b++)a._free(r.temps[b]);r.temps.length=0;a._free(r.buffer);r.buffer=0;r.size+=
|
||||
r.needed;r.needed=0}r.buffer||(r.size+=128,r.buffer=a._malloc(r.size),r.buffer||y(void 0));r.pos=0},alloc:function(b,c){r.buffer||y(void 0);b=b.length*c.BYTES_PER_ELEMENT;b=b+7&-8;r.pos+b>=r.size?(0<b||y(void 0),r.needed+=b,c=a._malloc(b),r.temps.push(c)):(c=r.buffer+r.pos,r.pos+=b);return c},copy:function(b,c,d){d>>>=0;switch(c.BYTES_PER_ELEMENT){case 2:d>>>=1;break;case 4:d>>>=2;break;case 8:d>>>=3}for(var g=0;g<b.length;g++)c[d+g]=b[g]}};X.prototype=Object.create(v.prototype);X.prototype.constructor=
|
||||
X;X.prototype.__class__=X;X.__cache__={};a.VoidPtr=X;X.prototype.__destroy__=X.prototype.__destroy__=function(){Xa(this.ptr)};S.prototype=Object.create(v.prototype);S.prototype.constructor=S;S.prototype.__class__=S;S.__cache__={};a.DecoderBuffer=S;S.prototype.Init=S.prototype.Init=function(b,c){var d=this.ptr;r.prepare();"object"==typeof b&&(b=Z(b));c&&"object"===typeof c&&(c=c.ptr);Ya(d,b,c)};S.prototype.__destroy__=S.prototype.__destroy__=function(){Za(this.ptr)};Q.prototype=Object.create(v.prototype);
|
||||
Q.prototype.constructor=Q;Q.prototype.__class__=Q;Q.__cache__={};a.AttributeTransformData=Q;Q.prototype.transform_type=Q.prototype.transform_type=function(){return $a(this.ptr)};Q.prototype.__destroy__=Q.prototype.__destroy__=function(){ab(this.ptr)};V.prototype=Object.create(v.prototype);V.prototype.constructor=V;V.prototype.__class__=V;V.__cache__={};a.GeometryAttribute=V;V.prototype.__destroy__=V.prototype.__destroy__=function(){bb(this.ptr)};x.prototype=Object.create(v.prototype);x.prototype.constructor=
|
||||
x;x.prototype.__class__=x;x.__cache__={};a.PointAttribute=x;x.prototype.size=x.prototype.size=function(){return cb(this.ptr)};x.prototype.GetAttributeTransformData=x.prototype.GetAttributeTransformData=function(){return B(db(this.ptr),Q)};x.prototype.attribute_type=x.prototype.attribute_type=function(){return eb(this.ptr)};x.prototype.data_type=x.prototype.data_type=function(){return fb(this.ptr)};x.prototype.num_components=x.prototype.num_components=function(){return gb(this.ptr)};x.prototype.normalized=
|
||||
x.prototype.normalized=function(){return!!hb(this.ptr)};x.prototype.byte_stride=x.prototype.byte_stride=function(){return ib(this.ptr)};x.prototype.byte_offset=x.prototype.byte_offset=function(){return jb(this.ptr)};x.prototype.unique_id=x.prototype.unique_id=function(){return kb(this.ptr)};x.prototype.__destroy__=x.prototype.__destroy__=function(){lb(this.ptr)};D.prototype=Object.create(v.prototype);D.prototype.constructor=D;D.prototype.__class__=D;D.__cache__={};a.AttributeQuantizationTransform=
|
||||
D;D.prototype.InitFromAttribute=D.prototype.InitFromAttribute=function(b){var c=this.ptr;b&&"object"===typeof b&&(b=b.ptr);return!!mb(c,b)};D.prototype.quantization_bits=D.prototype.quantization_bits=function(){return nb(this.ptr)};D.prototype.min_value=D.prototype.min_value=function(b){var c=this.ptr;b&&"object"===typeof b&&(b=b.ptr);return ob(c,b)};D.prototype.range=D.prototype.range=function(){return pb(this.ptr)};D.prototype.__destroy__=D.prototype.__destroy__=function(){qb(this.ptr)};G.prototype=
|
||||
Object.create(v.prototype);G.prototype.constructor=G;G.prototype.__class__=G;G.__cache__={};a.AttributeOctahedronTransform=G;G.prototype.InitFromAttribute=G.prototype.InitFromAttribute=function(b){var c=this.ptr;b&&"object"===typeof b&&(b=b.ptr);return!!rb(c,b)};G.prototype.quantization_bits=G.prototype.quantization_bits=function(){return sb(this.ptr)};G.prototype.__destroy__=G.prototype.__destroy__=function(){tb(this.ptr)};H.prototype=Object.create(v.prototype);H.prototype.constructor=H;H.prototype.__class__=
|
||||
H;H.__cache__={};a.PointCloud=H;H.prototype.num_attributes=H.prototype.num_attributes=function(){return ub(this.ptr)};H.prototype.num_points=H.prototype.num_points=function(){return vb(this.ptr)};H.prototype.__destroy__=H.prototype.__destroy__=function(){wb(this.ptr)};E.prototype=Object.create(v.prototype);E.prototype.constructor=E;E.prototype.__class__=E;E.__cache__={};a.Mesh=E;E.prototype.num_faces=E.prototype.num_faces=function(){return xb(this.ptr)};E.prototype.num_attributes=E.prototype.num_attributes=
|
||||
function(){return yb(this.ptr)};E.prototype.num_points=E.prototype.num_points=function(){return zb(this.ptr)};E.prototype.__destroy__=E.prototype.__destroy__=function(){Ab(this.ptr)};T.prototype=Object.create(v.prototype);T.prototype.constructor=T;T.prototype.__class__=T;T.__cache__={};a.Metadata=T;T.prototype.__destroy__=T.prototype.__destroy__=function(){Bb(this.ptr)};C.prototype=Object.create(v.prototype);C.prototype.constructor=C;C.prototype.__class__=C;C.__cache__={};a.Status=C;C.prototype.code=
|
||||
C.prototype.code=function(){return Cb(this.ptr)};C.prototype.ok=C.prototype.ok=function(){return!!Db(this.ptr)};C.prototype.error_msg=C.prototype.error_msg=function(){return p(Eb(this.ptr))};C.prototype.__destroy__=C.prototype.__destroy__=function(){Fb(this.ptr)};I.prototype=Object.create(v.prototype);I.prototype.constructor=I;I.prototype.__class__=I;I.__cache__={};a.DracoFloat32Array=I;I.prototype.GetValue=I.prototype.GetValue=function(b){var c=this.ptr;b&&"object"===typeof b&&(b=b.ptr);return Gb(c,
|
||||
b)};I.prototype.size=I.prototype.size=function(){return Hb(this.ptr)};I.prototype.__destroy__=I.prototype.__destroy__=function(){Ib(this.ptr)};J.prototype=Object.create(v.prototype);J.prototype.constructor=J;J.prototype.__class__=J;J.__cache__={};a.DracoInt8Array=J;J.prototype.GetValue=J.prototype.GetValue=function(b){var c=this.ptr;b&&"object"===typeof b&&(b=b.ptr);return Jb(c,b)};J.prototype.size=J.prototype.size=function(){return Kb(this.ptr)};J.prototype.__destroy__=J.prototype.__destroy__=function(){Lb(this.ptr)};
|
||||
K.prototype=Object.create(v.prototype);K.prototype.constructor=K;K.prototype.__class__=K;K.__cache__={};a.DracoUInt8Array=K;K.prototype.GetValue=K.prototype.GetValue=function(b){var c=this.ptr;b&&"object"===typeof b&&(b=b.ptr);return Mb(c,b)};K.prototype.size=K.prototype.size=function(){return Nb(this.ptr)};K.prototype.__destroy__=K.prototype.__destroy__=function(){Ob(this.ptr)};L.prototype=Object.create(v.prototype);L.prototype.constructor=L;L.prototype.__class__=L;L.__cache__={};a.DracoInt16Array=
|
||||
L;L.prototype.GetValue=L.prototype.GetValue=function(b){var c=this.ptr;b&&"object"===typeof b&&(b=b.ptr);return Pb(c,b)};L.prototype.size=L.prototype.size=function(){return Qb(this.ptr)};L.prototype.__destroy__=L.prototype.__destroy__=function(){Rb(this.ptr)};M.prototype=Object.create(v.prototype);M.prototype.constructor=M;M.prototype.__class__=M;M.__cache__={};a.DracoUInt16Array=M;M.prototype.GetValue=M.prototype.GetValue=function(b){var c=this.ptr;b&&"object"===typeof b&&(b=b.ptr);return Sb(c,b)};
|
||||
M.prototype.size=M.prototype.size=function(){return Tb(this.ptr)};M.prototype.__destroy__=M.prototype.__destroy__=function(){Ub(this.ptr)};N.prototype=Object.create(v.prototype);N.prototype.constructor=N;N.prototype.__class__=N;N.__cache__={};a.DracoInt32Array=N;N.prototype.GetValue=N.prototype.GetValue=function(b){var c=this.ptr;b&&"object"===typeof b&&(b=b.ptr);return Vb(c,b)};N.prototype.size=N.prototype.size=function(){return Wb(this.ptr)};N.prototype.__destroy__=N.prototype.__destroy__=function(){Xb(this.ptr)};
|
||||
O.prototype=Object.create(v.prototype);O.prototype.constructor=O;O.prototype.__class__=O;O.__cache__={};a.DracoUInt32Array=O;O.prototype.GetValue=O.prototype.GetValue=function(b){var c=this.ptr;b&&"object"===typeof b&&(b=b.ptr);return Yb(c,b)};O.prototype.size=O.prototype.size=function(){return Zb(this.ptr)};O.prototype.__destroy__=O.prototype.__destroy__=function(){$b(this.ptr)};z.prototype=Object.create(v.prototype);z.prototype.constructor=z;z.prototype.__class__=z;z.__cache__={};a.MetadataQuerier=
|
||||
z;z.prototype.HasEntry=z.prototype.HasEntry=function(b,c){var d=this.ptr;r.prepare();b&&"object"===typeof b&&(b=b.ptr);c=c&&"object"===typeof c?c.ptr:R(c);return!!ac(d,b,c)};z.prototype.GetIntEntry=z.prototype.GetIntEntry=function(b,c){var d=this.ptr;r.prepare();b&&"object"===typeof b&&(b=b.ptr);c=c&&"object"===typeof c?c.ptr:R(c);return bc(d,b,c)};z.prototype.GetIntEntryArray=z.prototype.GetIntEntryArray=function(b,c,d){var g=this.ptr;r.prepare();b&&"object"===typeof b&&(b=b.ptr);c=c&&"object"===
|
||||
typeof c?c.ptr:R(c);d&&"object"===typeof d&&(d=d.ptr);cc(g,b,c,d)};z.prototype.GetDoubleEntry=z.prototype.GetDoubleEntry=function(b,c){var d=this.ptr;r.prepare();b&&"object"===typeof b&&(b=b.ptr);c=c&&"object"===typeof c?c.ptr:R(c);return dc(d,b,c)};z.prototype.GetStringEntry=z.prototype.GetStringEntry=function(b,c){var d=this.ptr;r.prepare();b&&"object"===typeof b&&(b=b.ptr);c=c&&"object"===typeof c?c.ptr:R(c);return p(ec(d,b,c))};z.prototype.NumEntries=z.prototype.NumEntries=function(b){var c=this.ptr;
|
||||
b&&"object"===typeof b&&(b=b.ptr);return fc(c,b)};z.prototype.GetEntryName=z.prototype.GetEntryName=function(b,c){var d=this.ptr;b&&"object"===typeof b&&(b=b.ptr);c&&"object"===typeof c&&(c=c.ptr);return p(gc(d,b,c))};z.prototype.__destroy__=z.prototype.__destroy__=function(){hc(this.ptr)};m.prototype=Object.create(v.prototype);m.prototype.constructor=m;m.prototype.__class__=m;m.__cache__={};a.Decoder=m;m.prototype.DecodeArrayToPointCloud=m.prototype.DecodeArrayToPointCloud=function(b,c,d){var g=
|
||||
this.ptr;r.prepare();"object"==typeof b&&(b=Z(b));c&&"object"===typeof c&&(c=c.ptr);d&&"object"===typeof d&&(d=d.ptr);return B(ic(g,b,c,d),C)};m.prototype.DecodeArrayToMesh=m.prototype.DecodeArrayToMesh=function(b,c,d){var g=this.ptr;r.prepare();"object"==typeof b&&(b=Z(b));c&&"object"===typeof c&&(c=c.ptr);d&&"object"===typeof d&&(d=d.ptr);return B(jc(g,b,c,d),C)};m.prototype.GetAttributeId=m.prototype.GetAttributeId=function(b,c){var d=this.ptr;b&&"object"===typeof b&&(b=b.ptr);c&&"object"===typeof c&&
|
||||
(c=c.ptr);return kc(d,b,c)};m.prototype.GetAttributeIdByName=m.prototype.GetAttributeIdByName=function(b,c){var d=this.ptr;r.prepare();b&&"object"===typeof b&&(b=b.ptr);c=c&&"object"===typeof c?c.ptr:R(c);return lc(d,b,c)};m.prototype.GetAttributeIdByMetadataEntry=m.prototype.GetAttributeIdByMetadataEntry=function(b,c,d){var g=this.ptr;r.prepare();b&&"object"===typeof b&&(b=b.ptr);c=c&&"object"===typeof c?c.ptr:R(c);d=d&&"object"===typeof d?d.ptr:R(d);return mc(g,b,c,d)};m.prototype.GetAttribute=
|
||||
m.prototype.GetAttribute=function(b,c){var d=this.ptr;b&&"object"===typeof b&&(b=b.ptr);c&&"object"===typeof c&&(c=c.ptr);return B(nc(d,b,c),x)};m.prototype.GetAttributeByUniqueId=m.prototype.GetAttributeByUniqueId=function(b,c){var d=this.ptr;b&&"object"===typeof b&&(b=b.ptr);c&&"object"===typeof c&&(c=c.ptr);return B(oc(d,b,c),x)};m.prototype.GetMetadata=m.prototype.GetMetadata=function(b){var c=this.ptr;b&&"object"===typeof b&&(b=b.ptr);return B(pc(c,b),T)};m.prototype.GetAttributeMetadata=m.prototype.GetAttributeMetadata=
|
||||
function(b,c){var d=this.ptr;b&&"object"===typeof b&&(b=b.ptr);c&&"object"===typeof c&&(c=c.ptr);return B(qc(d,b,c),T)};m.prototype.GetFaceFromMesh=m.prototype.GetFaceFromMesh=function(b,c,d){var g=this.ptr;b&&"object"===typeof b&&(b=b.ptr);c&&"object"===typeof c&&(c=c.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!rc(g,b,c,d)};m.prototype.GetTriangleStripsFromMesh=m.prototype.GetTriangleStripsFromMesh=function(b,c){var d=this.ptr;b&&"object"===typeof b&&(b=b.ptr);c&&"object"===typeof c&&(c=c.ptr);
|
||||
return sc(d,b,c)};m.prototype.GetTrianglesUInt16Array=m.prototype.GetTrianglesUInt16Array=function(b,c,d){var g=this.ptr;b&&"object"===typeof b&&(b=b.ptr);c&&"object"===typeof c&&(c=c.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!tc(g,b,c,d)};m.prototype.GetTrianglesUInt32Array=m.prototype.GetTrianglesUInt32Array=function(b,c,d){var g=this.ptr;b&&"object"===typeof b&&(b=b.ptr);c&&"object"===typeof c&&(c=c.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!uc(g,b,c,d)};m.prototype.GetAttributeFloat=m.prototype.GetAttributeFloat=
|
||||
function(b,c,d){var g=this.ptr;b&&"object"===typeof b&&(b=b.ptr);c&&"object"===typeof c&&(c=c.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!vc(g,b,c,d)};m.prototype.GetAttributeFloatForAllPoints=m.prototype.GetAttributeFloatForAllPoints=function(b,c,d){var g=this.ptr;b&&"object"===typeof b&&(b=b.ptr);c&&"object"===typeof c&&(c=c.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!wc(g,b,c,d)};m.prototype.GetAttributeIntForAllPoints=m.prototype.GetAttributeIntForAllPoints=function(b,c,d){var g=this.ptr;
|
||||
b&&"object"===typeof b&&(b=b.ptr);c&&"object"===typeof c&&(c=c.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!xc(g,b,c,d)};m.prototype.GetAttributeInt8ForAllPoints=m.prototype.GetAttributeInt8ForAllPoints=function(b,c,d){var g=this.ptr;b&&"object"===typeof b&&(b=b.ptr);c&&"object"===typeof c&&(c=c.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!yc(g,b,c,d)};m.prototype.GetAttributeUInt8ForAllPoints=m.prototype.GetAttributeUInt8ForAllPoints=function(b,c,d){var g=this.ptr;b&&"object"===typeof b&&(b=
|
||||
b.ptr);c&&"object"===typeof c&&(c=c.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!zc(g,b,c,d)};m.prototype.GetAttributeInt16ForAllPoints=m.prototype.GetAttributeInt16ForAllPoints=function(b,c,d){var g=this.ptr;b&&"object"===typeof b&&(b=b.ptr);c&&"object"===typeof c&&(c=c.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!Ac(g,b,c,d)};m.prototype.GetAttributeUInt16ForAllPoints=m.prototype.GetAttributeUInt16ForAllPoints=function(b,c,d){var g=this.ptr;b&&"object"===typeof b&&(b=b.ptr);c&&"object"===typeof c&&
|
||||
(c=c.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!Bc(g,b,c,d)};m.prototype.GetAttributeInt32ForAllPoints=m.prototype.GetAttributeInt32ForAllPoints=function(b,c,d){var g=this.ptr;b&&"object"===typeof b&&(b=b.ptr);c&&"object"===typeof c&&(c=c.ptr);d&&"object"===typeof d&&(d=d.ptr);return!!Cc(g,b,c,d)};m.prototype.GetAttributeUInt32ForAllPoints=m.prototype.GetAttributeUInt32ForAllPoints=function(b,c,d){var g=this.ptr;b&&"object"===typeof b&&(b=b.ptr);c&&"object"===typeof c&&(c=c.ptr);d&&"object"===
|
||||
typeof d&&(d=d.ptr);return!!Dc(g,b,c,d)};m.prototype.GetAttributeDataArrayForAllPoints=m.prototype.GetAttributeDataArrayForAllPoints=function(b,c,d,g,t){var aa=this.ptr;b&&"object"===typeof b&&(b=b.ptr);c&&"object"===typeof c&&(c=c.ptr);d&&"object"===typeof d&&(d=d.ptr);g&&"object"===typeof g&&(g=g.ptr);t&&"object"===typeof t&&(t=t.ptr);return!!Ec(aa,b,c,d,g,t)};m.prototype.SkipAttributeTransform=m.prototype.SkipAttributeTransform=function(b){var c=this.ptr;b&&"object"===typeof b&&(b=b.ptr);Fc(c,
|
||||
b)};m.prototype.GetEncodedGeometryType_Deprecated=m.prototype.GetEncodedGeometryType_Deprecated=function(b){var c=this.ptr;b&&"object"===typeof b&&(b=b.ptr);return Gc(c,b)};m.prototype.DecodeBufferToPointCloud=m.prototype.DecodeBufferToPointCloud=function(b,c){var d=this.ptr;b&&"object"===typeof b&&(b=b.ptr);c&&"object"===typeof c&&(c=c.ptr);return B(Hc(d,b,c),C)};m.prototype.DecodeBufferToMesh=m.prototype.DecodeBufferToMesh=function(b,c){var d=this.ptr;b&&"object"===typeof b&&(b=b.ptr);c&&"object"===
|
||||
typeof c&&(c=c.ptr);return B(Ic(d,b,c),C)};m.prototype.__destroy__=m.prototype.__destroy__=function(){Jc(this.ptr)};(function(){function b(){a.ATTRIBUTE_INVALID_TRANSFORM=Kc();a.ATTRIBUTE_NO_TRANSFORM=Lc();a.ATTRIBUTE_QUANTIZATION_TRANSFORM=Mc();a.ATTRIBUTE_OCTAHEDRON_TRANSFORM=Nc();a.INVALID=Oc();a.POSITION=Pc();a.NORMAL=Qc();a.COLOR=Rc();a.TEX_COORD=Sc();a.GENERIC=Tc();a.INVALID_GEOMETRY_TYPE=Uc();a.POINT_CLOUD=Vc();a.TRIANGULAR_MESH=Wc();a.DT_INVALID=Xc();a.DT_INT8=Yc();a.DT_UINT8=Zc();a.DT_INT16=
|
||||
$c();a.DT_UINT16=ad();a.DT_INT32=bd();a.DT_UINT32=cd();a.DT_INT64=dd();a.DT_UINT64=ed();a.DT_FLOAT32=fd();a.DT_FLOAT64=gd();a.DT_BOOL=hd();a.DT_TYPES_COUNT=id();a.OK=jd();a.DRACO_ERROR=kd();a.IO_ERROR=ld();a.INVALID_PARAMETER=md();a.UNSUPPORTED_VERSION=nd();a.UNKNOWN_VERSION=od()}va?b():oa.unshift(b)})();if("function"===typeof a.onModuleParsed)a.onModuleParsed();a.Decoder.prototype.GetEncodedGeometryType=function(b){if(b.__class__&&b.__class__===a.DecoderBuffer)return a.Decoder.prototype.GetEncodedGeometryType_Deprecated(b);
|
||||
if(8>b.byteLength)return a.INVALID_GEOMETRY_TYPE;switch(b[7]){case 0:return a.POINT_CLOUD;case 1:return a.TRIANGULAR_MESH;default:return a.INVALID_GEOMETRY_TYPE}};return n.ready}}();"object"===typeof exports&&"object"===typeof module?module.exports=DracoDecoderModule:"function"===typeof define&&define.amd?define([],function(){return DracoDecoderModule}):"object"===typeof exports&&(exports.DracoDecoderModule=DracoDecoderModule);
|
@@ -43,7 +43,7 @@ namespace gdjs {
|
||||
// and then must be displayed on a plane in the 3D world:
|
||||
private _threePlaneTexture: THREE.Texture | null = null;
|
||||
private _threePlaneGeometry: THREE.PlaneGeometry | null = null;
|
||||
private _threePlaneMaterial: THREE.MeshBasicMaterial | null = null;
|
||||
private _threePlaneMaterial: THREE.ShaderMaterial | null = null;
|
||||
private _threePlaneMesh: THREE.Mesh | null = null;
|
||||
|
||||
/**
|
||||
@@ -51,6 +51,8 @@ namespace gdjs {
|
||||
*/
|
||||
private static readonly zeroZOrderForPixi = Math.pow(2, -24);
|
||||
|
||||
private static vectorForProjections: THREE.Vector3 | null = null;
|
||||
|
||||
/**
|
||||
* @param layer The layer
|
||||
* @param runtimeInstanceContainerRenderer The scene renderer
|
||||
@@ -64,7 +66,6 @@ namespace gdjs {
|
||||
this._pixiContainer.sortableChildren = true;
|
||||
this._layer = layer;
|
||||
this._isLightingLayer = layer.isLightingLayer();
|
||||
this._clearColor = layer.getClearColor();
|
||||
runtimeInstanceContainerRenderer
|
||||
.getRendererObject()
|
||||
.addChild(this._pixiContainer);
|
||||
@@ -73,11 +74,19 @@ namespace gdjs {
|
||||
// Setup rendering for lighting or 3D rendering:
|
||||
const pixiRenderer = runtimeGameRenderer.getPIXIRenderer();
|
||||
if (this._isLightingLayer) {
|
||||
this._clearColor = layer.getClearColor();
|
||||
this._setupLightingRendering(
|
||||
pixiRenderer,
|
||||
runtimeInstanceContainerRenderer
|
||||
);
|
||||
} else {
|
||||
// Clear color is used as background color of transparent sprites.
|
||||
this._clearColor = [
|
||||
...gdjs.hexNumberToRGBArray(
|
||||
this._layer.getRuntimeScene().getBackgroundColor()
|
||||
),
|
||||
0,
|
||||
];
|
||||
this._setup3DRendering(pixiRenderer, runtimeInstanceContainerRenderer);
|
||||
}
|
||||
}
|
||||
@@ -186,10 +195,6 @@ namespace gdjs {
|
||||
|
||||
// Create the plane that will show this texture.
|
||||
this._threePlaneGeometry = new THREE.PlaneGeometry(1, 1);
|
||||
this._threePlaneMaterial = new THREE.MeshBasicMaterial({
|
||||
side: THREE.FrontSide,
|
||||
transparent: true,
|
||||
});
|
||||
|
||||
// Create the texture to project on the plane.
|
||||
// Use a buffer to create a "fake" DataTexture, just so the texture
|
||||
@@ -212,13 +217,45 @@ namespace gdjs {
|
||||
this._threePlaneTexture.magFilter = filter;
|
||||
this._threePlaneTexture.wrapS = THREE.ClampToEdgeWrapping;
|
||||
this._threePlaneTexture.wrapT = THREE.ClampToEdgeWrapping;
|
||||
this._threePlaneMaterial.map = this._threePlaneTexture;
|
||||
// This disable the gamma correction done by THREE as PIXI is already doing it.
|
||||
const noGammaCorrectionShader: THREE.ShaderMaterialParameters = {
|
||||
vertexShader: `
|
||||
varying vec2 vUv;
|
||||
void main() {
|
||||
vUv = uv;
|
||||
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
||||
}
|
||||
`,
|
||||
fragmentShader: `
|
||||
uniform sampler2D map;
|
||||
varying vec2 vUv;
|
||||
void main() {
|
||||
vec4 texel = texture2D(map, vUv);
|
||||
gl_FragColor = texel;
|
||||
}
|
||||
`,
|
||||
uniforms: {
|
||||
map: { value: this._threePlaneTexture },
|
||||
},
|
||||
side: THREE.FrontSide,
|
||||
transparent: true,
|
||||
};
|
||||
this._threePlaneMaterial = new THREE.ShaderMaterial(
|
||||
noGammaCorrectionShader
|
||||
);
|
||||
this._threePlaneMaterial;
|
||||
|
||||
// Finally, create the mesh shown in the scene.
|
||||
this._threePlaneMesh = new THREE.Mesh(
|
||||
this._threePlaneGeometry,
|
||||
this._threePlaneMaterial
|
||||
);
|
||||
|
||||
// Force to render the mesh last (after the rest of 3D objects, including
|
||||
// transparent ones). In most cases, the 2D rendering is composed of a lot
|
||||
// of transparent areas, and we can't risk it being displayed first and wrongly
|
||||
// occluding 3D objects shown behind.
|
||||
this._threePlaneMesh.renderOrder = Number.MAX_SAFE_INTEGER;
|
||||
this._threeScene.add(this._threePlaneMesh);
|
||||
}
|
||||
|
||||
@@ -337,6 +374,55 @@ namespace gdjs {
|
||||
}
|
||||
}
|
||||
|
||||
isCameraRotatedIn3D() {
|
||||
return (
|
||||
this._threeCamera &&
|
||||
(this._threeCamera.rotation.x !== 0 ||
|
||||
this._threeCamera.rotation.y !== 0)
|
||||
);
|
||||
}
|
||||
|
||||
transformTo3DWorld(
|
||||
screenX: float,
|
||||
screenY: float,
|
||||
worldZ: float,
|
||||
cameraId: integer,
|
||||
result: FloatPoint
|
||||
): FloatPoint {
|
||||
const camera = this._threeCamera;
|
||||
if (!camera) {
|
||||
result[0] = 0;
|
||||
result[1] = 0;
|
||||
return result;
|
||||
}
|
||||
const width = this._layer.getWidth();
|
||||
const height = this._layer.getHeight();
|
||||
|
||||
let vector = LayerPixiRenderer.vectorForProjections;
|
||||
if (!vector) {
|
||||
vector = new THREE.Vector3();
|
||||
LayerPixiRenderer.vectorForProjections = vector;
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/questions/13055214/mouse-canvas-x-y-to-three-js-world-x-y-z
|
||||
vector.set((screenX / width) * 2 - 1, -(screenY / height) * 2 + 1, 0.5);
|
||||
vector.unproject(camera);
|
||||
vector.sub(camera.position).normalize();
|
||||
const distance = (worldZ - camera.position.z) / vector.z;
|
||||
vector.multiplyScalar(distance);
|
||||
|
||||
// The plane z == worldZ may not be visible on the camera.
|
||||
if (!Number.isFinite(vector.x) || !Number.isFinite(vector.y)) {
|
||||
result[0] = 0;
|
||||
result[1] = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
result[0] = camera.position.x + vector.x;
|
||||
result[1] = -(camera.position.y + vector.y);
|
||||
return result;
|
||||
}
|
||||
|
||||
updateVisibility(visible: boolean): void {
|
||||
this._pixiContainer.visible = !!visible;
|
||||
if (this._threeGroup) this._threeGroup.visible = !!visible;
|
||||
|
@@ -194,6 +194,7 @@ namespace gdjs {
|
||||
threeTexture.minFilter = THREE.LinearFilter;
|
||||
threeTexture.wrapS = THREE.RepeatWrapping;
|
||||
threeTexture.wrapT = THREE.RepeatWrapping;
|
||||
threeTexture.colorSpace = THREE.SRGBColorSpace;
|
||||
threeTexture.needsUpdate = true;
|
||||
|
||||
const resource = findResourceWithNameAndKind(
|
||||
|
@@ -69,6 +69,10 @@ namespace gdjs {
|
||||
gameCanvas = document.createElement('canvas');
|
||||
this._threeRenderer = new THREE.WebGLRenderer({
|
||||
canvas: gameCanvas,
|
||||
antialias:
|
||||
this._game.getAntialiasingMode() !== 'none' &&
|
||||
(this._game.isAntialisingEnabledOnMobile() ||
|
||||
!gdjs.evtTools.common.isMobile()),
|
||||
});
|
||||
this._threeRenderer.autoClear = false;
|
||||
this._threeRenderer.setSize(
|
||||
|
@@ -134,6 +134,7 @@ namespace gdjs {
|
||||
(runtimeLayer.isLightingLayer() &&
|
||||
runtimeLayerRenderer.getLightingSprite()) ||
|
||||
runtimeLayerRenderer.getRendererObject();
|
||||
|
||||
pixiRenderer.render(pixiContainer, { clear: false });
|
||||
this._layerRenderingMetrics.rendered2DLayersCount++;
|
||||
|
||||
@@ -197,6 +198,10 @@ namespace gdjs {
|
||||
);
|
||||
|
||||
isFirstRender = false;
|
||||
} else {
|
||||
// It's important to set the background to null, as maybe the first rendered
|
||||
// layer has changed and so the Three.js scene background must be reset.
|
||||
threeScene.background = null;
|
||||
}
|
||||
|
||||
// Clear the depth as each layer is independent and display on top of the previous one,
|
||||
@@ -210,6 +215,17 @@ namespace gdjs {
|
||||
}
|
||||
}
|
||||
|
||||
const debugContainer = this._runtimeScene
|
||||
.getDebuggerRenderer()
|
||||
.getRendererObject();
|
||||
|
||||
if (debugContainer) {
|
||||
threeRenderer.resetState();
|
||||
pixiRenderer.reset();
|
||||
pixiRenderer.render(debugContainer);
|
||||
lastRenderWas3D = false;
|
||||
}
|
||||
|
||||
if (!lastRenderWas3D) {
|
||||
// Out of caution, reset the WebGL states from PixiJS to start again
|
||||
// with a 3D rendering on the next frame.
|
||||
|
File diff suppressed because one or more lines are too long
@@ -153,6 +153,8 @@ namespace gdjs {
|
||||
_adaptGameResolutionAtRuntime: boolean;
|
||||
_scaleMode: 'linear' | 'nearest';
|
||||
_pixelsRounding: boolean;
|
||||
_antialiasingMode: 'none' | 'MSAA';
|
||||
_isAntialisingEnabledOnMobile: boolean;
|
||||
/**
|
||||
* Game loop management (see startGameLoop method)
|
||||
*/
|
||||
@@ -245,6 +247,8 @@ namespace gdjs {
|
||||
this._adaptGameResolutionAtRuntime = this._data.properties.adaptGameResolutionAtRuntime;
|
||||
this._scaleMode = data.properties.scaleMode || 'linear';
|
||||
this._pixelsRounding = this._data.properties.pixelsRounding;
|
||||
this._antialiasingMode = this._data.properties.antialiasingMode;
|
||||
this._isAntialisingEnabledOnMobile = this._data.properties.antialisingEnabledOnMobile;
|
||||
this._renderer = new gdjs.RuntimeGameRenderer(
|
||||
this,
|
||||
this._options.forceFullscreen || false
|
||||
@@ -637,6 +641,20 @@ namespace gdjs {
|
||||
return this._pixelsRounding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the antialiasing mode used by the game ("none" or "MSAA").
|
||||
*/
|
||||
getAntialiasingMode(): 'none' | 'MSAA' {
|
||||
return this._antialiasingMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if antialising is enabled on mobiles.
|
||||
*/
|
||||
isAntialisingEnabledOnMobile(): boolean {
|
||||
return this._isAntialisingEnabledOnMobile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set or unset the game as paused.
|
||||
* When paused, the game won't step and will be freezed. Useful for debugging.
|
||||
|
@@ -280,7 +280,7 @@ namespace gdjs {
|
||||
* To implement this in your object:
|
||||
* * Set `gdjs.YourRuntimeObject.supportsReinitialization = true;` to declare support for recycling.
|
||||
* * Implement `reinitialize`. It **must** call the `reinitialize` of `gdjs.RuntimeObject`, and call `this.onCreated();`
|
||||
* at the end of `reinitizalize`.
|
||||
* at the end of `reinitialize`.
|
||||
* * It must reset the object as if it was newly constructed (be careful about your renderers and any global state).
|
||||
* * The `_runtimeScene`, `_nameId`, `name` and `type` are guaranteed to stay the same and do not
|
||||
* need to be set again.
|
||||
|
6
GDJS/Runtime/types/global-three-addons.d.ts
vendored
6
GDJS/Runtime/types/global-three-addons.d.ts
vendored
@@ -1,7 +1,9 @@
|
||||
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
|
||||
import { GLTFLoader, GLTF } from 'three/examples/jsm/loaders/GLTFLoader';
|
||||
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
|
||||
import * as SkeletonUtils from 'three/examples/jsm/utils/SkeletonUtils';
|
||||
|
||||
declare global {
|
||||
namespace THREE_ADDONS {
|
||||
export { GLTFLoader };
|
||||
export { GLTFLoader, GLTF, DRACOLoader, SkeletonUtils };
|
||||
}
|
||||
}
|
||||
|
20
GDJS/Runtime/types/project-data.d.ts
vendored
20
GDJS/Runtime/types/project-data.d.ts
vendored
@@ -107,16 +107,26 @@ declare interface ExternalLayoutData {
|
||||
|
||||
declare interface InstanceData {
|
||||
persistentUuid: string;
|
||||
angle: number;
|
||||
customSize: boolean;
|
||||
height: number;
|
||||
|
||||
layer: string;
|
||||
locked: boolean;
|
||||
name: string;
|
||||
width: number;
|
||||
|
||||
x: number;
|
||||
y: number;
|
||||
z?: number;
|
||||
|
||||
angle: number;
|
||||
rotationX?: number;
|
||||
rotationY?: number;
|
||||
|
||||
zOrder: number;
|
||||
|
||||
customSize: boolean;
|
||||
width: number;
|
||||
height: number;
|
||||
depth?: number;
|
||||
|
||||
numberProperties: InstanceNumberProperty[];
|
||||
stringProperties: InstanceStringProperty[];
|
||||
initialVariables: RootVariableData[];
|
||||
@@ -180,6 +190,8 @@ declare interface ProjectPropertiesData {
|
||||
projectFile: string;
|
||||
scaleMode: 'linear' | 'nearest';
|
||||
pixelsRounding: boolean;
|
||||
antialiasingMode: 'none' | 'MSAA';
|
||||
antialisingEnabledOnMobile: boolean;
|
||||
sizeOnStartupMode: string;
|
||||
useExternalSourceFiles: boolean;
|
||||
version: string;
|
||||
|
43
GDJS/package-lock.json
generated
43
GDJS/package-lock.json
generated
@@ -14,17 +14,16 @@
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "^14.11.1",
|
||||
"@types/sinon": "^10.0.13",
|
||||
"@types/three": "0.150.1",
|
||||
"@types/three": "0.152.0",
|
||||
"better-docs": "^2.3.2",
|
||||
"esbuild": "^0.13.12",
|
||||
"lebab": "^3.1.0",
|
||||
"minimist": "^1.2.5",
|
||||
"patch-package": "^6.4.7",
|
||||
"pixi.js": "^6.1.2",
|
||||
"pixi.js": "6.1.2",
|
||||
"prettier": "2.1.2",
|
||||
"recursive-readdir": "^2.2.2",
|
||||
"shelljs": "^0.8.4",
|
||||
"three": "0.151.2",
|
||||
"typedoc": "^0.22.11",
|
||||
"typedoc-plugin-reference-excluder": "^1.0.0",
|
||||
"typescript": "4.3.2"
|
||||
@@ -730,6 +729,12 @@
|
||||
"@pixi/settings": "6.1.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@tweenjs/tween.js": {
|
||||
"version": "18.6.4",
|
||||
"resolved": "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-18.6.4.tgz",
|
||||
"integrity": "sha512-lB9lMjuqjtuJrx7/kOkqQBtllspPIN+96OvTCeJ2j5FEzinoAXTdAMFnDAQT1KVPRlnYfBrqxtqP66vDM40xxQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/babel-types": {
|
||||
"version": "7.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/babel-types/-/babel-types-7.0.9.tgz",
|
||||
@@ -791,11 +796,12 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/three": {
|
||||
"version": "0.150.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/three/-/three-0.150.1.tgz",
|
||||
"integrity": "sha512-ZXS1M3brsfAAbTeeUEt0defPi98yWQuEyPBnvjEYY1dCEYfJnFaww0mYgRpJ9JVfmtwRxqISpVcv/g/0lMl1DQ==",
|
||||
"version": "0.152.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/three/-/three-0.152.0.tgz",
|
||||
"integrity": "sha512-9QdaV5bfZEqeQi0xkXLdnoJt7lgYZbppdBAgJSWRicdtZoCYJ34nS2QkdeuzXt+UXExofk4OWqMzdX71HeDOVg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@tweenjs/tween.js": "~18.6.4",
|
||||
"@types/stats.js": "*",
|
||||
"@types/webxr": "*",
|
||||
"fflate": "~0.6.9",
|
||||
@@ -2936,12 +2942,6 @@
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/three": {
|
||||
"version": "0.151.2",
|
||||
"resolved": "https://registry.npmjs.org/three/-/three-0.151.2.tgz",
|
||||
"integrity": "sha512-tGaLRP2H6++tj2JumHD25slhFAx0C619rl6G6Utjq7JTrDGJwDxpu+J2XpnYIUMfEmhNvIFDQJfp79JtKmNBWw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/tmp": {
|
||||
"version": "0.0.33",
|
||||
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
|
||||
@@ -3818,6 +3818,12 @@
|
||||
"url": "^0.11.0"
|
||||
}
|
||||
},
|
||||
"@tweenjs/tween.js": {
|
||||
"version": "18.6.4",
|
||||
"resolved": "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-18.6.4.tgz",
|
||||
"integrity": "sha512-lB9lMjuqjtuJrx7/kOkqQBtllspPIN+96OvTCeJ2j5FEzinoAXTdAMFnDAQT1KVPRlnYfBrqxtqP66vDM40xxQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/babel-types": {
|
||||
"version": "7.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/babel-types/-/babel-types-7.0.9.tgz",
|
||||
@@ -3879,11 +3885,12 @@
|
||||
"dev": true
|
||||
},
|
||||
"@types/three": {
|
||||
"version": "0.150.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/three/-/three-0.150.1.tgz",
|
||||
"integrity": "sha512-ZXS1M3brsfAAbTeeUEt0defPi98yWQuEyPBnvjEYY1dCEYfJnFaww0mYgRpJ9JVfmtwRxqISpVcv/g/0lMl1DQ==",
|
||||
"version": "0.152.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/three/-/three-0.152.0.tgz",
|
||||
"integrity": "sha512-9QdaV5bfZEqeQi0xkXLdnoJt7lgYZbppdBAgJSWRicdtZoCYJ34nS2QkdeuzXt+UXExofk4OWqMzdX71HeDOVg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@tweenjs/tween.js": "~18.6.4",
|
||||
"@types/stats.js": "*",
|
||||
"@types/webxr": "*",
|
||||
"fflate": "~0.6.9",
|
||||
@@ -5592,12 +5599,6 @@
|
||||
"has-flag": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"three": {
|
||||
"version": "0.151.2",
|
||||
"resolved": "https://registry.npmjs.org/three/-/three-0.151.2.tgz",
|
||||
"integrity": "sha512-tGaLRP2H6++tj2JumHD25slhFAx0C619rl6G6Utjq7JTrDGJwDxpu+J2XpnYIUMfEmhNvIFDQJfp79JtKmNBWw==",
|
||||
"dev": true
|
||||
},
|
||||
"tmp": {
|
||||
"version": "0.0.33",
|
||||
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
|
||||
|
@@ -10,17 +10,16 @@
|
||||
"@types/mocha": "^5.2.7",
|
||||
"@types/node": "^14.11.1",
|
||||
"@types/sinon": "^10.0.13",
|
||||
"@types/three": "0.150.1",
|
||||
"@types/three": "0.152.0",
|
||||
"better-docs": "^2.3.2",
|
||||
"esbuild": "^0.13.12",
|
||||
"lebab": "^3.1.0",
|
||||
"minimist": "^1.2.5",
|
||||
"patch-package": "^6.4.7",
|
||||
"pixi.js": "^6.1.2",
|
||||
"pixi.js": "6.1.2",
|
||||
"prettier": "2.1.2",
|
||||
"recursive-readdir": "^2.2.2",
|
||||
"shelljs": "^0.8.4",
|
||||
"three": "0.151.2",
|
||||
"typedoc": "^0.22.11",
|
||||
"typedoc-plugin-reference-excluder": "^1.0.0",
|
||||
"typescript": "4.3.2"
|
||||
|
@@ -24,13 +24,14 @@ const untransformedPaths = [
|
||||
// GDJS prebuilt files:
|
||||
'GDJS/Runtime/pixi-renderers/pixi.js',
|
||||
'GDJS/Runtime/pixi-renderers/three.js',
|
||||
'GDJS/Runtime/pixi-renderers/ThreeAddons.js',
|
||||
'GDJS/Runtime/pixi-renderers/draco/gltf/draco_wasm_wrapper.js',
|
||||
'GDJS/Runtime/fontfaceobserver-font-manager/fontfaceobserver.js',
|
||||
'GDJS/Runtime/Cordova',
|
||||
'GDJS/Runtime/Electron',
|
||||
'GDJS/Runtime/FacebookInstantGames',
|
||||
'GDJS/Runtime/libs/CocoonJS',
|
||||
'GDJS/Runtime/libs/rbush.js',
|
||||
'GDJS/Runtime/libs/ThreeAddons.js',
|
||||
|
||||
// Extensions pre-built files:
|
||||
'Extensions/Leaderboards/sha256.js',
|
||||
|
@@ -18,6 +18,8 @@ gdjs.getPixiRuntimeGame = (settings) => {
|
||||
scaleMode: 'linear',
|
||||
pixelsRounding: false,
|
||||
sizeOnStartupMode: '',
|
||||
antialiasingMode: 'MSAA',
|
||||
antialisingEnabledOnMobile: false,
|
||||
useExternalSourceFiles: true,
|
||||
version: '1.0.0',
|
||||
name: 'Test game',
|
||||
|
@@ -22,6 +22,8 @@ gdjs.getPixiRuntimeGameWithAssets = () => {
|
||||
scaleMode: 'linear',
|
||||
pixelsRounding: false,
|
||||
sizeOnStartupMode: 'adaptWidth',
|
||||
antialiasingMode: 'MSAA',
|
||||
antialisingEnabledOnMobile: false,
|
||||
useExternalSourceFiles: true,
|
||||
version: '1.0.0',
|
||||
name: 'Test game with real assets',
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user