mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
Compare commits
177 Commits
close-prev
...
v5.1.162
Author | SHA1 | Date | |
---|---|---|---|
![]() |
fde1039707 | ||
![]() |
73e087936a | ||
![]() |
260fd5949e | ||
![]() |
a4939181a5 | ||
![]() |
cab56451ff | ||
![]() |
7b32bbacd6 | ||
![]() |
a15707d655 | ||
![]() |
714a9f1198 | ||
![]() |
2a91c54b0e | ||
![]() |
3272b8eda7 | ||
![]() |
cd432a22b6 | ||
![]() |
9ac483156e | ||
![]() |
d0f39027af | ||
![]() |
5d8a59533d | ||
![]() |
243a72008b | ||
![]() |
e56cdac96a | ||
![]() |
cf374737fc | ||
![]() |
3d043f5264 | ||
![]() |
032f53e4e3 | ||
![]() |
f68ae4b8d8 | ||
![]() |
fa40381fb4 | ||
![]() |
544b6243ba | ||
![]() |
0a03cbb89c | ||
![]() |
c00d75f047 | ||
![]() |
5dce0684f5 | ||
![]() |
cb44999538 | ||
![]() |
4a9de2edf3 | ||
![]() |
8c3728f8b7 | ||
![]() |
212c58f67c | ||
![]() |
f5d89c66ea | ||
![]() |
8fb139ff63 | ||
![]() |
0c0fb5da1c | ||
![]() |
65a33589c0 | ||
![]() |
7ec5a95de8 | ||
![]() |
26289eec99 | ||
![]() |
cc0a01bbdb | ||
![]() |
a0fb289aaf | ||
![]() |
94045aec91 | ||
![]() |
b70d4c54c1 | ||
![]() |
f269b820fc | ||
![]() |
f91bde1fca | ||
![]() |
73ac71dadf | ||
![]() |
52fcf52ecc | ||
![]() |
55c7c4e8bf | ||
![]() |
d6a15d4090 | ||
![]() |
21a87daf64 | ||
![]() |
c712ab3163 | ||
![]() |
6c27c3dcf8 | ||
![]() |
f8de6c2ea9 | ||
![]() |
b2e8c23944 | ||
![]() |
bfc6a69d77 | ||
![]() |
3abf81fda2 | ||
![]() |
4caef9c7e6 | ||
![]() |
f9edfdef72 | ||
![]() |
4e0e4b9184 | ||
![]() |
908926bf73 | ||
![]() |
2ba81cc7d6 | ||
![]() |
e77e1fb840 | ||
![]() |
f0f47ca2f0 | ||
![]() |
07920fda9f | ||
![]() |
48e4447212 | ||
![]() |
b69dcafcc6 | ||
![]() |
89e06b0801 | ||
![]() |
5e1a6eb084 | ||
![]() |
f89a48fb2c | ||
![]() |
ddb65012ce | ||
![]() |
bb0fe0ea37 | ||
![]() |
747cdf0243 | ||
![]() |
385ec5e9ca | ||
![]() |
bcbdc35d72 | ||
![]() |
6053369474 | ||
![]() |
ed1e0852b5 | ||
![]() |
23ce46439a | ||
![]() |
d9b35018e7 | ||
![]() |
571ab1313d | ||
![]() |
aff82c4733 | ||
![]() |
2d4fc0af07 | ||
![]() |
7cadf35642 | ||
![]() |
73e1ea5ff1 | ||
![]() |
bc87caf640 | ||
![]() |
95dfb391c4 | ||
![]() |
4b973c9655 | ||
![]() |
23f24a3939 | ||
![]() |
b3ed22806b | ||
![]() |
4afefafc76 | ||
![]() |
d2a1d8620f | ||
![]() |
fdfc028a2c | ||
![]() |
48cd42fee0 | ||
![]() |
b215eff444 | ||
![]() |
1bf66a97ae | ||
![]() |
cc6890a495 | ||
![]() |
418dd834c0 | ||
![]() |
e52faae332 | ||
![]() |
31809fdf61 | ||
![]() |
17504c1713 | ||
![]() |
e29b79fdc9 | ||
![]() |
b0009cc999 | ||
![]() |
384eb2b8ee | ||
![]() |
5fa0627218 | ||
![]() |
e66660d2df | ||
![]() |
df6320c39f | ||
![]() |
ca667c02be | ||
![]() |
62d0754b33 | ||
![]() |
4c4ca0d202 | ||
![]() |
5c68d117c6 | ||
![]() |
21b9ae47ab | ||
![]() |
e8687119c9 | ||
![]() |
9c09e26aaa | ||
![]() |
c223abad60 | ||
![]() |
769de55317 | ||
![]() |
0dfe765ae1 | ||
![]() |
b94ce2b20d | ||
![]() |
89eb61b4a6 | ||
![]() |
32ba55e726 | ||
![]() |
844ac23666 | ||
![]() |
657036384d | ||
![]() |
b13ce5b17c | ||
![]() |
8f0f5a5bc5 | ||
![]() |
d23a064ca2 | ||
![]() |
3b0dc66046 | ||
![]() |
356bde650b | ||
![]() |
6d25496f89 | ||
![]() |
dfeeb864a5 | ||
![]() |
25c36d26db | ||
![]() |
36721c63e0 | ||
![]() |
69cd89ddb8 | ||
![]() |
2db4b54986 | ||
![]() |
303a4d20ed | ||
![]() |
a09bfafd26 | ||
![]() |
822329af63 | ||
![]() |
0b90e17307 | ||
![]() |
00817b4393 | ||
![]() |
2a5bbcb8d4 | ||
![]() |
7f03579855 | ||
![]() |
c7e42d1e88 | ||
![]() |
e3fd91681c | ||
![]() |
c8392332c7 | ||
![]() |
14d7dafb79 | ||
![]() |
373d5e14b8 | ||
![]() |
8b89896082 | ||
![]() |
e7d213534e | ||
![]() |
859b1d0a1c | ||
![]() |
2b6a14c612 | ||
![]() |
07051017b9 | ||
![]() |
0d5f238c75 | ||
![]() |
936c75b4ed | ||
![]() |
8d1bdfed25 | ||
![]() |
440205531f | ||
![]() |
8f45642a25 | ||
![]() |
1e6ca8c403 | ||
![]() |
113e329d7a | ||
![]() |
48ae688873 | ||
![]() |
fe77180748 | ||
![]() |
48b88b9d92 | ||
![]() |
f57a8bc6cd | ||
![]() |
1b827eb67b | ||
![]() |
c3521db5ba | ||
![]() |
b51e47233e | ||
![]() |
1bf9d3c432 | ||
![]() |
1c47d12033 | ||
![]() |
1250060848 | ||
![]() |
4712c3d9ef | ||
![]() |
56cf1cf18f | ||
![]() |
0427766b9d | ||
![]() |
8cf20cdef2 | ||
![]() |
b3f74a3e9b | ||
![]() |
38f15503e9 | ||
![]() |
47f15f6881 | ||
![]() |
b0c8bf9625 | ||
![]() |
089c774ad6 | ||
![]() |
a2ca532749 | ||
![]() |
a6e7dd6160 | ||
![]() |
7b6f3c029d | ||
![]() |
6c31056be4 | ||
![]() |
2f8287b017 | ||
![]() |
0ef4012b03 | ||
![]() |
438d70e8ba |
@@ -1,6 +0,0 @@
|
||||
# This is the Dockerfile to create a "devcontainer".
|
||||
# This is a way to quickly create a development environment,
|
||||
# that can be used with GitHub workspaces.
|
||||
|
||||
# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.162.0/containers/codespaces-linux/.devcontainer/base.Dockerfile
|
||||
FROM mcr.microsoft.com/vscode/devcontainers/universal:1-focal
|
@@ -1,16 +0,0 @@
|
||||
# Devcontainer (development environment in the cloud) for GDevelop (beta)
|
||||
|
||||
A devcontainer is the configuration to run a cloud development environment, available remotely.
|
||||
This is notably used to run a **[GitHub Codespace](https://docs.github.com/en/github/developing-online-with-codespaces/about-codespaces)**. The advantage is that you can quickly experiment and do changes without installing anything on your computer.
|
||||
|
||||
> ⚠️ This development environment is in beta, and not everything is supported. This is useful for playing a bit with GDevelop codebase or to make quick changes. **In particular, it's not possible to test your changes on GDJS** because only the web-app can be launched.
|
||||
|
||||
It's recommended that you follow the usual [README](../newIDE/README.md) to get started, with development tools installed on your computer.
|
||||
|
||||
## Start a GitHub workspace to work on GDevelop (beta)
|
||||
|
||||
- Subscribe to the [beta edition of GitHub workspace](https://docs.github.com/en/github/developing-online-with-codespaces/about-codespaces#joining-the-beta).
|
||||
- In the repository GitHub page, click **Code** and then choose **Open with Codespaces**.
|
||||
- Wait for the Codespace to load and Visual Studio Code to open.
|
||||
- When it's ready, open a terminal in Visual Studio Code.
|
||||
- Follow the usual [README in `newIDE`](../newIDE/README.md) to get started, like you would do on your own computer.
|
@@ -1,51 +0,0 @@
|
||||
// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
|
||||
// https://github.com/microsoft/vscode-dev-containers/tree/v0.162.0/containers/codespaces-linux
|
||||
{
|
||||
"name": "GitHub Codespaces for GDevelop",
|
||||
"build": {
|
||||
"dockerfile": "Dockerfile"
|
||||
},
|
||||
"settings": {
|
||||
"terminal.integrated.shell.linux": "/bin/zsh",
|
||||
"go.toolsManagement.checkForUpdates": "off",
|
||||
"go.useLanguageServer": true,
|
||||
"go.gopath": "/go",
|
||||
"go.goroot": "/usr/local/go",
|
||||
"python.pythonPath": "/opt/python/latest/bin/python",
|
||||
"python.linting.enabled": true,
|
||||
"python.linting.pylintEnabled": true,
|
||||
"python.formatting.autopep8Path": "/usr/local/py-utils/bin/autopep8",
|
||||
"python.formatting.blackPath": "/usr/local/py-utils/bin/black",
|
||||
"python.formatting.yapfPath": "/usr/local/py-utils/bin/yapf",
|
||||
"python.linting.banditPath": "/usr/local/py-utils/bin/bandit",
|
||||
"python.linting.flake8Path": "/usr/local/py-utils/bin/flake8",
|
||||
"python.linting.mypyPath": "/usr/local/py-utils/bin/mypy",
|
||||
"python.linting.pycodestylePath": "/usr/local/py-utils/bin/pycodestyle",
|
||||
"python.linting.pydocstylePath": "/usr/local/py-utils/bin/pydocstyle",
|
||||
"python.linting.pylintPath": "/usr/local/py-utils/bin/pylint",
|
||||
"lldb.executable": "/usr/bin/lldb",
|
||||
"files.watcherExclude": {
|
||||
"**/target/**": true
|
||||
}
|
||||
},
|
||||
"remoteUser": "codespace",
|
||||
"overrideCommand": false,
|
||||
"workspaceMount": "source=${localWorkspaceFolder},target=/home/codespace/workspace,type=bind,consistency=cached",
|
||||
"workspaceFolder": "/home/codespace/workspace",
|
||||
"runArgs": [ "--cap-add=SYS_PTRACE", "--security-opt", "seccomp=unconfined", "--privileged", "--init" ],
|
||||
|
||||
// Add the IDs of extensions you want installed when the container is created.
|
||||
"extensions": [
|
||||
"GitHub.vscode-pull-request-github",
|
||||
"esbenp.prettier-vscode",
|
||||
"ms-vscode.cpptools",
|
||||
"xaver.clang-format",
|
||||
"flowtype.flow-for-vscode"
|
||||
],
|
||||
|
||||
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
||||
// "forwardPorts": [],
|
||||
|
||||
// "oryx build" will automatically install your dependencies and attempt to build your project
|
||||
"postCreateCommand": "oryx build -p virtualenv_name=.venv || echo 'Could not auto-build. Skipping.'"
|
||||
}
|
28
.github/ISSUE_TEMPLATE/--bug-report.md
vendored
28
.github/ISSUE_TEMPLATE/--bug-report.md
vendored
@@ -1,28 +0,0 @@
|
||||
---
|
||||
name: "\U0001F41BBug report"
|
||||
about: Create a bug report about GDevelop or the game engine
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
## Describe the bug
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
Please double check that the bug is not already reported in the issues list.
|
||||
|
||||
## To Reproduce
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
* Please include a link to a game if possible!
|
||||
* If applicable, add screenshots to help explain your problem.
|
||||
|
||||
## Other details
|
||||
* Include any OS/browser version/smartphone that you're using
|
||||
* Which version of GDevelop are you using? The desktop app or the web-app?
|
||||
* Add any other context about the problem here.
|
71
.github/ISSUE_TEMPLATE/--bug-report.yml
vendored
Normal file
71
.github/ISSUE_TEMPLATE/--bug-report.yml
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
name: 🐛Bug report
|
||||
description: Create a bug report about GDevelop or the game engine
|
||||
body:
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Is there an existing issue for this?
|
||||
options:
|
||||
- label: I have searched the [existing issues](https://github.com/4ian/GDevelop/issues)
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Describe the bug
|
||||
description: A clear and concise description of what the bug is.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Steps to reproduce
|
||||
description: |
|
||||
* Please include a link to a game if possible!
|
||||
* If applicable, add screenshots to help explain your problem.
|
||||
placeholder: |
|
||||
1. Go to '...'
|
||||
2. Click on '...'
|
||||
3. Scroll down to '...'
|
||||
4. See error
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
attributes:
|
||||
label: GDevelop platform
|
||||
description: Which platform of GDevelop are you using?
|
||||
multiple: true
|
||||
options:
|
||||
- Desktop
|
||||
- Web
|
||||
- Mobile
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
attributes:
|
||||
label: GDevelop version
|
||||
description: |
|
||||
Which version of GDevelop are you using?
|
||||
Take a look here: [Editor Home - About GDevelop - "This version of GDevelop is: ~~~"]
|
||||
placeholder: 5.1.159? 5.1.160?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Platform info
|
||||
value: |
|
||||
<details>
|
||||
|
||||
*OS (e.g. Windows, Linux, macOS, Android, iOS)*
|
||||
>
|
||||
|
||||
*OS Version (e.g. Windows 10, macOS 10.15)*
|
||||
>
|
||||
|
||||
*Browser(For Web) (e.g. Chrome, Firefox, Safari)*
|
||||
>
|
||||
|
||||
*Device(For Mobile) (e.g. iPhone 12, Samsung Galaxy S21)*
|
||||
>
|
||||
|
||||
</details>
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Additional context
|
||||
description: Add any other context about the problem here.
|
@@ -1,3 +1,3 @@
|
||||
This is the directory where native or WebAssembly binaries of the C++ code of GDCore and GDJS are produced.
|
||||
|
||||
See GDevelop.js README for the instructions to compile after a change in the C++ source code.
|
||||
See GDevelop.js README for the instructions to compile after a change in the C++ source code.
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#This is the CMake file used to build GDevelop.
|
||||
#For more information, see the Readme.md file.
|
||||
#For more information, see the README.md file.
|
||||
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
cmake_policy(SET CMP0011 NEW)
|
||||
|
@@ -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
|
||||
|
@@ -13,6 +13,7 @@
|
||||
namespace gd {
|
||||
class Instruction;
|
||||
class Project;
|
||||
class EventVisitor;
|
||||
}
|
||||
class EventsCodeGenerationContext;
|
||||
|
||||
|
@@ -16,6 +16,7 @@
|
||||
#include "GDCore/Project/Object.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
#include "GDCore/Events/EventVisitor.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
@@ -156,4 +157,14 @@ void LinkEvent::UnserializeFrom(gd::Project& project,
|
||||
}
|
||||
}
|
||||
|
||||
bool LinkEvent::AcceptVisitor(gd::EventVisitor &eventVisitor) {
|
||||
return BaseEvent::AcceptVisitor(eventVisitor) |
|
||||
eventVisitor.VisitLinkEvent(*this);
|
||||
}
|
||||
|
||||
void LinkEvent::AcceptVisitor(gd::ReadOnlyEventVisitor &eventVisitor) const {
|
||||
BaseEvent::AcceptVisitor(eventVisitor);
|
||||
eventVisitor.VisitLinkEvent(*this);
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -30,7 +30,7 @@ class GD_CORE_API LinkEvent : public gd::BaseEvent {
|
||||
includeEnd(gd::String::npos),
|
||||
linkWasInvalid(false){};
|
||||
virtual ~LinkEvent();
|
||||
virtual gd::LinkEvent* Clone() const { return new LinkEvent(*this); }
|
||||
virtual gd::LinkEvent* Clone() const override { return new LinkEvent(*this); }
|
||||
|
||||
/**
|
||||
* Get the link target (i.e. the scene or external events the link refers to).
|
||||
@@ -86,7 +86,7 @@ class GD_CORE_API LinkEvent : public gd::BaseEvent {
|
||||
/**
|
||||
* The link event must always be preprocessed.
|
||||
*/
|
||||
virtual bool MustBePreprocessed() { return true; }
|
||||
virtual bool MustBePreprocessed() override { return true; }
|
||||
|
||||
/**
|
||||
* \brief Get a pointer to the list of events that are targeted by the link.
|
||||
@@ -107,11 +107,14 @@ class GD_CORE_API LinkEvent : public gd::BaseEvent {
|
||||
EventsList& eventList,
|
||||
std::size_t indexOfTheEventInThisList);
|
||||
|
||||
virtual bool IsExecutable() const { return true; };
|
||||
virtual bool IsExecutable() const override { return true; };
|
||||
|
||||
virtual void SerializeTo(SerializerElement& element) const;
|
||||
virtual void SerializeTo(SerializerElement& element) const override;
|
||||
virtual void UnserializeFrom(gd::Project& project,
|
||||
const SerializerElement& element);
|
||||
const SerializerElement& element) override;
|
||||
|
||||
bool AcceptVisitor(gd::EventVisitor& eventVisitor) override;
|
||||
void AcceptVisitor(gd::ReadOnlyEventVisitor& eventVisitor) const override;
|
||||
|
||||
private:
|
||||
gd::String
|
||||
|
@@ -273,8 +273,6 @@ gd::String EventsCodeGenerator::GenerateConditionCode(
|
||||
|
||||
if (instrInfos.codeExtraInformation.HasCustomCodeGenerator()) {
|
||||
context.EnterCustomCondition();
|
||||
conditionCode += GenerateReferenceToUpperScopeBoolean(
|
||||
"conditionTrue", returnBoolean, context);
|
||||
conditionCode += instrInfos.codeExtraInformation.customCodeGenerator(
|
||||
condition, *this, context);
|
||||
maxCustomConditionsDepth =
|
||||
@@ -291,7 +289,7 @@ gd::String EventsCodeGenerator::GenerateConditionCode(
|
||||
condition.SetParameters(parameters);
|
||||
}
|
||||
|
||||
// Verify that there are no mismatchs between object type in parameters.
|
||||
// Verify that there are no mismatches between object type in parameters.
|
||||
for (std::size_t pNb = 0; pNb < instrInfos.parameters.size(); ++pNb) {
|
||||
if (ParameterMetadata::IsObject(instrInfos.parameters[pNb].GetType())) {
|
||||
gd::String objectInParameter =
|
||||
@@ -483,7 +481,7 @@ gd::String EventsCodeGenerator::GenerateActionCode(
|
||||
action.SetParameters(parameters);
|
||||
}
|
||||
|
||||
// Verify that there are no mismatchs between object type in parameters.
|
||||
// Verify that there are no mismatches between object type in parameters.
|
||||
for (std::size_t pNb = 0; pNb < instrInfos.parameters.size(); ++pNb) {
|
||||
if (ParameterMetadata::IsObject(instrInfos.parameters[pNb].GetType())) {
|
||||
gd::String objectInParameter = action.GetParameter(pNb).GetPlainString();
|
||||
@@ -729,6 +727,7 @@ gd::String EventsCodeGenerator::GenerateParameterCodes(
|
||||
metadata.GetType() == "tilemapResource" ||
|
||||
metadata.GetType() == "tilesetResource" ||
|
||||
metadata.GetType() == "videoResource" ||
|
||||
metadata.GetType() == "model3DResource" ||
|
||||
// Deprecated, old parameter names:
|
||||
metadata.GetType() == "password" || metadata.GetType() == "musicfile" ||
|
||||
metadata.GetType() == "soundfile" || metadata.GetType() == "police") {
|
||||
@@ -1240,7 +1239,7 @@ size_t EventsCodeGenerator::GenerateSingleUsageUniqueIdFor(
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
// Base the unique id on the adress in memory so that the same instruction
|
||||
// Base the unique id on the address in memory so that the same instruction
|
||||
// in memory will get the same id across different code generations.
|
||||
size_t uniqueId = (size_t)instruction;
|
||||
|
||||
|
@@ -404,6 +404,18 @@ class GD_CORE_API EventsCodeGenerator {
|
||||
return boolName;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Generate the full name for accessing to a boolean variable used for
|
||||
* conditions.
|
||||
*
|
||||
* Default implementation just returns the boolean name passed as argument.
|
||||
*/
|
||||
virtual gd::String GenerateUpperScopeBooleanFullName(
|
||||
const gd::String& boolName,
|
||||
const gd::EventsCodeGenerationContext& context) {
|
||||
return boolName;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Must create a boolean. Its value must be false.
|
||||
*
|
||||
@@ -493,9 +505,9 @@ class GD_CORE_API EventsCodeGenerator {
|
||||
* - object : Object name -> string
|
||||
* - expression : Mathematical expression -> number (double)
|
||||
* - string : %Text expression -> string
|
||||
* - layer, color, file, joyaxis : Same as string
|
||||
* - layer, color, file, stringWithSelector : Same as string
|
||||
* - relationalOperator : Used to make a comparison between the function
|
||||
resturn value and value of the parameter preceding the relationOperator
|
||||
return value and value of the parameter preceding the relationOperator
|
||||
parameter -> string
|
||||
* - operator : Used to update a value using a setter and a getter -> string
|
||||
* - key, mouse, objectvar, scenevar, globalvar, password, musicfile,
|
||||
@@ -665,19 +677,6 @@ class GD_CORE_API EventsCodeGenerator {
|
||||
return "!(" + predicat + ")";
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Must create a boolean which is a reference to a boolean declared in
|
||||
* the parent scope.
|
||||
*
|
||||
* The default implementation generates C-style code.
|
||||
*/
|
||||
virtual gd::String GenerateReferenceToUpperScopeBoolean(
|
||||
const gd::String& referenceName,
|
||||
const gd::String& referencedBoolean,
|
||||
gd::EventsCodeGenerationContext& context) {
|
||||
return "bool & " + referenceName + " = " + referencedBoolean + ";\n";
|
||||
}
|
||||
|
||||
virtual gd::String GenerateFreeCondition(
|
||||
const std::vector<gd::String>& arguments,
|
||||
const gd::InstructionMetadata& instrInfos,
|
||||
@@ -786,7 +785,7 @@ class GD_CORE_API EventsCodeGenerator {
|
||||
const gd::Project* project; ///< The project being used.
|
||||
const gd::Layout* scene; ///< The scene being generated.
|
||||
|
||||
bool errorOccurred; ///< Must be set to true if an error occured.
|
||||
bool errorOccurred; ///< Must be set to true if an error occurred.
|
||||
bool compilationForRuntime; ///< Is set to true if the code generation is
|
||||
///< made for runtime only.
|
||||
|
||||
|
@@ -51,8 +51,8 @@ gd::String ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
codeGenerator.GetObjectsAndGroups(),
|
||||
rootType);
|
||||
node->Visit(validator);
|
||||
if (!validator.GetErrors().empty()) {
|
||||
std::cout << "Error: \"" << validator.GetErrors()[0]->GetMessage()
|
||||
if (!validator.GetFatalErrors().empty()) {
|
||||
std::cout << "Error: \"" << validator.GetFatalErrors()[0]->GetMessage()
|
||||
<< "\" in: \"" << expression.GetPlainString() << "\" ("
|
||||
<< rootType << ")" << std::endl;
|
||||
|
||||
@@ -170,7 +170,7 @@ void ExpressionCodeGenerator::OnVisitIdentifierNode(IdentifierNode& node) {
|
||||
}
|
||||
else {
|
||||
// This is for function names that are put in IdentifierNode
|
||||
// because the type is needed to tell them appart from variables.
|
||||
// because the type is needed to tell them apart from variables.
|
||||
output += GenerateDefaultValue(type);
|
||||
}
|
||||
}
|
||||
|
@@ -9,6 +9,7 @@
|
||||
#include "GDCore/Events/Builtin/AsyncEvent.h"
|
||||
#include "GDCore/Events/CodeGeneration/EventsCodeGenerator.h"
|
||||
#include "GDCore/Events/EventsList.h"
|
||||
#include "GDCore/Events/EventVisitor.h"
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
#include "GDCore/Extensions/Platform.h"
|
||||
#include "GDCore/Extensions/PlatformExtension.h"
|
||||
@@ -140,6 +141,14 @@ void BaseEvent::Preprocess(gd::EventsCodeGenerator& codeGenerator,
|
||||
}
|
||||
}
|
||||
|
||||
bool BaseEvent::AcceptVisitor(gd::EventVisitor& eventVisitor) {
|
||||
return eventVisitor.VisitEvent(*this);
|
||||
}
|
||||
|
||||
void BaseEvent::AcceptVisitor(gd::ReadOnlyEventVisitor& eventVisitor) const {
|
||||
eventVisitor.VisitEvent(*this);
|
||||
}
|
||||
|
||||
BaseEventSPtr GD_CORE_API CloneRememberingOriginalEvent(BaseEventSPtr event) {
|
||||
gd::BaseEventSPtr copy(event->Clone());
|
||||
// Original event is either the original event of the copied event, or the
|
||||
|
@@ -24,6 +24,8 @@ class EventsCodeGenerationContext;
|
||||
class Platform;
|
||||
class SerializerElement;
|
||||
class Instruction;
|
||||
class EventVisitor;
|
||||
class ReadOnlyEventVisitor;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
@@ -238,6 +240,9 @@ class GD_CORE_API BaseEvent {
|
||||
*/
|
||||
virtual void UnserializeFrom(gd::Project& project,
|
||||
const SerializerElement& element){};
|
||||
|
||||
virtual bool AcceptVisitor(gd::EventVisitor& eventVisitor);
|
||||
virtual void AcceptVisitor(gd::ReadOnlyEventVisitor& eventVisitor) const;
|
||||
///@}
|
||||
|
||||
/** \name Common properties
|
||||
|
71
Core/GDCore/Events/EventVisitor.h
Normal file
71
Core/GDCore/Events/EventVisitor.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
class BaseEvent;
|
||||
class LinkEvent;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief Visitor of any kind of event.
|
||||
*
|
||||
* \ingroup Events
|
||||
*/
|
||||
class GD_CORE_API EventVisitor {
|
||||
public:
|
||||
virtual ~EventVisitor(){};
|
||||
|
||||
/**
|
||||
* Called to do some work on an event.
|
||||
*
|
||||
* \return true if the event must be deleted from the events list, false
|
||||
* otherwise.
|
||||
*/
|
||||
virtual bool VisitEvent(gd::BaseEvent& linkEvent) = 0;
|
||||
|
||||
/**
|
||||
* Called to do some work on a link event.
|
||||
*
|
||||
* Note that VisitEvent is also called with this event.
|
||||
*
|
||||
* \return true if the event must be deleted from the events list, false
|
||||
* otherwise.
|
||||
*/
|
||||
virtual bool VisitLinkEvent(gd::LinkEvent& linkEvent) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Visitor of any kind of event.
|
||||
*
|
||||
* \ingroup Events
|
||||
*/
|
||||
class GD_CORE_API ReadOnlyEventVisitor {
|
||||
public:
|
||||
virtual ~ReadOnlyEventVisitor(){};
|
||||
|
||||
/**
|
||||
* Called to do some work on an event.
|
||||
*/
|
||||
virtual void VisitEvent(const gd::BaseEvent& linkEvent) = 0;
|
||||
|
||||
/**
|
||||
* Called to do some work on a link event.
|
||||
*
|
||||
* Note that VisitEvent is also called with this event.
|
||||
*/
|
||||
virtual void VisitLinkEvent(const gd::LinkEvent& linkEvent) = 0;
|
||||
};
|
||||
|
||||
}
|
@@ -33,7 +33,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAdvancedExtension(
|
||||
"res/function32.png",
|
||||
"res/function32.png")
|
||||
.SetHelpPath("/events/functions/return")
|
||||
.AddParameter("expression", "The number to be returned")
|
||||
.AddParameter("expression", _("The number to be returned"))
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
@@ -48,7 +48,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAdvancedExtension(
|
||||
"res/function32.png",
|
||||
"res/function32.png")
|
||||
.SetHelpPath("/events/functions/return")
|
||||
.AddParameter("string", "The text to be returned")
|
||||
.AddParameter("string", _("The text to be returned"))
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
@@ -62,7 +62,37 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAdvancedExtension(
|
||||
"res/function32.png",
|
||||
"res/function32.png")
|
||||
.SetHelpPath("/events/functions/return")
|
||||
.AddParameter("trueorfalse", "Should the condition be true or false?")
|
||||
.AddParameter("trueorfalse", _("Should the condition be true or false?"))
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddAction("CopyArgumentToVariable",
|
||||
_("Copy function parameter to variable"),
|
||||
_("Copy a function parameter (also called \"argument\") to a variable. "
|
||||
"The parameter type must be a variable."),
|
||||
_("Copy the parameter _PARAM0_ into the variable _PARAM1_"),
|
||||
"",
|
||||
"res/function32.png",
|
||||
"res/function32.png")
|
||||
.SetHelpPath("/events/functions/return")
|
||||
.AddParameter("functionParameterName", _("Parameter name"), "variable")
|
||||
.AddParameter("scenevar", _("Scene variable"))
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddAction("CopyVariableToArgument",
|
||||
_("Copy variable to function parameter"),
|
||||
_("Copy a variable to function parameter (also called \"argument\"). "
|
||||
"The parameter type must be a variable."),
|
||||
_("Copy the variable _PARAM1_ into the parameter _PARAM0_"),
|
||||
"",
|
||||
"res/function32.png",
|
||||
"res/function32.png")
|
||||
.SetHelpPath("/events/functions/return")
|
||||
.AddParameter("functionParameterName", _("Parameter name"), "variable")
|
||||
.AddParameter("scenevar", _("Scene variable"))
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
@@ -77,7 +107,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAdvancedExtension(
|
||||
"",
|
||||
"res/function32.png",
|
||||
"res/function32.png")
|
||||
.AddParameter("functionParameterName", "Parameter name")
|
||||
.AddParameter("functionParameterName", _("Parameter name"), "number,string,boolean")
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
@@ -88,7 +118,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAdvancedExtension(
|
||||
_("Get function parameter (also called \"argument\") value."),
|
||||
"",
|
||||
"res/function16.png")
|
||||
.AddParameter("functionParameterName", "Parameter name")
|
||||
.AddParameter("functionParameterName", _("Parameter name"), "number,string,boolean")
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
@@ -98,7 +128,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAdvancedExtension(
|
||||
_("Get function parameter (also called \"argument\") text."),
|
||||
"",
|
||||
"res/function16.png")
|
||||
.AddParameter("functionParameterName", "Parameter name")
|
||||
.AddParameter("functionParameterName", _("Parameter name"), "number,string,boolean")
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
@@ -110,7 +140,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAdvancedExtension(
|
||||
"",
|
||||
"res/function32.png",
|
||||
"res/function16.png")
|
||||
.AddParameter("functionParameterName", "Parameter name")
|
||||
.AddParameter("functionParameterName", _("Parameter name"), "number,string,boolean")
|
||||
.UseStandardRelationalOperatorParameters(
|
||||
"number", gd::ParameterOptions::MakeNewOptions())
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
@@ -124,7 +154,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAdvancedExtension(
|
||||
"",
|
||||
"res/function32.png",
|
||||
"res/function16.png")
|
||||
.AddParameter("functionParameterName", "Parameter name")
|
||||
.AddParameter("functionParameterName", _("Parameter name"), "number,string,boolean")
|
||||
.UseStandardRelationalOperatorParameters(
|
||||
"string", gd::ParameterOptions::MakeNewOptions())
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
@@ -1349,7 +1349,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.AddParameter("objectListOrEmptyIfJustDeclared", _("Object to create"))
|
||||
.AddParameter("expression", _("X position"))
|
||||
.AddParameter("expression", _("Y position"))
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
|
||||
.AddParameter("layer", _("Layer"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
.MarkAsSimple();
|
||||
|
||||
@@ -1374,7 +1374,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
"with this name are found in the group, no object will be created."))
|
||||
.AddParameter("expression", _("X position"))
|
||||
.AddParameter("expression", _("Y position"))
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
|
||||
.AddParameter("layer", _("Layer"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
.MarkAsAdvanced();
|
||||
|
||||
@@ -1404,7 +1404,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
_("Objects"),
|
||||
"res/actions/ajouthasard24.png",
|
||||
"res/actions/ajouthasard.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddCodeOnlyParameter("objectsContext", "")
|
||||
.AddParameter("objectList", _("Object"))
|
||||
.MarkAsSimple();
|
||||
|
||||
@@ -1463,7 +1463,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
_("Objects"),
|
||||
"res/conditions/add24.png",
|
||||
"res/conditions/add.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddCodeOnlyParameter("objectsContext", "")
|
||||
.AddParameter("objectList", _("Object"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
@@ -1478,7 +1478,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
_("Objects"),
|
||||
"res/conditions/ajouthasard24.png",
|
||||
"res/conditions/ajouthasard.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddCodeOnlyParameter("objectsContext", "")
|
||||
.AddParameter("objectList", _("Object"))
|
||||
.MarkAsSimple();
|
||||
|
||||
@@ -1588,7 +1588,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
"Raycast",
|
||||
_("Raycast"),
|
||||
_("Sends a ray from the given source position and angle, "
|
||||
"intersecting the closest object.\nThe instersected "
|
||||
"intersecting the closest object.\nThe intersected "
|
||||
"object will become the only one taken into account.\nIf "
|
||||
"the condition is inverted, the object to be intersected "
|
||||
"will be the farthest one within the ray radius."),
|
||||
@@ -1619,7 +1619,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
"RaycastToPosition",
|
||||
_("Raycast to position"),
|
||||
_("Sends a ray from the given source position to the final point, "
|
||||
"intersecting the closest object.\nThe instersected "
|
||||
"intersecting the closest object.\nThe intersected "
|
||||
"object will become the only one taken into account.\nIf "
|
||||
"the condition is inverted, the object to be intersected "
|
||||
"will be the farthest one within the ray radius."),
|
||||
|
@@ -40,7 +40,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
"res/conditions/camera24.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.UseStandardParameters("number", ParameterOptions::MakeNewOptions())
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
|
||||
.AddParameter("layer", _("Layer"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
.AddParameter("expression", _("Camera number (default : 0)"), "", true)
|
||||
.SetDefaultValue("0")
|
||||
@@ -72,7 +72,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
"res/conditions/camera24.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.UseStandardParameters("number", ParameterOptions::MakeNewOptions())
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
|
||||
.AddParameter("layer", _("Layer"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
.AddParameter("expression", _("Camera number (default : 0)"), "", true)
|
||||
.SetDefaultValue("0")
|
||||
@@ -103,7 +103,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
"",
|
||||
"res/conditions/camera24.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
|
||||
.AddParameter("layer", _("Layer"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
.AddParameter("expression", _("Camera number"), "", true)
|
||||
.UseStandardParameters("number", ParameterOptions::MakeNewOptions())
|
||||
@@ -119,7 +119,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
"",
|
||||
"res/conditions/camera24.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
|
||||
.AddParameter("layer", _("Layer"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
.AddParameter("expression", _("Camera number"), "", true)
|
||||
.UseStandardParameters("number", ParameterOptions::MakeNewOptions())
|
||||
@@ -136,7 +136,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
"",
|
||||
"res/conditions/camera24.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
|
||||
.AddParameter("layer", _("Layer"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
.AddParameter("expression", _("Camera number"), "", true)
|
||||
.UseStandardParameters("number", ParameterOptions::MakeNewOptions())
|
||||
@@ -153,7 +153,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
"",
|
||||
"res/conditions/camera24.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
|
||||
.AddParameter("layer", _("Layer"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
.AddParameter("expression", _("Camera number"), "", true)
|
||||
.UseStandardParameters("number", ParameterOptions::MakeNewOptions())
|
||||
@@ -170,7 +170,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
"",
|
||||
"res/conditions/camera24.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
|
||||
.AddParameter("layer", _("Layer"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
.AddParameter("expression", _("Camera number"), "", true)
|
||||
.UseStandardParameters("number", ParameterOptions::MakeNewOptions())
|
||||
@@ -187,7 +187,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
"",
|
||||
"res/conditions/camera24.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
|
||||
.AddParameter("layer", _("Layer"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
.AddParameter("expression", _("Camera number"), "", true)
|
||||
.UseStandardParameters("number", ParameterOptions::MakeNewOptions())
|
||||
@@ -204,7 +204,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
"res/conditions/camera24.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.UseStandardParameters("number", ParameterOptions::MakeNewOptions())
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
|
||||
.AddParameter("layer", _("Layer"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
.AddParameter("expression", _("Camera number (default : 0)"), "", true)
|
||||
.SetDefaultValue("0")
|
||||
@@ -322,7 +322,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("expression",
|
||||
_("Value (1:Initial zoom, 2:Zoom x2, 0.5:Unzoom x2...)"))
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
|
||||
.AddParameter("layer", _("Layer"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
.AddParameter("expression", _("Camera number (default : 0)"), "", true)
|
||||
.SetDefaultValue("0");
|
||||
@@ -354,46 +354,41 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
"",
|
||||
true)
|
||||
.SetDefaultValue("yes")
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
|
||||
.AddParameter("layer", _("Layer"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
.AddParameter("expression", _("Camera number (default : 0)"), "", true)
|
||||
.SetDefaultValue("0")
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddAction(
|
||||
"ClampCamera",
|
||||
_("Enforce camera boundaries"),
|
||||
_("Enforce camera boundaries by moving the camera back inside specified boundaries."),
|
||||
_("Enforce camera boundaries (left: _PARAM1_, top: _PARAM2_ "
|
||||
"right: _PARAM3_, bottom: _PARAM4_, layer: _PARAM5_)"),
|
||||
"",
|
||||
"res/actions/camera24.png",
|
||||
"res/actions/camera.png")
|
||||
.AddAction("ClampCamera",
|
||||
_("Enforce camera boundaries"),
|
||||
_("Enforce camera boundaries by moving the camera back inside "
|
||||
"specified boundaries."),
|
||||
_("Enforce camera boundaries (left: _PARAM1_, top: _PARAM2_ "
|
||||
"right: _PARAM3_, bottom: _PARAM4_, layer: _PARAM5_)"),
|
||||
"",
|
||||
"res/actions/camera24.png",
|
||||
"res/actions/camera.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("expression",
|
||||
_("Left bound X Position"))
|
||||
.AddParameter("expression",
|
||||
_("Top bound Y Position"))
|
||||
.AddParameter("expression",
|
||||
_("Right bound X Position"))
|
||||
.AddParameter("expression",
|
||||
_("Bottom bound Y Position"))
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
|
||||
.AddParameter("expression", _("Left bound X Position"))
|
||||
.AddParameter("expression", _("Top bound Y Position"))
|
||||
.AddParameter("expression", _("Right bound X Position"))
|
||||
.AddParameter("expression", _("Bottom bound Y Position"))
|
||||
.AddParameter("layer", _("Layer"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
.AddParameter("expression", _("Camera number (default : 0)"), "", true)
|
||||
.SetDefaultValue("0")
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddAction(
|
||||
"CentreCamera",
|
||||
_("Center the camera on an object"),
|
||||
_("Center the camera on the specified object."),
|
||||
_("Center camera on _PARAM1_ (layer: _PARAM3_)"),
|
||||
"",
|
||||
"res/actions/camera24.png",
|
||||
"res/actions/camera.png")
|
||||
.AddAction("CentreCamera",
|
||||
_("Center the camera on an object"),
|
||||
_("Center the camera on the specified object."),
|
||||
_("Center camera on _PARAM1_ (layer: _PARAM3_)"),
|
||||
"",
|
||||
"res/actions/camera24.png",
|
||||
"res/actions/camera.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("objectPtr", _("Object"))
|
||||
.AddParameter("yesorno",
|
||||
@@ -401,7 +396,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
"",
|
||||
true)
|
||||
.SetDefaultValue("yes")
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
|
||||
.AddParameter("layer", _("Layer"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
.AddParameter("expression", _("Camera number (default : 0)"), "", true)
|
||||
.SetDefaultValue("0")
|
||||
@@ -458,7 +453,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
"res/actions/effect24.png",
|
||||
"res/actions/effect.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
|
||||
.AddParameter("layer", _("Layer"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
.AddParameter("layerEffectName", _("Effect name"))
|
||||
.AddParameter("layerEffectParameterName", _("Parameter name"))
|
||||
@@ -477,7 +472,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
"res/actions/effect24.png",
|
||||
"res/actions/effect.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
|
||||
.AddParameter("layer", _("Layer"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
.AddParameter("layerEffectName", _("Effect name"))
|
||||
.AddParameter("layerEffectParameterName", _("Parameter name"))
|
||||
@@ -496,7 +491,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
"res/actions/effect24.png",
|
||||
"res/actions/effect.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
|
||||
.AddParameter("layer", _("Layer"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
.AddParameter("layerEffectName", _("Effect name"))
|
||||
.AddParameter("layerEffectParameterName", _("Parameter name"))
|
||||
@@ -512,7 +507,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
"res/actions/effect24.png",
|
||||
"res/actions/effect.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
|
||||
.AddParameter("layer", _("Layer"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
.AddParameter("layerEffectName", _("Effect name"))
|
||||
.MarkAsAdvanced();
|
||||
@@ -526,7 +521,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
"res/actions/effect24.png",
|
||||
"res/actions/effect.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
|
||||
.AddParameter("layer", _("Layer"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
.AddParameter("layerEffectName", _("Effect name"))
|
||||
.AddParameter("yesorno", _("Enable"), "", true)
|
||||
@@ -542,7 +537,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
"res/conditions/time24.png",
|
||||
"res/conditions/time.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
|
||||
.AddParameter("layer", _("Layer"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
.UseStandardRelationalOperatorParameters(
|
||||
"number",
|
||||
@@ -560,7 +555,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
"res/actions/time24.png",
|
||||
"res/actions/time.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
|
||||
.AddParameter("layer", _("Layer"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
.AddParameter("expression",
|
||||
_("Scale (1: Default, 2: 2x faster, 0.5: 2x slower...)"));
|
||||
@@ -575,7 +570,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
"res/conditions/layer24.png",
|
||||
"res/conditions/layer.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
|
||||
.AddParameter("layer", _("Layer"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
.UseStandardRelationalOperatorParameters(
|
||||
"number", gd::ParameterOptions::MakeNewOptions())
|
||||
@@ -592,7 +587,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
"res/actions/layer24.png",
|
||||
"res/actions/layer.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
|
||||
.AddParameter("layer", _("Layer"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
.AddParameter("expression", _("New default Z order"));
|
||||
|
||||
@@ -607,7 +602,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
"res/actions/color24.png",
|
||||
"res/actions/color.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
|
||||
.AddParameter("layer", _("Layer"), "", true)
|
||||
.SetDefaultValue("\"Lighting\"")
|
||||
.AddParameter("color", _("Color"))
|
||||
.MarkAsAdvanced();
|
||||
|
@@ -163,7 +163,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsMouseExtension(
|
||||
"res/conditions/mouse24.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.UseStandardParameters("number", ParameterOptions::MakeNewOptions())
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
|
||||
.AddParameter("layer", _("Layer"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
.AddParameter("expression", _("Camera number (default : 0)"), "", true)
|
||||
.SetDefaultValue("0");
|
||||
@@ -185,7 +185,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsMouseExtension(
|
||||
"res/conditions/mouse24.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.UseStandardParameters("number", ParameterOptions::MakeNewOptions())
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
|
||||
.AddParameter("layer", _("Layer"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
.AddParameter("expression", _("Camera number (default : 0)"), "", true)
|
||||
.SetDefaultValue("0");
|
||||
@@ -206,7 +206,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsMouseExtension(
|
||||
"res/conditions/mouse24.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.UseStandardParameters("number", ParameterOptions::MakeNewOptions())
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
|
||||
.AddParameter("layer", _("Layer"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
.AddParameter("expression", _("Camera number (default : 0)"), "", true)
|
||||
.SetDefaultValue("0")
|
||||
@@ -223,7 +223,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsMouseExtension(
|
||||
"res/conditions/mouse24.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.UseStandardParameters("number", ParameterOptions::MakeNewOptions())
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
|
||||
.AddParameter("layer", _("Layer"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
.AddParameter("expression", _("Camera number (default : 0)"), "", true)
|
||||
.SetDefaultValue("0")
|
||||
@@ -317,7 +317,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsMouseExtension(
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("expression", _("Touch identifier"))
|
||||
.UseStandardParameters("number", ParameterOptions::MakeNewOptions())
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
|
||||
.AddParameter("layer", _("Layer"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
.AddParameter("expression", _("Camera number (default : 0)"), "", true)
|
||||
.SetDefaultValue("0");
|
||||
@@ -333,7 +333,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsMouseExtension(
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("expression", _("Touch identifier"))
|
||||
.UseStandardParameters("number", ParameterOptions::MakeNewOptions())
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
|
||||
.AddParameter("layer", _("Layer"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
.AddParameter("expression", _("Camera number (default : 0)"), "", true)
|
||||
.SetDefaultValue("0");
|
||||
|
@@ -48,7 +48,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsNetworkExtension(
|
||||
.AddParameter("string", "Content type", "", true)
|
||||
.SetParameterLongDescription(
|
||||
"If empty, \"application/x-www-form-urlencoded\" will be used.")
|
||||
.AddParameter("scenevar", "Reponse scene variable", "", true)
|
||||
.AddParameter("scenevar", "Response scene variable", "", true)
|
||||
.SetParameterLongDescription(
|
||||
"The response of the server will be stored, as a string, in this "
|
||||
"variable. If the server returns *JSON*, you may want to use the "
|
||||
|
@@ -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"),
|
||||
|
@@ -126,8 +126,8 @@ BuiltinExtensionsImplementer::ImplementsStringInstructionsExtension(
|
||||
extension
|
||||
.AddExpression(
|
||||
"StrFindLast",
|
||||
_("Search the last occurence in a text"),
|
||||
_("Search the last occurence in a string (return the position of "
|
||||
_("Search the last occurrence in a text"),
|
||||
_("Search the last occurrence in a string (return the position of "
|
||||
"the result, from the beginning of the string, or -1 if not "
|
||||
"found)"),
|
||||
"",
|
||||
@@ -169,8 +169,8 @@ BuiltinExtensionsImplementer::ImplementsStringInstructionsExtension(
|
||||
extension
|
||||
.AddExpression(
|
||||
"StrFindLastFrom",
|
||||
_("Search the last occurence in a text, starting from a position"),
|
||||
_("Search in a text the last occurence, starting from a position "
|
||||
_("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 "
|
||||
"-1 if not found)"),
|
||||
|
@@ -62,7 +62,7 @@ class GD_CORE_API DependencyMetadata {
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Sets the type of dependecy (what will be used to install it)
|
||||
* \brief Sets the type of dependency (what will be used to install it)
|
||||
*
|
||||
* This can either be "npm" or "cordova" for now.
|
||||
*/
|
||||
|
@@ -7,9 +7,6 @@
|
||||
|
||||
namespace gd {
|
||||
|
||||
EffectMetadata::EffectMetadata(const gd::String& type_)
|
||||
: type(type_), isMarkedAsNotWorkingForObjects(false) {}
|
||||
|
||||
EffectMetadata& EffectMetadata::SetIncludeFile(const gd::String& includeFile) {
|
||||
includeFiles.clear();
|
||||
includeFiles.push_back(includeFile);
|
||||
@@ -23,9 +20,4 @@ EffectMetadata& EffectMetadata::AddIncludeFile(const gd::String& includeFile) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
EffectMetadata& EffectMetadata::MarkAsNotWorkingForObjects() {
|
||||
isMarkedAsNotWorkingForObjects = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -3,8 +3,8 @@
|
||||
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef EFFECTMETADATA_H
|
||||
#define EFFECTMETADATA_H
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
@@ -25,21 +25,25 @@ class GD_CORE_API EffectMetadata {
|
||||
/**
|
||||
* \brief Construct an effect metadata, with the given type
|
||||
*/
|
||||
EffectMetadata(const gd::String& type_);
|
||||
EffectMetadata(const gd::String &type_)
|
||||
: type(type_), isMarkedAsNotWorkingForObjects(false),
|
||||
isMarkedAsOnlyWorkingFor2D(false), isMarkedAsOnlyWorkingFor3D(false),
|
||||
isMarkedAsUnique(false) {}
|
||||
|
||||
/**
|
||||
* \brief Default constructor, only used for initializing `badEffectMetadata`.
|
||||
*/
|
||||
EffectMetadata() {}
|
||||
/**
|
||||
* \brief Default constructor, only used for initializing
|
||||
* `badEffectMetadata`.
|
||||
*/
|
||||
EffectMetadata() {}
|
||||
|
||||
virtual ~EffectMetadata(){};
|
||||
virtual ~EffectMetadata(){};
|
||||
|
||||
/**
|
||||
* \brief Set the name shown to the user.
|
||||
*/
|
||||
EffectMetadata& SetFullName(const gd::String& fullname_) {
|
||||
fullname = fullname_;
|
||||
return *this;
|
||||
/**
|
||||
* \brief Set the name shown to the user.
|
||||
*/
|
||||
EffectMetadata &SetFullName(const gd::String &fullname_) {
|
||||
fullname = fullname_;
|
||||
return *this;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -69,11 +73,6 @@ class GD_CORE_API EffectMetadata {
|
||||
*/
|
||||
EffectMetadata& AddIncludeFile(const gd::String& includeFile);
|
||||
|
||||
/**
|
||||
* \brief Mark the effect as not working as an object effect.
|
||||
*/
|
||||
EffectMetadata& MarkAsNotWorkingForObjects();
|
||||
|
||||
/**
|
||||
* \brief Return a reference to the properties of this effect.
|
||||
*/
|
||||
@@ -117,10 +116,65 @@ class GD_CORE_API EffectMetadata {
|
||||
return includeFiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Mark the effect as not working as an object effect.
|
||||
*/
|
||||
EffectMetadata& MarkAsNotWorkingForObjects() {
|
||||
isMarkedAsNotWorkingForObjects = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Mark the effect as only working for the 2D renderer.
|
||||
*/
|
||||
EffectMetadata& MarkAsOnlyWorkingFor2D() {
|
||||
isMarkedAsOnlyWorkingFor2D = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Mark the effect as only working for the 3D renderer.
|
||||
*/
|
||||
EffectMetadata& MarkAsOnlyWorkingFor3D() {
|
||||
isMarkedAsOnlyWorkingFor3D = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Mark the effect as only addable once.
|
||||
*/
|
||||
EffectMetadata& MarkAsUnique() {
|
||||
isMarkedAsUnique = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Check if the effect is marked as not working as an object effect.
|
||||
*/
|
||||
bool IsMarkedAsNotWorkingForObjects() const { return isMarkedAsNotWorkingForObjects; };
|
||||
bool IsMarkedAsNotWorkingForObjects() const {
|
||||
return isMarkedAsNotWorkingForObjects;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Check if the effect is marked as only working for the 2D renderer.
|
||||
*/
|
||||
bool IsMarkedAsOnlyWorkingFor2D() const {
|
||||
return isMarkedAsOnlyWorkingFor2D;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Check if the effect is marked as only working for the 3D renderer.
|
||||
*/
|
||||
bool IsMarkedAsOnlyWorkingFor3D() const {
|
||||
return isMarkedAsOnlyWorkingFor3D;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Check if the effect can only be added once.
|
||||
*/
|
||||
bool IsMarkedAsUnique() const {
|
||||
return isMarkedAsUnique;
|
||||
};
|
||||
|
||||
private:
|
||||
gd::String extensionNamespace;
|
||||
@@ -130,8 +184,10 @@ class GD_CORE_API EffectMetadata {
|
||||
gd::String description;
|
||||
std::vector<gd::String> includeFiles;
|
||||
bool isMarkedAsNotWorkingForObjects;
|
||||
bool isMarkedAsOnlyWorkingFor2D;
|
||||
bool isMarkedAsOnlyWorkingFor3D;
|
||||
bool isMarkedAsUnique;
|
||||
std::map<gd::String, gd::PropertyDescriptor> properties;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
#endif // EFFECTMETADATA_H
|
||||
|
@@ -57,7 +57,7 @@ class GD_CORE_API ObjectMetadata {
|
||||
|
||||
/**
|
||||
* \brief Construct an object metadata, with a function that will be called
|
||||
* to instanciate a new object.
|
||||
* to instantiate a new object.
|
||||
*/
|
||||
ObjectMetadata(const gd::String& extensionNamespace_,
|
||||
const gd::String& name_,
|
||||
@@ -224,7 +224,7 @@ class GD_CORE_API ObjectMetadata {
|
||||
/**
|
||||
* \brief The "capabilities" that are offered by the base object that are
|
||||
* *not* supported by this object, and should be hidden in the editor
|
||||
* inferface.
|
||||
* interface.
|
||||
*/
|
||||
const std::set<gd::String>& GetUnsupportedBaseObjectCapabilities() const {
|
||||
return unsupportedBaseObjectCapabilities;
|
||||
@@ -232,7 +232,7 @@ class GD_CORE_API ObjectMetadata {
|
||||
|
||||
/**
|
||||
* \brief Add a "capability" that is offered by the base object that is *not*
|
||||
* supported by this object, and should be hidden in the editor inferface.
|
||||
* supported by this object, and should be hidden in the editor interface.
|
||||
*/
|
||||
ObjectMetadata& AddUnsupportedBaseObjectCapability(
|
||||
const gd::String& capability) {
|
||||
@@ -242,7 +242,7 @@ class GD_CORE_API ObjectMetadata {
|
||||
|
||||
/**
|
||||
* \brief Check if a "capability" that is offered by the base object is *not*
|
||||
* supported by this object, and should be hidden in the editor inferface.
|
||||
* supported by this object, and should be hidden in the editor interface.
|
||||
*/
|
||||
bool IsUnsupportedBaseObjectCapability(const gd::String& capability) const {
|
||||
return unsupportedBaseObjectCapabilities.find(capability) != unsupportedBaseObjectCapabilities.end();
|
||||
|
@@ -209,10 +209,10 @@ class GD_CORE_API ParameterMetadata {
|
||||
* \brief Return the expression type from the parameter type.
|
||||
* Declinations of "number" and "string" types (like "forceMultiplier" or
|
||||
* "sceneName") are replaced by "number" and "string".
|
||||
* \deprecated Use gd::ValueTypeMetadata instead.
|
||||
* \deprecated Use gd::ValueTypeMetadata or gd::GetExpressionPrimitiveValueType instead.
|
||||
*/
|
||||
static const gd::String &GetExpressionValueType(const gd::String ¶meterType) {
|
||||
return gd::ValueTypeMetadata::GetPrimitiveValueType(parameterType);
|
||||
return gd::ValueTypeMetadata::GetExpressionPrimitiveValueType(parameterType);
|
||||
}
|
||||
|
||||
/** \name Serialization
|
||||
|
@@ -11,6 +11,8 @@
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/String.h"
|
||||
#include "InstructionMetadata.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodePrinter.h"
|
||||
|
||||
namespace gd {
|
||||
void ParameterMetadataTools::ParametersToObjectsContainer(
|
||||
@@ -101,6 +103,56 @@ void ParameterMetadataTools::IterateOverParametersWithIndex(
|
||||
}
|
||||
}
|
||||
|
||||
void ParameterMetadataTools::IterateOverParametersWithIndex(
|
||||
const gd::Platform &platform,
|
||||
const gd::ObjectsContainer &globalObjectsContainer,
|
||||
const gd::ObjectsContainer &objectsContainer, FunctionCallNode &node,
|
||||
std::function<void(const gd::ParameterMetadata ¶meterMetadata,
|
||||
std::unique_ptr<gd::ExpressionNode> ¶meterNode,
|
||||
size_t parameterIndex, const gd::String &lastObjectName)>
|
||||
fn) {
|
||||
gd::String lastObjectName = node.objectName;
|
||||
|
||||
const bool isObjectFunction = !node.objectName.empty();
|
||||
const gd::ExpressionMetadata &metadata =
|
||||
isObjectFunction ? MetadataProvider::GetObjectAnyExpressionMetadata(
|
||||
platform,
|
||||
GetTypeOfObject(globalObjectsContainer,
|
||||
objectsContainer, node.objectName),
|
||||
node.functionName)
|
||||
: MetadataProvider::GetAnyExpressionMetadata(
|
||||
platform, node.functionName);
|
||||
|
||||
if (gd::MetadataProvider::IsBadExpressionMetadata(metadata)) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t parameterIndex = 0;
|
||||
for (size_t metadataIndex = (isObjectFunction ? 1 : 0);
|
||||
metadataIndex < metadata.parameters.size() &&
|
||||
parameterIndex < node.parameters.size();
|
||||
++metadataIndex) {
|
||||
auto ¶meterMetadata = metadata.parameters[metadataIndex];
|
||||
if (parameterMetadata.IsCodeOnly()) {
|
||||
continue;
|
||||
}
|
||||
auto ¶meterNode = node.parameters[parameterIndex];
|
||||
++parameterIndex;
|
||||
|
||||
fn(parameterMetadata, parameterNode, parameterIndex, lastObjectName);
|
||||
|
||||
// Memorize the last object name. By convention, parameters that require
|
||||
// an object (mainly, "objectvar" and "behavior") should be placed after
|
||||
// the object in the list of parameters (if possible, just after).
|
||||
// Search "lastObjectName" in the codebase for other place where this
|
||||
// convention is enforced.
|
||||
if (gd::ParameterMetadata::IsObject(parameterMetadata.GetType()))
|
||||
// Object can't be expressions so it should always be the object name.
|
||||
lastObjectName =
|
||||
gd::ExpressionParser2NodePrinter::PrintNode(*parameterNode);
|
||||
}
|
||||
}
|
||||
|
||||
size_t ParameterMetadataTools::GetObjectParameterIndexFor(
|
||||
const std::vector<gd::ParameterMetadata>& parametersMetadata,
|
||||
size_t parameterIndex) {
|
||||
|
@@ -7,12 +7,16 @@
|
||||
#ifndef ParameterMetadataTools_H
|
||||
#define ParameterMetadataTools_H
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include "GDCore/String.h"
|
||||
namespace gd {
|
||||
class Platform;
|
||||
class Project;
|
||||
class ObjectsContainer;
|
||||
class ParameterMetadata;
|
||||
class Expression;
|
||||
struct FunctionCallNode;
|
||||
struct ExpressionNode;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
@@ -48,6 +52,21 @@ class GD_CORE_API ParameterMetadataTools {
|
||||
size_t parameterIndex,
|
||||
const gd::String& lastObjectName)> fn);
|
||||
|
||||
/**
|
||||
* Iterate over the parameters of a FunctionCallNode.
|
||||
* Callback function is called with the parameter metadata, its value
|
||||
* and if applicable the name of the object it's linked to.
|
||||
*/
|
||||
static void IterateOverParametersWithIndex(
|
||||
const gd::Platform &platform,
|
||||
const gd::ObjectsContainer &globalObjectsContainer,
|
||||
const gd::ObjectsContainer &objectsContainer, FunctionCallNode &node,
|
||||
std::function<void(const gd::ParameterMetadata ¶meterMetadata,
|
||||
std::unique_ptr<gd::ExpressionNode> ¶meterNode,
|
||||
size_t parameterIndex,
|
||||
const gd::String &lastObjectName)>
|
||||
fn);
|
||||
|
||||
/**
|
||||
* Given a parameter, return, if applicable, the index of the object parameter
|
||||
* it's linked to.
|
||||
|
@@ -35,17 +35,40 @@ void ValueTypeMetadata::UnserializeFrom(const SerializerElement& element) {
|
||||
|
||||
const gd::String ValueTypeMetadata::numberType = "number";
|
||||
const gd::String ValueTypeMetadata::stringType = "string";
|
||||
const gd::String ValueTypeMetadata::variableType = "variable";
|
||||
const gd::String ValueTypeMetadata::booleanType = "boolean";
|
||||
|
||||
const gd::String &ValueTypeMetadata::GetPrimitiveValueType(const gd::String ¶meterType) {
|
||||
if (parameterType == "number" || gd::ValueTypeMetadata::IsTypeExpression("number", parameterType)) {
|
||||
const gd::String &ValueTypeMetadata::GetExpressionPrimitiveValueType(
|
||||
const gd::String ¶meterType) {
|
||||
if (parameterType == "number" ||
|
||||
gd::ValueTypeMetadata::IsTypeExpression("number", parameterType)) {
|
||||
return ValueTypeMetadata::numberType;
|
||||
}
|
||||
if (parameterType == "string" || gd::ValueTypeMetadata::IsTypeExpression("string", parameterType)) {
|
||||
if (parameterType == "string" ||
|
||||
gd::ValueTypeMetadata::IsTypeExpression("string", parameterType)) {
|
||||
return ValueTypeMetadata::stringType;
|
||||
}
|
||||
return parameterType;
|
||||
}
|
||||
|
||||
const gd::String &
|
||||
ValueTypeMetadata::GetPrimitiveValueType(const gd::String ¶meterType) {
|
||||
if (parameterType == "variable" ||
|
||||
gd::ValueTypeMetadata::IsTypeExpression("variable", parameterType)) {
|
||||
return ValueTypeMetadata::variableType;
|
||||
}
|
||||
if (parameterType == "boolean" || parameterType == "yesorno" ||
|
||||
parameterType == "trueorfalse") {
|
||||
return ValueTypeMetadata::booleanType;
|
||||
}
|
||||
// These 2 types are not strings from the code generator point of view,
|
||||
// but it is for event-based extensions.
|
||||
if (parameterType == "key" || parameterType == "mouse") {
|
||||
return ValueTypeMetadata::stringType;
|
||||
}
|
||||
return GetExpressionPrimitiveValueType(parameterType);
|
||||
}
|
||||
|
||||
const gd::String ValueTypeMetadata::numberValueType = "number";
|
||||
const gd::String ValueTypeMetadata::booleanValueType = "boolean";
|
||||
const gd::String ValueTypeMetadata::colorValueType = "color";
|
||||
|
@@ -163,7 +163,6 @@ class GD_CORE_API ValueTypeMetadata {
|
||||
} else if (type == "string") {
|
||||
return parameterType == "string" || parameterType == "layer" ||
|
||||
parameterType == "color" || parameterType == "file" ||
|
||||
parameterType == "joyaxis" ||
|
||||
parameterType == "stringWithSelector" ||
|
||||
parameterType == "sceneName" ||
|
||||
parameterType == "layerEffectName" ||
|
||||
@@ -179,6 +178,16 @@ class GD_CORE_API ValueTypeMetadata {
|
||||
} else if (type == "variable") {
|
||||
return parameterType == "objectvar" || parameterType == "globalvar" ||
|
||||
parameterType == "scenevar";
|
||||
} else if (type == "resource") {
|
||||
return parameterType == "fontResource" ||
|
||||
parameterType == "soundfile" ||
|
||||
parameterType == "musicfile" ||
|
||||
parameterType == "bitmapFontResource" ||
|
||||
parameterType == "imageResource" ||
|
||||
parameterType == "jsonResource" ||
|
||||
parameterType == "tilemapResource" ||
|
||||
parameterType == "tilesetResource" ||
|
||||
parameterType == "model3DResource";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -187,10 +196,23 @@ class GD_CORE_API ValueTypeMetadata {
|
||||
* \brief Return the expression type from the parameter type.
|
||||
* Declinations of "number" and "string" types (like "forceMultiplier" or
|
||||
* "sceneName") are replaced by "number" and "string".
|
||||
*
|
||||
* \note It only maps string and number types.
|
||||
*/
|
||||
static const gd::String &GetExpressionPrimitiveValueType(const gd::String ¶meterType);
|
||||
|
||||
/**
|
||||
* \brief Return the primitive type from the parameter type.
|
||||
* Declinations of "number" and "string" types (like "forceMultiplier" or
|
||||
* "sceneName") are replaced by "number" and "string".
|
||||
*
|
||||
* \note It also maps variable and boolean types.
|
||||
*/
|
||||
static const gd::String &GetPrimitiveValueType(const gd::String ¶meterType);
|
||||
static const gd::String numberType;
|
||||
static const gd::String stringType;
|
||||
static const gd::String variableType;
|
||||
static const gd::String booleanType;
|
||||
|
||||
/**
|
||||
* \brief Return the ValueTypeMetadata name for a property type.
|
||||
|
@@ -42,7 +42,7 @@ class GD_CORE_API DependenciesAnalyzer {
|
||||
*
|
||||
* You can also call then
|
||||
* DependenciesAnalyzer::ExternalEventsCanBeCompiledForAScene to check if the
|
||||
* external events can be compiled separatly and called by a scene. \see
|
||||
* external events can be compiled separately and called by a scene. \see
|
||||
* DependenciesAnalyzer::ExternalEventsCanBeCompiledForAScene
|
||||
*/
|
||||
DependenciesAnalyzer(const gd::Project& project_,
|
||||
|
@@ -23,7 +23,7 @@ void ArbitraryEventsWorker::VisitEventList(gd::EventsList& events) {
|
||||
DoVisitEventList(events);
|
||||
|
||||
for (std::size_t i = 0; i < events.size();) {
|
||||
if (VisitEvent(events[i]))
|
||||
if (events[i].AcceptVisitor(*this))
|
||||
events.RemoveEvent(i);
|
||||
else {
|
||||
if (events[i].CanHaveSubEvents())
|
||||
@@ -50,6 +50,10 @@ bool ArbitraryEventsWorker::VisitEvent(gd::BaseEvent& event) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ArbitraryEventsWorker::VisitLinkEvent(gd::LinkEvent& linkEvent) {
|
||||
return DoVisitLinkEvent(linkEvent);
|
||||
}
|
||||
|
||||
void ArbitraryEventsWorker::VisitInstructionList(
|
||||
gd::InstructionsList& instructions, bool areConditions) {
|
||||
DoVisitInstructionList(instructions, areConditions);
|
||||
@@ -80,7 +84,7 @@ void ReadOnlyArbitraryEventsWorker::VisitEventList(const gd::EventsList& events)
|
||||
DoVisitEventList(events);
|
||||
|
||||
for (std::size_t i = 0; i < events.size(); ++i) {
|
||||
VisitEvent(events[i]);
|
||||
events[i].AcceptVisitor(*this);
|
||||
|
||||
if (events[i].CanHaveSubEvents()) {
|
||||
VisitEventList(events[i].GetSubEvents());
|
||||
@@ -103,6 +107,10 @@ void ReadOnlyArbitraryEventsWorker::VisitEvent(const gd::BaseEvent& event) {
|
||||
}
|
||||
}
|
||||
|
||||
void ReadOnlyArbitraryEventsWorker::VisitLinkEvent(const gd::LinkEvent& linkEvent) {
|
||||
DoVisitLinkEvent(linkEvent);
|
||||
}
|
||||
|
||||
void ReadOnlyArbitraryEventsWorker::VisitInstructionList(
|
||||
const gd::InstructionsList& instructions, bool areConditions) {
|
||||
DoVisitInstructionList(instructions, areConditions);
|
||||
|
@@ -9,10 +9,12 @@
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include "GDCore/Events/InstructionsList.h"
|
||||
#include "GDCore/Events/EventVisitor.h"
|
||||
#include "GDCore/String.h"
|
||||
namespace gd {
|
||||
class Instruction;
|
||||
class BaseEvent;
|
||||
class LinkEvent;
|
||||
class EventsList;
|
||||
class ObjectsContainer;
|
||||
} // namespace gd
|
||||
@@ -28,7 +30,7 @@ namespace gd {
|
||||
*
|
||||
* \ingroup IDE
|
||||
*/
|
||||
class GD_CORE_API ArbitraryEventsWorker {
|
||||
class GD_CORE_API ArbitraryEventsWorker : private EventVisitor {
|
||||
public:
|
||||
ArbitraryEventsWorker(){};
|
||||
virtual ~ArbitraryEventsWorker();
|
||||
@@ -40,7 +42,8 @@ class GD_CORE_API ArbitraryEventsWorker {
|
||||
|
||||
private:
|
||||
void VisitEventList(gd::EventsList& events);
|
||||
bool VisitEvent(gd::BaseEvent& event);
|
||||
bool VisitEvent(gd::BaseEvent& event) override;
|
||||
bool VisitLinkEvent(gd::LinkEvent& linkEvent) override;
|
||||
void VisitInstructionList(gd::InstructionsList& instructions,
|
||||
bool areConditions);
|
||||
bool VisitInstruction(gd::Instruction& instruction, bool isCondition);
|
||||
@@ -52,11 +55,21 @@ class GD_CORE_API ArbitraryEventsWorker {
|
||||
|
||||
/**
|
||||
* Called to do some work on an event
|
||||
* \return true if the instruction must be deleted from the events list, false
|
||||
* \return true if the event must be deleted from the events list, false
|
||||
* otherwise (default).
|
||||
*/
|
||||
virtual bool DoVisitEvent(gd::BaseEvent& event) { return false; };
|
||||
|
||||
/**
|
||||
* Called to do some work on a link event.
|
||||
*
|
||||
* Note that DoVisitEvent is also called with this event.
|
||||
*
|
||||
* \return true if the event must be deleted from the events list, false
|
||||
* otherwise (default).
|
||||
*/
|
||||
virtual bool DoVisitLinkEvent(gd::LinkEvent& event) { return false; };
|
||||
|
||||
/**
|
||||
* Called to do some work on an instruction list
|
||||
*/
|
||||
@@ -129,7 +142,7 @@ class GD_CORE_API ArbitraryEventsWorkerWithContext
|
||||
*
|
||||
* \ingroup IDE
|
||||
*/
|
||||
class GD_CORE_API ReadOnlyArbitraryEventsWorker {
|
||||
class GD_CORE_API ReadOnlyArbitraryEventsWorker : private ReadOnlyEventVisitor {
|
||||
public:
|
||||
ReadOnlyArbitraryEventsWorker(){};
|
||||
virtual ~ReadOnlyArbitraryEventsWorker();
|
||||
@@ -141,7 +154,8 @@ class GD_CORE_API ReadOnlyArbitraryEventsWorker {
|
||||
|
||||
private:
|
||||
void VisitEventList(const gd::EventsList& events);
|
||||
void VisitEvent(const gd::BaseEvent& event);
|
||||
void VisitEvent(const gd::BaseEvent& event) override;
|
||||
void VisitLinkEvent(const gd::LinkEvent& linkEvent) override;
|
||||
void VisitInstructionList(const gd::InstructionsList& instructions,
|
||||
bool areConditions);
|
||||
void VisitInstruction(const gd::Instruction& instruction, bool isCondition);
|
||||
@@ -156,6 +170,13 @@ class GD_CORE_API ReadOnlyArbitraryEventsWorker {
|
||||
*/
|
||||
virtual void DoVisitEvent(const gd::BaseEvent& event) {};
|
||||
|
||||
/**
|
||||
* Called to do some work on a link event.
|
||||
*
|
||||
* Note that DoVisitEvent is also called with this event.
|
||||
*/
|
||||
virtual void DoVisitLinkEvent(const gd::LinkEvent& linkEvent) {};
|
||||
|
||||
/**
|
||||
* Called to do some work on an instruction list
|
||||
*/
|
||||
|
@@ -77,24 +77,42 @@ ExpressionValidator::Type ExpressionValidator::ValidateFunction(const gd::Functi
|
||||
MetadataProvider::GetBehaviorAnyExpressionMetadata(
|
||||
platform, behaviorType, function.functionName);
|
||||
|
||||
if (!function.objectName.empty()) {
|
||||
// If the function needs a capability on the object that may not be covered
|
||||
// by all objects, check it now.
|
||||
if (!metadata.GetRequiredBaseObjectCapability().empty()) {
|
||||
const gd::ObjectMetadata &objectMetadata =
|
||||
MetadataProvider::GetObjectMetadata(platform, objectType);
|
||||
Type returnType = StringToType(metadata.GetReturnType());
|
||||
|
||||
if (objectMetadata.IsUnsupportedBaseObjectCapability(
|
||||
metadata.GetRequiredBaseObjectCapability())) {
|
||||
RaiseTypeError(
|
||||
_("This expression exists, but it can't be used on this object."),
|
||||
function.objectNameLocation);
|
||||
return StringToType(metadata.GetReturnType());
|
||||
}
|
||||
}
|
||||
if (!function.objectName.empty() &&
|
||||
!globalObjectsContainer.HasObjectNamed(function.objectName) &&
|
||||
!globalObjectsContainer.GetObjectGroups().Has(function.objectName) &&
|
||||
!objectsContainer.HasObjectNamed(function.objectName) &&
|
||||
!objectsContainer.GetObjectGroups().Has(function.objectName)) {
|
||||
RaiseTypeError(_("This object doesn't exist."),
|
||||
function.objectNameLocation, /*isFatal=*/false);
|
||||
return returnType;
|
||||
}
|
||||
|
||||
Type returnType = StringToType(metadata.GetReturnType());
|
||||
if (!function.behaviorName.empty() &&
|
||||
!gd::HasBehaviorInObjectOrGroup(globalObjectsContainer, objectsContainer,
|
||||
function.objectName,
|
||||
function.behaviorName)) {
|
||||
RaiseTypeError(_("This behavior is not attached to this object."),
|
||||
function.behaviorNameLocation, /*isFatal=*/false);
|
||||
return returnType;
|
||||
}
|
||||
|
||||
if (!function.objectName.empty() &&
|
||||
// If the function needs a capability on the object that may not be covered
|
||||
// by all objects, check it now.
|
||||
!metadata.GetRequiredBaseObjectCapability().empty()) {
|
||||
const gd::ObjectMetadata &objectMetadata =
|
||||
MetadataProvider::GetObjectMetadata(platform, objectType);
|
||||
|
||||
if (objectMetadata.IsUnsupportedBaseObjectCapability(
|
||||
metadata.GetRequiredBaseObjectCapability())) {
|
||||
RaiseTypeError(
|
||||
_("This expression exists, but it can't be used on this object."),
|
||||
function.objectNameLocation);
|
||||
return returnType;
|
||||
}
|
||||
}
|
||||
|
||||
if (gd::MetadataProvider::IsBadExpressionMetadata(metadata)) {
|
||||
RaiseError(
|
||||
@@ -115,8 +133,8 @@ ExpressionValidator::Type ExpressionValidator::ValidateFunction(const gd::Functi
|
||||
"number to a string."),
|
||||
function.location);
|
||||
return returnType;
|
||||
}
|
||||
else if (parentType != Type::Number && parentType != Type::NumberOrString) {
|
||||
} else if (parentType != Type::Number &&
|
||||
parentType != Type::NumberOrString) {
|
||||
RaiseTypeError(_("You tried to use an expression that returns a "
|
||||
"number, but another type is expected:") +
|
||||
" " + TypeToString(parentType),
|
||||
@@ -131,8 +149,8 @@ ExpressionValidator::Type ExpressionValidator::ValidateFunction(const gd::Functi
|
||||
"string to a number."),
|
||||
function.location);
|
||||
return returnType;
|
||||
}
|
||||
else if (parentType != Type::String && parentType != Type::NumberOrString) {
|
||||
} else if (parentType != Type::String &&
|
||||
parentType != Type::NumberOrString) {
|
||||
RaiseTypeError(_("You tried to use an expression that returns a "
|
||||
"string, but another type is expected:") +
|
||||
" " + TypeToString(parentType),
|
||||
@@ -172,8 +190,7 @@ ExpressionValidator::Type ExpressionValidator::ValidateFunction(const gd::Functi
|
||||
_("You have not entered enough parameters for the expression.") + " " +
|
||||
expectedCountMessage,
|
||||
function.location);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
RaiseError(
|
||||
"extra_parameter",
|
||||
_("This parameter was not expected by this expression. Remove it "
|
||||
@@ -217,8 +234,7 @@ ExpressionValidator::Type ExpressionValidator::ValidateFunction(const gd::Functi
|
||||
"parameter."),
|
||||
parameter->location);
|
||||
}
|
||||
}
|
||||
else if (gd::ParameterMetadata::IsObject(expectedParameterType)) {
|
||||
} else if (gd::ParameterMetadata::IsObject(expectedParameterType)) {
|
||||
if (dynamic_cast<IdentifierNode *>(parameter.get()) == nullptr) {
|
||||
RaiseError(
|
||||
"malformed_object_parameter",
|
||||
|
@@ -45,7 +45,7 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
|
||||
/**
|
||||
* \brief Helper function to check if a given node does not contain
|
||||
* any error.
|
||||
* any error including non-fatal ones.
|
||||
*/
|
||||
static bool HasNoErrors(const gd::Platform &platform,
|
||||
const gd::ObjectsContainer &globalObjectsContainer,
|
||||
@@ -54,16 +54,25 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
gd::ExpressionNode& node) {
|
||||
gd::ExpressionValidator validator(platform, globalObjectsContainer, objectsContainer, rootType);
|
||||
node.Visit(validator);
|
||||
return validator.GetErrors().empty();
|
||||
return validator.GetAllErrors().empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get only the fatal errors
|
||||
*
|
||||
* Expressions with fatal error can't be generated.
|
||||
*/
|
||||
const std::vector<ExpressionParserDiagnostic*>& GetFatalErrors() {
|
||||
return fatalErrors;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Get all the errors
|
||||
*
|
||||
* No errors means that the expression is valid.
|
||||
*/
|
||||
const std::vector<ExpressionParserDiagnostic*>& GetErrors() {
|
||||
return errors;
|
||||
const std::vector<ExpressionParserDiagnostic*>& GetAllErrors() {
|
||||
return allErrors;
|
||||
};
|
||||
|
||||
protected:
|
||||
@@ -150,12 +159,29 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
void OnVisitNumberNode(NumberNode& node) override {
|
||||
ReportAnyError(node);
|
||||
childType = Type::Number;
|
||||
CheckType(parentType, childType, node.location);
|
||||
if (parentType == Type::String) {
|
||||
RaiseTypeError(
|
||||
_("You entered a number, but a text was expected (in quotes)."),
|
||||
node.location);
|
||||
} else if (parentType != Type::Number &&
|
||||
parentType != Type::NumberOrString) {
|
||||
RaiseTypeError(_("You entered a number, but this type was expected:") +
|
||||
" " + TypeToString(parentType),
|
||||
node.location);
|
||||
}
|
||||
}
|
||||
void OnVisitTextNode(TextNode& node) override {
|
||||
ReportAnyError(node);
|
||||
childType = Type::String;
|
||||
CheckType(parentType, childType, node.location);
|
||||
if (parentType == Type::Number) {
|
||||
RaiseTypeError(_("You entered a text, but a number was expected."),
|
||||
node.location);
|
||||
} else if (parentType != Type::String &&
|
||||
parentType != Type::NumberOrString) {
|
||||
RaiseTypeError(_("You entered a text, but this type was expected:") +
|
||||
" " + TypeToString(parentType),
|
||||
node.location);
|
||||
}
|
||||
}
|
||||
void OnVisitVariableNode(VariableNode& node) override {
|
||||
ReportAnyError(node);
|
||||
@@ -163,7 +189,21 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
node.child->Visit(*this);
|
||||
}
|
||||
childType = Type::Variable;
|
||||
CheckType(parentType, childType, node.location);
|
||||
if (parentType == Type::String) {
|
||||
RaiseTypeError(_("Variables must be surrounded by VariableString()."),
|
||||
node.location);
|
||||
} else if (parentType == Type::Number) {
|
||||
RaiseTypeError(_("Variables must be surrounded by Variable()."),
|
||||
node.location);
|
||||
} else if (parentType == Type::NumberOrString) {
|
||||
RaiseTypeError(
|
||||
_("Variables must be surrounded by Variable() or VariableString()."),
|
||||
node.location);
|
||||
} else if (parentType != Type::Variable) {
|
||||
RaiseTypeError(_("You entered a variable, but this type was expected:") +
|
||||
" " + TypeToString(parentType),
|
||||
node.location);
|
||||
}
|
||||
}
|
||||
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {
|
||||
ReportAnyError(node);
|
||||
@@ -239,20 +279,26 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
enum Type {Unknown = 0, Number, String, NumberOrString, Variable, Object, Empty};
|
||||
Type ValidateFunction(const gd::FunctionCallNode& function);
|
||||
|
||||
void ReportAnyError(const ExpressionNode& node) {
|
||||
void ReportAnyError(const ExpressionNode& node, bool isFatal = true) {
|
||||
if (node.diagnostic && node.diagnostic->IsError()) {
|
||||
// Syntax errors are holden by the AST nodes.
|
||||
// It's fine to give pointers on them as the AST live longer than errors
|
||||
// handling.
|
||||
errors.push_back(node.diagnostic.get());
|
||||
allErrors.push_back(node.diagnostic.get());
|
||||
if (isFatal) {
|
||||
fatalErrors.push_back(node.diagnostic.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RaiseError(const gd::String &type,
|
||||
const gd::String &message, const ExpressionParserLocation &location) {
|
||||
const gd::String &message, const ExpressionParserLocation &location, bool isFatal = true) {
|
||||
auto diagnostic = gd::make_unique<ExpressionParserError>(
|
||||
type, message, location);
|
||||
errors.push_back(diagnostic.get());
|
||||
allErrors.push_back(diagnostic.get());
|
||||
if (isFatal) {
|
||||
fatalErrors.push_back(diagnostic.get());
|
||||
}
|
||||
// Errors found by the validator are not holden by the AST nodes.
|
||||
// They must be owned by the validator to keep living while errors are
|
||||
// handled by the caller.
|
||||
@@ -260,8 +306,8 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
}
|
||||
|
||||
void RaiseTypeError(
|
||||
const gd::String &message, const ExpressionParserLocation &location) {
|
||||
RaiseError("type_error", message, location);
|
||||
const gd::String &message, const ExpressionParserLocation &location, bool isFatal = true) {
|
||||
RaiseError("type_error", message, location, isFatal);
|
||||
}
|
||||
|
||||
void RaiseOperatorError(
|
||||
@@ -269,32 +315,6 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
RaiseError("invalid_operator", message, location);
|
||||
}
|
||||
|
||||
void CheckType(Type expect, Type actual, const ExpressionParserLocation &location) {
|
||||
if (actual == Type::String) {
|
||||
if (expect == Type::Number) {
|
||||
RaiseTypeError(_("You entered a text, but a number was expected."),
|
||||
location);
|
||||
}
|
||||
else if (expect != Type::String && expect != Type::NumberOrString) {
|
||||
RaiseTypeError(
|
||||
_("You entered a text, but this type was expected:") + " " + TypeToString(expect),
|
||||
location);
|
||||
}
|
||||
}
|
||||
else if (actual == Type::Number) {
|
||||
if (expect == Type::String) {
|
||||
RaiseTypeError(
|
||||
_("You entered a number, but a text was expected (in quotes)."),
|
||||
location);
|
||||
}
|
||||
else if (expect != Type::Number && expect != Type::NumberOrString) {
|
||||
RaiseTypeError(
|
||||
_("You entered a number, but this type was expected:") + " " + TypeToString(expect),
|
||||
location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static Type StringToType(const gd::String &type);
|
||||
static const gd::String &TypeToString(Type type);
|
||||
static const gd::String unknownTypeString;
|
||||
@@ -306,7 +326,8 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
static const gd::String identifierTypeString;
|
||||
static const gd::String emptyTypeString;
|
||||
|
||||
std::vector<ExpressionParserDiagnostic*> errors;
|
||||
std::vector<ExpressionParserDiagnostic*> fatalErrors;
|
||||
std::vector<ExpressionParserDiagnostic*> allErrors;
|
||||
std::vector<std::unique_ptr<ExpressionParserDiagnostic>> supplementalErrors;
|
||||
Type childType;
|
||||
Type parentType;
|
||||
|
33
Core/GDCore/IDE/Events/LinkEventTargetRenamer.cpp
Normal file
33
Core/GDCore/IDE/Events/LinkEventTargetRenamer.cpp
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "LinkEventTargetRenamer.h"
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/Events/Builtin/LinkEvent.h"
|
||||
#include "GDCore/Events/Event.h"
|
||||
#include "GDCore/Events/EventsList.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/String.h"
|
||||
#include "GDCore/Tools/Log.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
bool LinkEventTargetRenamer::DoVisitLinkEvent(gd::LinkEvent &linkEvent) {
|
||||
|
||||
if (linkEvent.GetTarget() == oldName) {
|
||||
linkEvent.SetTarget(newName);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
LinkEventTargetRenamer::~LinkEventTargetRenamer() {}
|
||||
|
||||
} // namespace gd
|
44
Core/GDCore/IDE/Events/LinkEventTargetRenamer.h
Normal file
44
Core/GDCore/IDE/Events/LinkEventTargetRenamer.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
|
||||
#include "GDCore/String.h"
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace gd {
|
||||
class BaseEvent;
|
||||
class LinkEvent;
|
||||
class Platform;
|
||||
class EventsList;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief Replace in link events the name of external events.
|
||||
*
|
||||
* \ingroup IDE
|
||||
*/
|
||||
class GD_CORE_API LinkEventTargetRenamer
|
||||
: public ArbitraryEventsWorkerWithContext {
|
||||
public:
|
||||
LinkEventTargetRenamer(const gd::Platform &platform_,
|
||||
const gd::String &oldName_, const gd::String &newName_)
|
||||
: platform(platform_), oldName(oldName_), newName(newName_){};
|
||||
virtual ~LinkEventTargetRenamer();
|
||||
|
||||
private:
|
||||
bool DoVisitLinkEvent(gd::LinkEvent &linkEvent) override;
|
||||
|
||||
const gd::Platform &platform;
|
||||
gd::String oldName;
|
||||
gd::String newName;
|
||||
};
|
||||
|
||||
} // namespace gd
|
198
Core/GDCore/IDE/Events/ProjectElementRenamer.cpp
Normal file
198
Core/GDCore/IDE/Events/ProjectElementRenamer.cpp
Normal file
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "ProjectElementRenamer.h"
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/Events/Event.h"
|
||||
#include "GDCore/Events/EventsList.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodePrinter.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
#include "GDCore/Extensions/Metadata/ParameterMetadataTools.h"
|
||||
#include "GDCore/IDE/Events/ExpressionValidator.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/String.h"
|
||||
#include "GDCore/Tools/Log.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief Go through the nodes and find every function call parameter of a
|
||||
* given type.
|
||||
*
|
||||
* \see gd::ExpressionParser2
|
||||
*/
|
||||
class GD_CORE_API ExpressionIdentifierStringFinder
|
||||
: public ExpressionParser2NodeWorker {
|
||||
public:
|
||||
ExpressionIdentifierStringFinder(
|
||||
const gd::Platform &platform_,
|
||||
const gd::ObjectsContainer &globalObjectsContainer_,
|
||||
const gd::ObjectsContainer &objectsContainer_,
|
||||
const gd::String &expressionPlainString_,
|
||||
const gd::String ¶meterType_, const gd::String &objectName_,
|
||||
const gd::String &layerName_, const gd::String &oldName_)
|
||||
: platform(platform_), globalObjectsContainer(globalObjectsContainer_),
|
||||
objectsContainer(objectsContainer_),
|
||||
expressionPlainString(expressionPlainString_),
|
||||
parameterType(parameterType_), objectName(objectName_),
|
||||
layerName(layerName_), oldName(oldName_){};
|
||||
virtual ~ExpressionIdentifierStringFinder(){};
|
||||
|
||||
const std::vector<gd::ExpressionParserLocation> GetOccurrences() const {
|
||||
return occurrences;
|
||||
}
|
||||
|
||||
protected:
|
||||
void OnVisitSubExpressionNode(SubExpressionNode &node) override {
|
||||
node.expression->Visit(*this);
|
||||
}
|
||||
void OnVisitOperatorNode(OperatorNode &node) override {
|
||||
node.leftHandSide->Visit(*this);
|
||||
node.rightHandSide->Visit(*this);
|
||||
}
|
||||
void OnVisitUnaryOperatorNode(UnaryOperatorNode &node) override {
|
||||
node.factor->Visit(*this);
|
||||
}
|
||||
void OnVisitNumberNode(NumberNode &node) override {}
|
||||
void OnVisitTextNode(TextNode &node) override {}
|
||||
void OnVisitVariableNode(VariableNode &node) override {
|
||||
if (node.child)
|
||||
node.child->Visit(*this);
|
||||
}
|
||||
void OnVisitVariableAccessorNode(VariableAccessorNode &node) override {
|
||||
if (node.child)
|
||||
node.child->Visit(*this);
|
||||
}
|
||||
void OnVisitVariableBracketAccessorNode(
|
||||
VariableBracketAccessorNode &node) override {
|
||||
node.expression->Visit(*this);
|
||||
if (node.child)
|
||||
node.child->Visit(*this);
|
||||
}
|
||||
void OnVisitIdentifierNode(IdentifierNode &node) override {}
|
||||
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode &node) override {}
|
||||
void OnVisitFunctionCallNode(FunctionCallNode &node) override {
|
||||
gd::String lastLayerName;
|
||||
gd::ParameterMetadataTools::IterateOverParametersWithIndex(
|
||||
platform, globalObjectsContainer, objectsContainer, node,
|
||||
[&](const gd::ParameterMetadata ¶meterMetadata,
|
||||
std::unique_ptr<gd::ExpressionNode> ¶meterNode,
|
||||
size_t parameterIndex, const gd::String &lastObjectName) {
|
||||
if (parameterMetadata.GetType() == "layer") {
|
||||
// Remove quotes, it won't match if it's not a literal anyway.
|
||||
lastLayerName = expressionPlainString.substr(
|
||||
parameterNode->location.GetStartPosition() + 1,
|
||||
parameterNode->location.GetEndPosition() -
|
||||
parameterNode->location.GetStartPosition() - 2);
|
||||
}
|
||||
if (parameterMetadata.GetType() == parameterType) {
|
||||
auto parameterExpressionPlainString = expressionPlainString.substr(
|
||||
parameterNode->location.GetStartPosition(),
|
||||
parameterNode->location.GetEndPosition() -
|
||||
parameterNode->location.GetStartPosition());
|
||||
if ((objectName.empty() || lastObjectName == objectName) &&
|
||||
(layerName.empty() || lastLayerName == layerName) &&
|
||||
parameterExpressionPlainString == "\"" + oldName + "\"") {
|
||||
occurrences.push_back(parameterNode->location);
|
||||
} else {
|
||||
parameterNode->Visit(*this);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
void OnVisitEmptyNode(EmptyNode &node) override {}
|
||||
|
||||
private:
|
||||
const gd::Platform &platform;
|
||||
const gd::ObjectsContainer &globalObjectsContainer;
|
||||
const gd::ObjectsContainer &objectsContainer;
|
||||
/// It's used to extract parameter content.
|
||||
const gd::String &expressionPlainString;
|
||||
const gd::String &oldName;
|
||||
/// The type of parameter to check.
|
||||
const gd::String parameterType;
|
||||
/// If not empty, parameters will be taken into account only if related to
|
||||
/// this object.
|
||||
const gd::String objectName;
|
||||
/// If not empty, parameters will be taken into account only if related to
|
||||
/// this layer.
|
||||
const gd::String layerName;
|
||||
std::vector<gd::ExpressionParserLocation> occurrences;
|
||||
};
|
||||
|
||||
bool ProjectElementRenamer::DoVisitInstruction(gd::Instruction &instruction,
|
||||
bool isCondition) {
|
||||
const auto &metadata = isCondition
|
||||
? gd::MetadataProvider::GetConditionMetadata(
|
||||
platform, instruction.GetType())
|
||||
: gd::MetadataProvider::GetActionMetadata(
|
||||
platform, instruction.GetType());
|
||||
|
||||
gd::String lastLayerName;
|
||||
gd::ParameterMetadataTools::IterateOverParametersWithIndex(
|
||||
instruction.GetParameters(), metadata.GetParameters(),
|
||||
[&](const gd::ParameterMetadata ¶meterMetadata,
|
||||
const gd::Expression ¶meterValue, size_t parameterIndex,
|
||||
const gd::String &lastObjectName) {
|
||||
if (parameterMetadata.GetType() == "layer") {
|
||||
// Remove quotes, it won't match if it's not a literal anyway.
|
||||
lastLayerName = parameterValue.GetPlainString().substr(
|
||||
1, parameterValue.GetPlainString().length() - 2);
|
||||
}
|
||||
|
||||
if (parameterMetadata.GetType() == parameterType &&
|
||||
(objectName.empty() || lastObjectName == objectName) &&
|
||||
(layerName.empty() || lastLayerName == layerName)) {
|
||||
if (parameterValue.GetPlainString() == "\"" + oldName + "\"") {
|
||||
instruction.SetParameter(parameterIndex,
|
||||
gd::Expression("\"" + newName + "\""));
|
||||
}
|
||||
}
|
||||
auto node = parameterValue.GetRootNode();
|
||||
if (node) {
|
||||
ExpressionIdentifierStringFinder finder(
|
||||
platform, GetGlobalObjectsContainer(), GetObjectsContainer(),
|
||||
parameterValue.GetPlainString(), parameterType, objectName,
|
||||
layerName, oldName);
|
||||
node->Visit(finder);
|
||||
|
||||
if (finder.GetOccurrences().size() > 0) {
|
||||
|
||||
gd::String newNameWithQuotes = "\"" + newName + "\"";
|
||||
gd::String oldParameterValue = parameterValue.GetPlainString();
|
||||
gd::String newParameterValue;
|
||||
auto previousEndPosition = 0;
|
||||
for (auto &&occurrenceLocation : finder.GetOccurrences()) {
|
||||
newParameterValue += oldParameterValue.substr(
|
||||
previousEndPosition,
|
||||
occurrenceLocation.GetStartPosition() - previousEndPosition);
|
||||
newParameterValue += newNameWithQuotes;
|
||||
|
||||
previousEndPosition = occurrenceLocation.GetEndPosition();
|
||||
}
|
||||
if (previousEndPosition < oldParameterValue.size()) {
|
||||
newParameterValue += oldParameterValue.substr(
|
||||
previousEndPosition,
|
||||
oldParameterValue.size() - previousEndPosition);
|
||||
}
|
||||
|
||||
instruction.SetParameter(parameterIndex,
|
||||
gd::Expression(newParameterValue));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ProjectElementRenamer::~ProjectElementRenamer() {}
|
||||
|
||||
} // namespace gd
|
63
Core/GDCore/IDE/Events/ProjectElementRenamer.h
Normal file
63
Core/GDCore/IDE/Events/ProjectElementRenamer.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
|
||||
#include "GDCore/String.h"
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace gd {
|
||||
class BaseEvent;
|
||||
class Platform;
|
||||
class EventsList;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief Replace in expressions and in parameters of actions or conditions
|
||||
* occurrences of project element name. For instance, it can be layouts or
|
||||
* object effects.
|
||||
*
|
||||
* \ingroup IDE
|
||||
*/
|
||||
class GD_CORE_API ProjectElementRenamer
|
||||
: public ArbitraryEventsWorkerWithContext {
|
||||
public:
|
||||
ProjectElementRenamer(const gd::Platform &platform_,
|
||||
const gd::String ¶meterType_,
|
||||
const gd::String &oldName_, const gd::String &newName_)
|
||||
: platform(platform_), parameterType(parameterType_), oldName(oldName_),
|
||||
newName(newName_){};
|
||||
virtual ~ProjectElementRenamer();
|
||||
|
||||
void SetObjectConstraint(const gd::String &objectName_) {
|
||||
objectName = objectName_;
|
||||
}
|
||||
|
||||
void SetLayerConstraint(const gd::String &layerName_) {
|
||||
layerName = layerName_;
|
||||
}
|
||||
|
||||
private:
|
||||
bool DoVisitInstruction(gd::Instruction &instruction,
|
||||
bool isCondition) override;
|
||||
|
||||
const gd::Platform &platform;
|
||||
const gd::String parameterType;
|
||||
/// If not empty, parameters will be taken into account only if related to
|
||||
/// this object.
|
||||
gd::String objectName;
|
||||
/// If not empty, parameters will be taken into account only if related to
|
||||
/// this layer.
|
||||
gd::String layerName;
|
||||
const gd::String oldName;
|
||||
const gd::String newName;
|
||||
};
|
||||
|
||||
} // namespace gd
|
@@ -82,7 +82,7 @@ bool UsedExtensionsFinder::DoVisitInstruction(gd::Instruction& instruction,
|
||||
|
||||
// Expressions scanner
|
||||
|
||||
// Ignore litterals nodes
|
||||
// Ignore literals nodes
|
||||
void UsedExtensionsFinder::OnVisitNumberNode(NumberNode& node){};
|
||||
void UsedExtensionsFinder::OnVisitTextNode(TextNode& node){};
|
||||
|
||||
|
@@ -144,7 +144,7 @@ void ExtensionsLoader::LoadExtension(const gd::String &fullpath,
|
||||
bool forgiving) {
|
||||
if (platform.GetExtensionCreateFunctionName().empty()) {
|
||||
cout << "Unable to load extension " << fullpath << ":" << endl;
|
||||
cout << "The plaftorm does not support extensions creation." << endl;
|
||||
cout << "The platform does not support extensions creation." << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@@ -35,7 +35,7 @@ class GD_CORE_API ExtensionsLoader {
|
||||
* \param platform The platform the extensions belongs to.
|
||||
* \param forgiving If set to true, files will try to be opened, but a failure
|
||||
* when searching for the platform creation function symbol won't be logged as
|
||||
* an error. (All other errors are still reparted as usual).
|
||||
* an error. (All other errors are still reported as usual).
|
||||
*
|
||||
* \note Extensions files must have extensions *.xgd(w|l|m)(e),
|
||||
* w for Windows, l for Linux, m for Mac, e for Edittime extensions.
|
||||
@@ -51,7 +51,7 @@ class GD_CORE_API ExtensionsLoader {
|
||||
* \param platform The platform the extension belongs to.
|
||||
* \param forgiving If set to true, files will try to be opened, but a failure
|
||||
* when searching for the platform creation function symbol won't be logged as
|
||||
* an error. (All other errors are still reparted as usual).
|
||||
* an error. (All other errors are still reported as usual).
|
||||
*/
|
||||
static void LoadExtension(const gd::String& fullpath,
|
||||
gd::Platform& platform,
|
||||
|
@@ -45,6 +45,11 @@ void ArbitraryResourceWorker::ExposeTileset(gd::String& tilesetName){
|
||||
// do.
|
||||
};
|
||||
|
||||
void ArbitraryResourceWorker::ExposeModel3D(gd::String& resourceName){
|
||||
// Nothing to do by default - each child class can define here the action to
|
||||
// do.
|
||||
};
|
||||
|
||||
void ArbitraryResourceWorker::ExposeVideo(gd::String& videoName){
|
||||
// Nothing to do by default - each child class can define here the action to
|
||||
// do.
|
||||
@@ -66,7 +71,7 @@ void ArbitraryResourceWorker::ExposeAudio(gd::String& audioName) {
|
||||
}
|
||||
}
|
||||
|
||||
// For compatibility with older projects (where events were refering to files
|
||||
// For compatibility with older projects (where events were referring to files
|
||||
// directly), we consider that this resource name is a filename, and so expose
|
||||
// it as a file.
|
||||
ExposeFile(audioName);
|
||||
@@ -83,7 +88,7 @@ void ArbitraryResourceWorker::ExposeFont(gd::String& fontName) {
|
||||
}
|
||||
}
|
||||
|
||||
// For compatibility with older projects (where events were refering to files
|
||||
// For compatibility with older projects (where events were referring to files
|
||||
// directly), we consider that this resource name is a filename, and so expose
|
||||
// it as a file.
|
||||
ExposeFile(fontName);
|
||||
@@ -146,6 +151,8 @@ void ArbitraryResourceWorker::ExposeEmbeddeds(gd::String& resourceName) {
|
||||
ExposeTileset(potentiallyUpdatedTargetResourceName);
|
||||
} else if (targetResourceKind == "video") {
|
||||
ExposeVideo(potentiallyUpdatedTargetResourceName);
|
||||
} else if (targetResourceKind == "model3D") {
|
||||
ExposeModel3D(potentiallyUpdatedTargetResourceName);
|
||||
}
|
||||
|
||||
if (potentiallyUpdatedTargetResourceName != targetResourceName) {
|
||||
@@ -233,6 +240,10 @@ class ResourceWorkerInEventsWorker : public ArbitraryEventsWorker {
|
||||
gd::String updatedParameterValue = parameterValue;
|
||||
worker.ExposeTileset(updatedParameterValue);
|
||||
instruction.SetParameter(parameterIndex, updatedParameterValue);
|
||||
} else if (parameterMetadata.GetType() == "model3DResource") {
|
||||
gd::String updatedParameterValue = parameterValue;
|
||||
worker.ExposeModel3D(updatedParameterValue);
|
||||
instruction.SetParameter(parameterIndex, updatedParameterValue);
|
||||
}
|
||||
});
|
||||
|
||||
|
@@ -85,6 +85,11 @@ class GD_CORE_API ArbitraryResourceWorker {
|
||||
*/
|
||||
virtual void ExposeTileset(gd::String &tilesetName);
|
||||
|
||||
/**
|
||||
* \brief Expose a 3D model, which is always a reference to a "model3D" resource.
|
||||
*/
|
||||
virtual void ExposeModel3D(gd::String &resourceName);
|
||||
|
||||
/**
|
||||
* \brief Expose a video, which is always a reference to a "video" resource.
|
||||
*/
|
||||
|
@@ -29,7 +29,7 @@ bool ProjectResourcesCopier::CopyAllResourcesTo(
|
||||
originalProject.ExposeResources(absolutePathChecker);
|
||||
|
||||
auto projectDirectory = fs.DirNameFrom(originalProject.GetProjectFile());
|
||||
std::cout << "Copying all ressources from " << projectDirectory << " to "
|
||||
std::cout << "Copying all resources from " << projectDirectory << " to "
|
||||
<< destinationDirectory << "..." << std::endl;
|
||||
|
||||
// Get the resources to be copied
|
||||
|
@@ -44,6 +44,7 @@ class ResourcesInUseHelper : public gd::ArbitraryResourceWorker {
|
||||
std::set<gd::String>& GetAllTilesets() { return GetAll("tileset"); };
|
||||
std::set<gd::String>& GetAllVideos() { return GetAll("video"); };
|
||||
std::set<gd::String>& GetAllBitmapFonts() { return GetAll("bitmapFont"); };
|
||||
std::set<gd::String>& GetAll3DModels() { return GetAll("model3D"); };
|
||||
std::set<gd::String>& GetAll(const gd::String& resourceType) {
|
||||
if (resourceType == "image") return allImages;
|
||||
if (resourceType == "audio") return allAudios;
|
||||
@@ -53,6 +54,7 @@ class ResourcesInUseHelper : public gd::ArbitraryResourceWorker {
|
||||
if (resourceType == "tileset") return allTilesets;
|
||||
if (resourceType == "video") return allVideos;
|
||||
if (resourceType == "bitmapFont") return allBitmapFonts;
|
||||
if (resourceType == "model3D") return allModel3Ds;
|
||||
|
||||
return emptyResources;
|
||||
};
|
||||
@@ -84,6 +86,9 @@ class ResourcesInUseHelper : public gd::ArbitraryResourceWorker {
|
||||
virtual void ExposeBitmapFont(gd::String& bitmapFontResourceName) override {
|
||||
allBitmapFonts.insert(bitmapFontResourceName);
|
||||
};
|
||||
virtual void ExposeModel3D(gd::String& resourceName) override {
|
||||
allModel3Ds.insert(resourceName);
|
||||
};
|
||||
|
||||
protected:
|
||||
std::set<gd::String> allImages;
|
||||
@@ -94,6 +99,7 @@ class ResourcesInUseHelper : public gd::ArbitraryResourceWorker {
|
||||
std::set<gd::String> allTilesets;
|
||||
std::set<gd::String> allVideos;
|
||||
std::set<gd::String> allBitmapFonts;
|
||||
std::set<gd::String> allModel3Ds;
|
||||
std::set<gd::String> emptyResources;
|
||||
};
|
||||
|
||||
|
@@ -59,6 +59,9 @@ class ResourcesRenamer : public gd::ArbitraryResourceWorker {
|
||||
virtual void ExposeBitmapFont(gd::String& bitmapFontName) override {
|
||||
RenameIfNeeded(bitmapFontName);
|
||||
};
|
||||
virtual void ExposeModel3D(gd::String& resourceName) override {
|
||||
RenameIfNeeded(resourceName);
|
||||
};
|
||||
|
||||
private:
|
||||
void RenameIfNeeded(gd::String& resourceName) {
|
||||
|
@@ -67,6 +67,38 @@ void ProjectBrowserHelper::ExposeProjectEventsWithoutExtensions(
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectBrowserHelper::ExposeLayoutEvents(
|
||||
gd::Project &project, gd::Layout &layout,
|
||||
gd::ArbitraryEventsWorker &worker) {
|
||||
|
||||
// Add layouts events
|
||||
worker.Launch(layout.GetEvents());
|
||||
|
||||
// Add external events events
|
||||
for (std::size_t s = 0; s < project.GetExternalEventsCount(); s++) {
|
||||
auto &externalEvents = project.GetExternalEvents(s);
|
||||
if (externalEvents.GetAssociatedLayout() == layout.GetName()) {
|
||||
worker.Launch(externalEvents.GetEvents());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectBrowserHelper::ExposeLayoutEvents(
|
||||
gd::Project &project, gd::Layout &layout,
|
||||
gd::ArbitraryEventsWorkerWithContext &worker) {
|
||||
|
||||
// Add layouts events
|
||||
worker.Launch(layout.GetEvents(), project, layout);
|
||||
|
||||
// Add external events events
|
||||
for (std::size_t s = 0; s < project.GetExternalEventsCount(); s++) {
|
||||
auto &externalEvents = project.GetExternalEvents(s);
|
||||
if (externalEvents.GetAssociatedLayout() == layout.GetName()) {
|
||||
worker.Launch(externalEvents.GetEvents(), project, layout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectBrowserHelper::ExposeProjectEvents(
|
||||
gd::Project &project, gd::ArbitraryEventsWorkerWithContext &worker) {
|
||||
// See also gd::Project::ExposeResources for a method that traverse the whole
|
||||
|
@@ -7,6 +7,7 @@
|
||||
|
||||
namespace gd {
|
||||
class Project;
|
||||
class Layout;
|
||||
class String;
|
||||
class EventsFunctionsExtension;
|
||||
class EventsFunction;
|
||||
@@ -55,6 +56,19 @@ public:
|
||||
ExposeProjectEventsWithoutExtensions(gd::Project &project,
|
||||
gd::ArbitraryEventsWorker &worker);
|
||||
|
||||
/**
|
||||
* \brief Call the specified worker on all events of a layout and
|
||||
* its external events.
|
||||
*/
|
||||
static void ExposeLayoutEvents(gd::Project &project, gd::Layout &layout,
|
||||
gd::ArbitraryEventsWorker &worker);
|
||||
/**
|
||||
* \brief Call the specified worker on all events of a layout and
|
||||
* its external events.
|
||||
*/
|
||||
static void ExposeLayoutEvents(gd::Project &project, gd::Layout &layout,
|
||||
gd::ArbitraryEventsWorkerWithContext &worker);
|
||||
|
||||
/**
|
||||
* \brief Call the specified worker on all events of the event-based
|
||||
* behavior
|
||||
|
@@ -11,6 +11,8 @@
|
||||
#include "GDCore/IDE/DependenciesAnalyzer.h"
|
||||
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
|
||||
#include "GDCore/IDE/Events/EventsBehaviorRenamer.h"
|
||||
#include "GDCore/IDE/Events/ProjectElementRenamer.h"
|
||||
#include "GDCore/IDE/Events/LinkEventTargetRenamer.h"
|
||||
#include "GDCore/IDE/Events/CustomObjectTypeRenamer.h"
|
||||
#include "GDCore/IDE/Events/BehaviorTypeRenamer.h"
|
||||
#include "GDCore/IDE/Events/EventsRefactorer.h"
|
||||
@@ -843,9 +845,21 @@ void WholeProjectRefactorer::AddBehaviorAndRequiredBehaviors(
|
||||
return;
|
||||
};
|
||||
|
||||
AddRequiredBehaviorsFor(project, object, behaviorName);
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::AddRequiredBehaviorsFor(
|
||||
gd::Project& project,
|
||||
gd::Object& object,
|
||||
const gd::String& behaviorName) {
|
||||
if (!object.HasBehaviorNamed(behaviorName)) {
|
||||
return;
|
||||
};
|
||||
gd::Behavior& behavior = object.GetBehavior(behaviorName);
|
||||
|
||||
const gd::Platform& platform = project.GetCurrentPlatform();
|
||||
const gd::BehaviorMetadata& behaviorMetadata =
|
||||
MetadataProvider::GetBehaviorMetadata(platform, behaviorType);
|
||||
MetadataProvider::GetBehaviorMetadata(platform, behavior.GetTypeName());
|
||||
if (MetadataProvider::IsBadBehaviorMetadata(behaviorMetadata)) {
|
||||
// Should not happen because the behavior was added successfully (so its
|
||||
// metadata are valid) - but double check anyway and bail out if the
|
||||
@@ -853,7 +867,6 @@ void WholeProjectRefactorer::AddBehaviorAndRequiredBehaviors(
|
||||
return;
|
||||
}
|
||||
|
||||
gd::Behavior& behavior = object.GetBehavior(behaviorName);
|
||||
for (auto const& keyValue : behavior.GetProperties()) {
|
||||
const gd::String& propertyName = keyValue.first;
|
||||
const gd::PropertyDescriptor& property = keyValue.second;
|
||||
@@ -1380,25 +1393,12 @@ void WholeProjectRefactorer::ObjectOrGroupRemovedInLayout(
|
||||
|
||||
// Remove object in external events
|
||||
if (removeEventsAndGroups) {
|
||||
DependenciesAnalyzer analyzer(project, layout);
|
||||
if (analyzer.Analyze()) {
|
||||
for (auto& externalEventsName :
|
||||
analyzer.GetExternalEventsDependencies()) {
|
||||
auto& externalEvents = project.GetExternalEvents(externalEventsName);
|
||||
gd::EventsRefactorer::RemoveObjectInEvents(project.GetCurrentPlatform(),
|
||||
project,
|
||||
layout,
|
||||
externalEvents.GetEvents(),
|
||||
objectName);
|
||||
}
|
||||
for (auto& layoutName : analyzer.GetScenesDependencies()) {
|
||||
auto& layout = project.GetLayout(layoutName);
|
||||
gd::EventsRefactorer::RemoveObjectInEvents(project.GetCurrentPlatform(),
|
||||
project,
|
||||
layout,
|
||||
layout.GetEvents(),
|
||||
objectName);
|
||||
}
|
||||
for (auto &externalEventsName :
|
||||
GetAssociatedExternalEvents(project, layout.GetName())) {
|
||||
auto &externalEvents = project.GetExternalEvents(externalEventsName);
|
||||
gd::EventsRefactorer::RemoveObjectInEvents(
|
||||
project.GetCurrentPlatform(), project, layout,
|
||||
externalEvents.GetEvents(), objectName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1437,26 +1437,12 @@ void WholeProjectRefactorer::ObjectOrGroupRenamedInLayout(
|
||||
}
|
||||
|
||||
// Rename object in external events
|
||||
DependenciesAnalyzer analyzer(project, layout);
|
||||
if (analyzer.Analyze()) {
|
||||
for (auto& externalEventsName : analyzer.GetExternalEventsDependencies()) {
|
||||
auto& externalEvents = project.GetExternalEvents(externalEventsName);
|
||||
gd::EventsRefactorer::RenameObjectInEvents(project.GetCurrentPlatform(),
|
||||
project,
|
||||
layout,
|
||||
externalEvents.GetEvents(),
|
||||
oldName,
|
||||
newName);
|
||||
}
|
||||
for (auto& layoutName : analyzer.GetScenesDependencies()) {
|
||||
auto& layout = project.GetLayout(layoutName);
|
||||
gd::EventsRefactorer::RenameObjectInEvents(project.GetCurrentPlatform(),
|
||||
project,
|
||||
layout,
|
||||
layout.GetEvents(),
|
||||
oldName,
|
||||
newName);
|
||||
}
|
||||
for (auto &externalEventsName :
|
||||
GetAssociatedExternalEvents(project, layout.GetName())) {
|
||||
auto &externalEvents = project.GetExternalEvents(externalEventsName);
|
||||
gd::EventsRefactorer::RenameObjectInEvents(
|
||||
project.GetCurrentPlatform(), project, layout,
|
||||
externalEvents.GetEvents(), oldName, newName);
|
||||
}
|
||||
|
||||
// Rename object in external layouts
|
||||
@@ -1471,6 +1457,102 @@ void WholeProjectRefactorer::ObjectOrGroupRenamedInLayout(
|
||||
}
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::RenameLayout(gd::Project &project,
|
||||
const gd::String &oldName,
|
||||
const gd::String &newName) {
|
||||
gd::ProjectElementRenamer projectElementRenamer(
|
||||
project.GetCurrentPlatform(), "sceneName", oldName, newName);
|
||||
gd::ProjectBrowserHelper::ExposeProjectEvents(project, projectElementRenamer);
|
||||
|
||||
for (gd::String externalLayoutName :
|
||||
GetAssociatedExternalLayouts(project, oldName)) {
|
||||
auto &externalLayout = project.GetExternalLayout(externalLayoutName);
|
||||
externalLayout.SetAssociatedLayout(newName);
|
||||
}
|
||||
for (gd::String externalEventsName :
|
||||
GetAssociatedExternalEvents(project, oldName)) {
|
||||
auto &externalEvents = project.GetExternalEvents(externalEventsName);
|
||||
externalEvents.SetAssociatedLayout(newName);
|
||||
}
|
||||
|
||||
gd::LinkEventTargetRenamer linkEventTargetRenamer(
|
||||
project.GetCurrentPlatform(), oldName, newName);
|
||||
gd::ProjectBrowserHelper::ExposeProjectEvents(project, linkEventTargetRenamer);
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::RenameExternalLayout(gd::Project &project,
|
||||
const gd::String &oldName,
|
||||
const gd::String &newName) {
|
||||
gd::ProjectElementRenamer projectElementRenamer(
|
||||
project.GetCurrentPlatform(), "externalLayoutName", oldName, newName);
|
||||
gd::ProjectBrowserHelper::ExposeProjectEvents(project, projectElementRenamer);
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::RenameExternalEvents(gd::Project &project,
|
||||
const gd::String &oldName,
|
||||
const gd::String &newName) {
|
||||
gd::LinkEventTargetRenamer linkEventTargetRenamer(
|
||||
project.GetCurrentPlatform(), oldName, newName);
|
||||
gd::ProjectBrowserHelper::ExposeProjectEvents(project, linkEventTargetRenamer);
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::RenameLayer(gd::Project &project,
|
||||
gd::Layout &layout,
|
||||
const gd::String &oldName,
|
||||
const gd::String &newName) {
|
||||
gd::ProjectElementRenamer projectElementRenamer(
|
||||
project.GetCurrentPlatform(), "layer", oldName, newName);
|
||||
gd::ProjectBrowserHelper::ExposeLayoutEvents(project, layout, projectElementRenamer);
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::RenameLayerEffect(gd::Project &project,
|
||||
gd::Layout &layout,
|
||||
gd::Layer &layer,
|
||||
const gd::String &oldName,
|
||||
const gd::String &newName) {
|
||||
gd::ProjectElementRenamer projectElementRenamer(
|
||||
project.GetCurrentPlatform(), "layerEffectName", oldName, newName);
|
||||
projectElementRenamer.SetLayerConstraint(layer.GetName());
|
||||
gd::ProjectBrowserHelper::ExposeLayoutEvents(project, layout,
|
||||
projectElementRenamer);
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::RenameObjectAnimation(gd::Project &project,
|
||||
gd::Layout &layout,
|
||||
gd::Object &object,
|
||||
const gd::String &oldName,
|
||||
const gd::String &newName) {
|
||||
gd::ProjectElementRenamer projectElementRenamer(
|
||||
project.GetCurrentPlatform(), "objectAnimationName", oldName, newName);
|
||||
projectElementRenamer.SetObjectConstraint(object.GetName());
|
||||
gd::ProjectBrowserHelper::ExposeLayoutEvents(project, layout,
|
||||
projectElementRenamer);
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::RenameObjectPoint(gd::Project &project,
|
||||
gd::Layout &layout,
|
||||
gd::Object &object,
|
||||
const gd::String &oldName,
|
||||
const gd::String &newName) {
|
||||
gd::ProjectElementRenamer projectElementRenamer(
|
||||
project.GetCurrentPlatform(), "objectPointName", oldName, newName);
|
||||
projectElementRenamer.SetObjectConstraint(object.GetName());
|
||||
gd::ProjectBrowserHelper::ExposeLayoutEvents(project, layout,
|
||||
projectElementRenamer);
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::RenameObjectEffect(gd::Project &project,
|
||||
gd::Layout &layout,
|
||||
gd::Object &object,
|
||||
const gd::String &oldName,
|
||||
const gd::String &newName) {
|
||||
gd::ProjectElementRenamer projectElementRenamer(
|
||||
project.GetCurrentPlatform(), "objectEffectName", oldName, newName);
|
||||
projectElementRenamer.SetObjectConstraint(object.GetName());
|
||||
gd::ProjectBrowserHelper::ExposeLayoutEvents(project, layout,
|
||||
projectElementRenamer);
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::ObjectOrGroupRemovedInEventsBasedObject(
|
||||
gd::Project& project,
|
||||
gd::EventsBasedObject& eventsBasedObject,
|
||||
@@ -1606,11 +1688,16 @@ void WholeProjectRefactorer::GlobalObjectOrGroupRemoved(
|
||||
|
||||
std::vector<gd::String> WholeProjectRefactorer::GetAssociatedExternalLayouts(
|
||||
gd::Project& project, gd::Layout& layout) {
|
||||
return GetAssociatedExternalLayouts(project, layout.GetName());
|
||||
}
|
||||
|
||||
std::vector<gd::String> WholeProjectRefactorer::GetAssociatedExternalLayouts(
|
||||
gd::Project& project, const gd::String& layoutName) {
|
||||
std::vector<gd::String> results;
|
||||
for (std::size_t i = 0; i < project.GetExternalLayoutsCount(); ++i) {
|
||||
auto& externalLayout = project.GetExternalLayout(i);
|
||||
|
||||
if (externalLayout.GetAssociatedLayout() == layout.GetName()) {
|
||||
if (externalLayout.GetAssociatedLayout() == layoutName) {
|
||||
results.push_back(externalLayout.GetName());
|
||||
}
|
||||
}
|
||||
@@ -1618,4 +1705,18 @@ std::vector<gd::String> WholeProjectRefactorer::GetAssociatedExternalLayouts(
|
||||
return results;
|
||||
}
|
||||
|
||||
std::vector<gd::String> WholeProjectRefactorer::GetAssociatedExternalEvents(
|
||||
gd::Project &project, const gd::String &layoutName) {
|
||||
std::vector<gd::String> results;
|
||||
for (std::size_t i = 0; i < project.GetExternalEventsCount(); ++i) {
|
||||
auto &externalEvents = project.GetExternalEvents(i);
|
||||
|
||||
if (externalEvents.GetAssociatedLayout() == layoutName) {
|
||||
results.push_back(externalEvents.GetName());
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -12,6 +12,7 @@ namespace gd {
|
||||
class Platform;
|
||||
class Project;
|
||||
class Layout;
|
||||
class Layer;
|
||||
class Object;
|
||||
class String;
|
||||
class EventsFunctionsExtension;
|
||||
@@ -211,6 +212,13 @@ class GD_CORE_API WholeProjectRefactorer {
|
||||
gd::Object& object,
|
||||
const gd::String& behaviorType,
|
||||
const gd::String& behaviorName);
|
||||
/**
|
||||
* \brief Add required behaviors if necessary to fill every behavior
|
||||
* properties of the given behaviors.
|
||||
*/
|
||||
static void AddRequiredBehaviorsFor(gd::Project& project,
|
||||
gd::Object& object,
|
||||
const gd::String& behaviorName);
|
||||
|
||||
/**
|
||||
* \brief Find every behavior of the object that needs the given behaviors
|
||||
@@ -268,11 +276,63 @@ class GD_CORE_API WholeProjectRefactorer {
|
||||
const gd::String& oldObjectName,
|
||||
const gd::String& newObjectName);
|
||||
|
||||
/**
|
||||
* \brief Refactor the project after a layout is renamed.
|
||||
*/
|
||||
static void RenameLayout(gd::Project &project, const gd::String &oldName,
|
||||
const gd::String &newName);
|
||||
/**
|
||||
* \brief Refactor the project after an external layout is renamed.
|
||||
*/
|
||||
static void RenameExternalLayout(gd::Project &project,
|
||||
const gd::String &oldName,
|
||||
const gd::String &newName);
|
||||
/**
|
||||
* \brief Refactor the project after external events are renamed.
|
||||
*/
|
||||
static void RenameExternalEvents(gd::Project &project,
|
||||
const gd::String &oldName,
|
||||
const gd::String &newName);
|
||||
/**
|
||||
* \brief Refactor the project after a layer is renamed.
|
||||
*/
|
||||
static void RenameLayer(gd::Project &project, gd::Layout &layout,
|
||||
const gd::String &oldName, const gd::String &newName);
|
||||
|
||||
/**
|
||||
* \brief Refactor the project after a layer effect is renamed.
|
||||
*/
|
||||
static void RenameLayerEffect(gd::Project &project, gd::Layout &layout,
|
||||
gd::Layer &layer, const gd::String &oldName,
|
||||
const gd::String &newName);
|
||||
|
||||
/**
|
||||
* \brief Refactor the project after an object animation is renamed.
|
||||
*/
|
||||
static void RenameObjectAnimation(gd::Project &project, gd::Layout &layout,
|
||||
gd::Object &object,
|
||||
const gd::String &oldName,
|
||||
const gd::String &newName);
|
||||
|
||||
/**
|
||||
* \brief Refactor the project after an object point is renamed.
|
||||
*/
|
||||
static void RenameObjectPoint(gd::Project &project, gd::Layout &layout,
|
||||
gd::Object &object, const gd::String &oldName,
|
||||
const gd::String &newName);
|
||||
|
||||
/**
|
||||
* \brief Refactor the project after an object effect is renamed.
|
||||
*/
|
||||
static void RenameObjectEffect(gd::Project &project, gd::Layout &layout,
|
||||
gd::Object &object, const gd::String &oldName,
|
||||
const gd::String &newName);
|
||||
|
||||
/**
|
||||
* \brief Refactor the project after an object is renamed in a layout
|
||||
*
|
||||
* This will update the layout, all external layouts associated with it
|
||||
* and all external events used by the layout.
|
||||
* and all external events associated with it.
|
||||
*/
|
||||
static void ObjectOrGroupRenamedInLayout(gd::Project& project,
|
||||
gd::Layout& layout,
|
||||
@@ -284,7 +344,7 @@ class GD_CORE_API WholeProjectRefactorer {
|
||||
* \brief Refactor the project after an object is removed in a layout
|
||||
*
|
||||
* This will update the layout, all external layouts associated with it
|
||||
* and all external events used by the layout.
|
||||
* and all external events associated with it.
|
||||
*/
|
||||
static void ObjectOrGroupRemovedInLayout(gd::Project& project,
|
||||
gd::Layout& layout,
|
||||
@@ -401,6 +461,12 @@ class GD_CORE_API WholeProjectRefactorer {
|
||||
private:
|
||||
static std::vector<gd::String> GetAssociatedExternalLayouts(
|
||||
gd::Project& project, gd::Layout& layout);
|
||||
static std::vector<gd::String>
|
||||
GetAssociatedExternalLayouts(gd::Project &project,
|
||||
const gd::String &layoutName);
|
||||
static std::vector<gd::String>
|
||||
GetAssociatedExternalEvents(gd::Project &project,
|
||||
const gd::String &layoutName);
|
||||
|
||||
static void DoRenameEventsFunction(gd::Project& project,
|
||||
const gd::EventsFunction& eventsFunction,
|
||||
|
@@ -64,7 +64,7 @@ class GD_CORE_API EffectsContainer {
|
||||
std::size_t GetEffectPosition(const gd::String& name) const;
|
||||
|
||||
/**
|
||||
* Return the number of effecst.
|
||||
* Return the number of effects.
|
||||
*/
|
||||
std::size_t GetEffectsCount() const;
|
||||
|
||||
|
@@ -217,7 +217,7 @@ class GD_CORE_API EventsFunction {
|
||||
bool IsAsync() const { return isAsync; }
|
||||
|
||||
/**
|
||||
* \brief Sets the asycronity of the function.
|
||||
* \brief Sets the asynchronicity of the function.
|
||||
*/
|
||||
EventsFunction& SetAsync(bool _isAsync) {
|
||||
isAsync = _isAsync;
|
||||
|
@@ -193,7 +193,6 @@ class GD_CORE_API InitialInstance {
|
||||
* \see gd::Object
|
||||
*/
|
||||
///@{
|
||||
#if defined(GD_IDE_ONLY)
|
||||
/**
|
||||
* \brief Return a map containing the properties names (as keys) and their
|
||||
* values.
|
||||
@@ -213,7 +212,6 @@ class GD_CORE_API InitialInstance {
|
||||
const gd::String& value,
|
||||
gd::Project& project,
|
||||
gd::Layout& layout);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief Get the value of a double property stored in the instance.
|
||||
|
@@ -14,7 +14,14 @@ namespace gd {
|
||||
Camera Layer::badCamera;
|
||||
|
||||
Layer::Layer()
|
||||
: isVisible(true), isLightingLayer(false), followBaseLayerCamera(false) {}
|
||||
: renderingType(""),
|
||||
isVisible(true),
|
||||
isLocked(false),
|
||||
isLightingLayer(false),
|
||||
followBaseLayerCamera(false),
|
||||
camera3DNearPlaneDistance(0.1),
|
||||
camera3DFarPlaneDistance(10000),
|
||||
camera3DFieldOfView(45) {}
|
||||
|
||||
/**
|
||||
* Change cameras count, automatically adding/removing them.
|
||||
@@ -26,15 +33,21 @@ void Layer::SetCameraCount(std::size_t n) {
|
||||
cameras.erase(cameras.begin() + cameras.size() - 1);
|
||||
}
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
void Layer::SerializeTo(SerializerElement& element) const {
|
||||
element.SetAttribute("name", GetName());
|
||||
element.SetAttribute("renderingType", GetRenderingType());
|
||||
element.SetAttribute("visibility", GetVisibility());
|
||||
element.SetAttribute("isLocked", IsLocked());
|
||||
element.SetAttribute("isLightingLayer", IsLightingLayer());
|
||||
element.SetAttribute("followBaseLayerCamera", IsFollowingBaseLayerCamera());
|
||||
element.SetAttribute("ambientLightColorR", (int)GetAmbientLightColorRed());
|
||||
element.SetAttribute("ambientLightColorG", (int)GetAmbientLightColorGreen());
|
||||
element.SetAttribute("ambientLightColorB", (int)GetAmbientLightColorBlue());
|
||||
element.SetAttribute("camera3DNearPlaneDistance",
|
||||
GetCamera3DNearPlaneDistance());
|
||||
element.SetAttribute("camera3DFarPlaneDistance",
|
||||
GetCamera3DFarPlaneDistance());
|
||||
element.SetAttribute("camera3DFieldOfView", GetCamera3DFieldOfView());
|
||||
|
||||
SerializerElement& camerasElement = element.AddChild("cameras");
|
||||
camerasElement.ConsiderAsArrayOf("camera");
|
||||
@@ -55,20 +68,27 @@ void Layer::SerializeTo(SerializerElement& element) const {
|
||||
SerializerElement& effectsElement = element.AddChild("effects");
|
||||
effectsContainer.SerializeTo(effectsElement);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief Unserialize the layer.
|
||||
*/
|
||||
void Layer::UnserializeFrom(const SerializerElement& element) {
|
||||
SetName(element.GetStringAttribute("name", "", "Name"));
|
||||
SetRenderingType(element.GetStringAttribute("renderingType", ""));
|
||||
SetVisibility(element.GetBoolAttribute("visibility", true, "Visibility"));
|
||||
SetLocked(element.GetBoolAttribute("isLocked", false));
|
||||
SetLightingLayer(element.GetBoolAttribute("isLightingLayer", false));
|
||||
SetFollowBaseLayerCamera(
|
||||
element.GetBoolAttribute("followBaseLayerCamera", false));
|
||||
SetAmbientLightColor(element.GetIntAttribute("ambientLightColorR", 200),
|
||||
element.GetIntAttribute("ambientLightColorG", 200),
|
||||
element.GetIntAttribute("ambientLightColorB", 200));
|
||||
SetCamera3DNearPlaneDistance(element.GetDoubleAttribute(
|
||||
"camera3DNearPlaneDistance", 0.1, "threeDNearPlaneDistance"));
|
||||
SetCamera3DFarPlaneDistance(element.GetDoubleAttribute(
|
||||
"camera3DFarPlaneDistance", 10000, "threeDFarPlaneDistance"));
|
||||
SetCamera3DFieldOfView(element.GetDoubleAttribute(
|
||||
"camera3DFieldOfView", 45, "threeDFieldOfView"));
|
||||
|
||||
cameras.clear();
|
||||
SerializerElement& camerasElement = element.GetChild("cameras");
|
||||
@@ -80,24 +100,22 @@ void Layer::UnserializeFrom(const SerializerElement& element) {
|
||||
camera.SetUseDefaultSize(
|
||||
cameraElement.GetBoolAttribute("defaultSize", true));
|
||||
camera.SetSize(cameraElement.GetDoubleAttribute("width"),
|
||||
cameraElement.GetDoubleAttribute("height"));
|
||||
cameraElement.GetDoubleAttribute("height"));
|
||||
camera.SetUseDefaultViewport(
|
||||
cameraElement.GetBoolAttribute("defaultViewport", true));
|
||||
camera.SetViewport(
|
||||
cameraElement.GetDoubleAttribute("viewportLeft"),
|
||||
cameraElement.GetDoubleAttribute("viewportTop"),
|
||||
cameraElement.GetDoubleAttribute("viewportRight"),
|
||||
cameraElement.GetDoubleAttribute(
|
||||
"viewportBottom"));
|
||||
camera.SetViewport(cameraElement.GetDoubleAttribute("viewportLeft"),
|
||||
cameraElement.GetDoubleAttribute("viewportTop"),
|
||||
cameraElement.GetDoubleAttribute("viewportRight"),
|
||||
cameraElement.GetDoubleAttribute("viewportBottom"));
|
||||
|
||||
cameras.push_back(camera);
|
||||
}
|
||||
|
||||
if (camerasElement.GetChildrenCount() > 50) {
|
||||
// Highly unlikely that we want as many cameras, as they were not even exposed in
|
||||
// the editor nor used in the game engine. Must be because of a bug in the editor that
|
||||
// duplicated cameras when cancelling changes on a layer.
|
||||
// Reset to one camera.
|
||||
// Highly unlikely that we want as many cameras, as they were not even
|
||||
// exposed in the editor nor used in the game engine. Must be because of a
|
||||
// bug in the editor that duplicated cameras when cancelling changes on a
|
||||
// layer. Reset to one camera.
|
||||
SetCameraCount(1);
|
||||
}
|
||||
|
||||
@@ -105,9 +123,7 @@ void Layer::UnserializeFrom(const SerializerElement& element) {
|
||||
effectsContainer.UnserializeFrom(effectsElement);
|
||||
}
|
||||
|
||||
gd::EffectsContainer& Layer::GetEffects() {
|
||||
return effectsContainer;
|
||||
}
|
||||
gd::EffectsContainer& Layer::GetEffects() { return effectsContainer; }
|
||||
|
||||
const gd::EffectsContainer& Layer::GetEffects() const {
|
||||
return effectsContainer;
|
||||
|
@@ -47,6 +47,11 @@ class GD_CORE_API Layer {
|
||||
*/
|
||||
const gd::String& GetName() const { return name; }
|
||||
|
||||
const gd::String& GetRenderingType() const { return renderingType; }
|
||||
void SetRenderingType(const gd::String& renderingType_) {
|
||||
renderingType = renderingType_;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Change if layer is displayed or not
|
||||
*/
|
||||
@@ -58,7 +63,17 @@ class GD_CORE_API Layer {
|
||||
bool GetVisibility() const { return isVisible; }
|
||||
|
||||
/**
|
||||
* \brief Set if the layer is a lightining layer or not.
|
||||
* \brief Change if layer can be modified or not.
|
||||
*/
|
||||
void SetLocked(bool isLocked_) { isLocked = isLocked_; }
|
||||
|
||||
/**
|
||||
* \brief Return true if layer can't be modified.
|
||||
*/
|
||||
bool IsLocked() const { return isLocked; }
|
||||
|
||||
/**
|
||||
* \brief Set if the layer is a lighting layer or not.
|
||||
*/
|
||||
void SetLightingLayer(bool isLightingLayer_) {
|
||||
isLightingLayer = isLightingLayer_;
|
||||
@@ -81,6 +96,25 @@ class GD_CORE_API Layer {
|
||||
*/
|
||||
bool IsFollowingBaseLayerCamera() const { return followBaseLayerCamera; }
|
||||
|
||||
/** \name 3D
|
||||
*/
|
||||
///@{
|
||||
double GetCamera3DNearPlaneDistance() const {
|
||||
return camera3DNearPlaneDistance;
|
||||
}
|
||||
void SetCamera3DNearPlaneDistance(double distance) {
|
||||
camera3DNearPlaneDistance = distance;
|
||||
}
|
||||
double GetCamera3DFarPlaneDistance() const {
|
||||
return camera3DFarPlaneDistance;
|
||||
}
|
||||
void SetCamera3DFarPlaneDistance(double distance) {
|
||||
camera3DFarPlaneDistance = distance;
|
||||
}
|
||||
double GetCamera3DFieldOfView() const { return camera3DFieldOfView; }
|
||||
void SetCamera3DFieldOfView(double angle) { camera3DFieldOfView = angle; }
|
||||
///@}
|
||||
|
||||
/** \name Cameras
|
||||
*/
|
||||
///@{
|
||||
@@ -164,12 +198,10 @@ class GD_CORE_API Layer {
|
||||
const EffectsContainer& GetEffects() const;
|
||||
///@}
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
/**
|
||||
* \brief Serialize layer.
|
||||
*/
|
||||
void SerializeTo(SerializerElement& element) const;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief Unserialize the layer.
|
||||
@@ -177,16 +209,22 @@ class GD_CORE_API Layer {
|
||||
void UnserializeFrom(const SerializerElement& element);
|
||||
|
||||
private:
|
||||
gd::String name; ///< The name of the layer
|
||||
bool isVisible; ///< True if the layer is visible
|
||||
gd::String name; ///< The name of the layer
|
||||
gd::String renderingType; ///< The rendering type: "" (empty), "2d", "3d" or
|
||||
///< "2d+3d".
|
||||
bool isVisible; ///< True if the layer is visible
|
||||
bool isLocked; ///< True if the layer is locked
|
||||
bool isLightingLayer; ///< True if the layer is used to display lights and
|
||||
///< renders an ambient light.
|
||||
bool followBaseLayerCamera; ///< True if the layer automatically follows the
|
||||
///< base layer
|
||||
unsigned int ambientLightColorR; ///< Ambient light color Red component
|
||||
unsigned int ambientLightColorG; ///< Ambient light color Green component
|
||||
unsigned int ambientLightColorB; ///< Ambient light color Blue component
|
||||
std::vector<gd::Camera> cameras; ///< The camera displayed by the layer
|
||||
double camera3DNearPlaneDistance; ///< 3D camera frustum near plan distance
|
||||
double camera3DFarPlaneDistance; ///< 3D camera frustum far plan distance
|
||||
double camera3DFieldOfView; ///< 3D camera field of view (fov) in degrees
|
||||
unsigned int ambientLightColorR; ///< Ambient light color Red component
|
||||
unsigned int ambientLightColorG; ///< Ambient light color Green component
|
||||
unsigned int ambientLightColorB; ///< Ambient light color Blue component
|
||||
std::vector<gd::Camera> cameras; ///< The camera displayed by the layer
|
||||
gd::EffectsContainer effectsContainer; ///< The effects applied to the layer.
|
||||
|
||||
static gd::Camera badCamera;
|
||||
|
@@ -507,6 +507,44 @@ gd::String GD_CORE_API GetTypeOfObject(const gd::ObjectsContainer& project,
|
||||
return type;
|
||||
}
|
||||
|
||||
bool GD_CORE_API HasBehaviorInObjectOrGroup(const gd::ObjectsContainer &project,
|
||||
const gd::ObjectsContainer &layout,
|
||||
const gd::String &objectOrGroupName,
|
||||
const gd::String &behaviorName,
|
||||
bool searchInGroups) {
|
||||
// Search in objects
|
||||
if (layout.HasObjectNamed(objectOrGroupName)) {
|
||||
return layout.GetObject(objectOrGroupName).HasBehaviorNamed(behaviorName);
|
||||
}
|
||||
if (project.HasObjectNamed(objectOrGroupName)) {
|
||||
return project.GetObject(objectOrGroupName).HasBehaviorNamed(behaviorName);
|
||||
}
|
||||
|
||||
// Search in groups
|
||||
const gd::ObjectsContainer *container;
|
||||
if (layout.GetObjectGroups().Has(objectOrGroupName)) {
|
||||
container = &layout;
|
||||
} else if (project.GetObjectGroups().Has(objectOrGroupName)) {
|
||||
container = &project;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
const vector<gd::String> &groupsObjects =
|
||||
container->GetObjectGroups().Get(objectOrGroupName).GetAllObjectsNames();
|
||||
// Empty groups don't contain any behavior.
|
||||
if (groupsObjects.empty()) {
|
||||
return false;
|
||||
}
|
||||
// Check that all objects have the same type.
|
||||
for (auto &&object : groupsObjects) {
|
||||
if (!HasBehaviorInObjectOrGroup(project, layout, object, behaviorName,
|
||||
false)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
gd::String GD_CORE_API GetTypeOfBehavior(const gd::ObjectsContainer& project,
|
||||
const gd::ObjectsContainer& layout,
|
||||
gd::String name,
|
||||
|
@@ -442,7 +442,14 @@ gd::String GD_CORE_API GetTypeOfObject(const ObjectsContainer& game,
|
||||
const ObjectsContainer& layout,
|
||||
gd::String objectName,
|
||||
bool searchInGroups = true);
|
||||
|
||||
/**
|
||||
* \brief Check if an object or all object of a group has a behavior.
|
||||
*/
|
||||
bool GD_CORE_API HasBehaviorInObjectOrGroup(const gd::ObjectsContainer &project,
|
||||
const gd::ObjectsContainer &layout,
|
||||
const gd::String &objectOrGroupName,
|
||||
const gd::String &behaviorName,
|
||||
bool searchInGroups = true);
|
||||
/**
|
||||
* \brief Get a type from a behavior name
|
||||
* @return Type of the behavior.
|
||||
|
@@ -91,6 +91,8 @@ std::shared_ptr<Resource> ResourcesManager::CreateResource(
|
||||
return std::make_shared<TilesetResource>();
|
||||
else if (kind == "bitmapFont")
|
||||
return std::make_shared<BitmapFontResource>();
|
||||
else if (kind == "model3D")
|
||||
return std::make_shared<Model3DResource>();
|
||||
|
||||
std::cout << "Bad resource created (type: " << kind << ")" << std::endl;
|
||||
return std::make_shared<Resource>();
|
||||
@@ -736,6 +738,20 @@ void BitmapFontResource::SerializeTo(SerializerElement& element) const {
|
||||
element.SetAttribute("file", GetFile());
|
||||
}
|
||||
|
||||
void Model3DResource::SetFile(const gd::String& newFile) {
|
||||
file = NormalizePathSeparator(newFile);
|
||||
}
|
||||
|
||||
void Model3DResource::UnserializeFrom(const SerializerElement& element) {
|
||||
SetUserAdded(element.GetBoolAttribute("userAdded"));
|
||||
SetFile(element.GetStringAttribute("file"));
|
||||
}
|
||||
|
||||
void Model3DResource::SerializeTo(SerializerElement& element) const {
|
||||
element.SetAttribute("userAdded", IsUserAdded());
|
||||
element.SetAttribute("file", GetFile());
|
||||
}
|
||||
|
||||
ResourceFolder::ResourceFolder(const ResourceFolder& other) { Init(other); }
|
||||
|
||||
ResourceFolder& ResourceFolder::operator=(const ResourceFolder& other) {
|
||||
|
@@ -142,7 +142,7 @@ class GD_CORE_API Resource {
|
||||
virtual void SerializeTo(SerializerElement& element) const {};
|
||||
|
||||
/**
|
||||
* \brief Unserialize the objectt.
|
||||
* \brief Unserialize the object.
|
||||
*/
|
||||
virtual void UnserializeFrom(const SerializerElement& element){};
|
||||
|
||||
@@ -195,7 +195,7 @@ class GD_CORE_API ImageResource : public Resource {
|
||||
void SerializeTo(SerializerElement& element) const override;
|
||||
|
||||
/**
|
||||
* \brief Unserialize the objectt.
|
||||
* \brief Unserialize the object.
|
||||
*/
|
||||
void UnserializeFrom(const SerializerElement& element) override;
|
||||
|
||||
@@ -481,6 +481,32 @@ class GD_CORE_API BitmapFontResource : public Resource {
|
||||
gd::String file;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Describe a 3D model file used by a project.
|
||||
*
|
||||
* \see Resource
|
||||
* \ingroup ResourcesManagement
|
||||
*/
|
||||
class GD_CORE_API Model3DResource : public Resource {
|
||||
public:
|
||||
Model3DResource() : Resource() { SetKind("model3D"); };
|
||||
virtual ~Model3DResource(){};
|
||||
virtual Model3DResource* Clone() const override {
|
||||
return new Model3DResource(*this);
|
||||
}
|
||||
|
||||
virtual const gd::String& GetFile() const override { return file; };
|
||||
virtual void SetFile(const gd::String& newFile) override;
|
||||
|
||||
virtual bool UseFile() const override { return true; }
|
||||
void SerializeTo(SerializerElement& element) const override;
|
||||
|
||||
void UnserializeFrom(const SerializerElement& element) override;
|
||||
|
||||
private:
|
||||
gd::String file;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Inventory all resources used by a project
|
||||
*
|
||||
@@ -637,7 +663,7 @@ class GD_CORE_API ResourcesManager {
|
||||
void SerializeTo(SerializerElement& element) const;
|
||||
|
||||
/**
|
||||
* \brief Unserialize the objectt.
|
||||
* \brief Unserialize the object.
|
||||
*/
|
||||
void UnserializeFrom(const SerializerElement& element);
|
||||
|
||||
@@ -714,7 +740,7 @@ class GD_CORE_API ResourceFolder {
|
||||
void SerializeTo(SerializerElement& element) const;
|
||||
|
||||
/**
|
||||
* \brief Unserialize the objectt.
|
||||
* \brief Unserialize the object.
|
||||
*/
|
||||
void UnserializeFrom(const SerializerElement& element,
|
||||
gd::ResourcesManager& parentManager);
|
||||
|
@@ -2280,7 +2280,7 @@ public:
|
||||
//!@name Handling parse errors
|
||||
//!@{
|
||||
|
||||
//! Whether a parse error has occured in the last parsing.
|
||||
//! Whether a parse error has occurred in the last parsing.
|
||||
bool HasParseError() const { return parseResult_.IsError(); }
|
||||
|
||||
//! Get the \ref ParseErrorCode of last parsing.
|
||||
|
@@ -527,7 +527,7 @@ public:
|
||||
return Parse<kParseDefaultFlags>(is, handler);
|
||||
}
|
||||
|
||||
//! Whether a parse error has occured in the last parsing.
|
||||
//! Whether a parse error has occurred in the last parsing.
|
||||
bool HasParseError() const { return parseResult_.IsError(); }
|
||||
|
||||
//! Get the \ref ParseErrorCode of last parsing.
|
||||
|
@@ -584,32 +584,32 @@ public:
|
||||
String substr( size_type start = 0, size_type length = npos ) const;
|
||||
|
||||
/**
|
||||
* \return the position of the first occurence of **search** starting from **pos**.
|
||||
* \return the position of the first occurrence of **search** starting from **pos**.
|
||||
*/
|
||||
size_type find( const String &search, size_type pos = 0 ) const;
|
||||
|
||||
/**
|
||||
* \return the position of the first occurence of **search** starting from **pos**.
|
||||
* \return the position of the first occurrence of **search** starting from **pos**.
|
||||
*/
|
||||
size_type find( const char *search, size_type pos = 0 ) const;
|
||||
|
||||
/**
|
||||
* \return the position of the first occurence of **search** starting from **pos**.
|
||||
* \return the position of the first occurrence of **search** starting from **pos**.
|
||||
*/
|
||||
size_type find( const value_type search, size_type pos = 0 ) const;
|
||||
|
||||
/**
|
||||
* \return the position of the last occurence of **search** starting before **pos**.
|
||||
* \return the position of the last occurrence of **search** starting before **pos**.
|
||||
*/
|
||||
size_type rfind( const String &search, size_type pos = npos ) const;
|
||||
|
||||
/**
|
||||
* \return the position of the last occurence of **search** starting before **pos**.
|
||||
* \return the position of the last occurrence of **search** starting before **pos**.
|
||||
*/
|
||||
size_type rfind( const char *search, size_type pos = npos ) const;
|
||||
|
||||
/**
|
||||
* \return the position of the last occurence of **search** starting before **pos**.
|
||||
* \return the position of the last occurrence of **search** starting before **pos**.
|
||||
*/
|
||||
size_type rfind( const value_type &search, size_type pos = npos ) const;
|
||||
|
||||
@@ -658,7 +658,7 @@ public:
|
||||
|
||||
/**
|
||||
* \brief Do a case-insensitive search
|
||||
* \return the position of the first occurence of **search** starting from **pos**.
|
||||
* \return the position of the first occurrence of **search** starting from **pos**.
|
||||
*
|
||||
* \note This method isn't very efficient as it is linear on the string size times the
|
||||
* search string size
|
||||
|
10
Core/GDCore/TinyXml/tinyxml.h
vendored
10
Core/GDCore/TinyXml/tinyxml.h
vendored
@@ -577,7 +577,7 @@ public:
|
||||
#endif
|
||||
|
||||
/** Add a new node related to this. Adds a child past the LastChild.
|
||||
Returns a pointer to the new object or NULL if an error occured.
|
||||
Returns a pointer to the new object or NULL if an error occurred.
|
||||
*/
|
||||
TiXmlNode* InsertEndChild( const TiXmlNode& addThis );
|
||||
|
||||
@@ -594,17 +594,17 @@ public:
|
||||
TiXmlNode* LinkEndChild( TiXmlNode* addThis );
|
||||
|
||||
/** Add a new node related to this. Adds a child before the specified child.
|
||||
Returns a pointer to the new object or NULL if an error occured.
|
||||
Returns a pointer to the new object or NULL if an error occurred.
|
||||
*/
|
||||
TiXmlNode* InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis );
|
||||
|
||||
/** Add a new node related to this. Adds a child after the specified child.
|
||||
Returns a pointer to the new object or NULL if an error occured.
|
||||
Returns a pointer to the new object or NULL if an error occurred.
|
||||
*/
|
||||
TiXmlNode* InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis );
|
||||
|
||||
/** Replace a child of this node.
|
||||
Returns a pointer to the new object or NULL if an error occured.
|
||||
Returns a pointer to the new object or NULL if an error occurred.
|
||||
*/
|
||||
TiXmlNode* ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis );
|
||||
|
||||
@@ -1471,7 +1471,7 @@ public:
|
||||
@sa SetTabSize, Row, Column
|
||||
*/
|
||||
int ErrorRow() const { return errorLocation.row+1; }
|
||||
int ErrorCol() const { return errorLocation.col+1; } ///< The column where the error occured. See ErrorRow()
|
||||
int ErrorCol() const { return errorLocation.col+1; } ///< The column where the error occurred. See ErrorRow()
|
||||
|
||||
/** SetTabSize() allows the error reporting functions (ErrorRow() and ErrorCol())
|
||||
to report the correct values for row and column. It does not change the output
|
||||
|
@@ -99,7 +99,7 @@ Everything in GDevelop.js is meant to create a "bridge" allowing us to run and u
|
||||
|
||||
### I want all the gory details about GDevelop.js 🧐
|
||||
|
||||
All the required C++ files are imported into this huge list: https://github.com/4ian/GDevelop/blob/master/GDevelop.js/Bindings/Wrapper.cpp#L1-L79. C++ compilation is done with a "build system" called CMake, which is using [this file](https://github.com/4ian/GDevelop/blob/master/GDevelop.js/CMakeLists.txt#L82-L101) to see what to compile.
|
||||
All the required C++ files are imported into this huge list: <https://github.com/4ian/GDevelop/blob/master/GDevelop.js/Bindings/Wrapper.cpp#L1-L79>. C++ compilation is done with a "build system" called CMake, which is using [this file](https://github.com/4ian/GDevelop/blob/master/GDevelop.js/CMakeLists.txt#L82-L101) to see what to compile.
|
||||
|
||||
> In an ideal world, there would be something to do this automatically, so the GDevelop.js folder would not even exist 😉
|
||||
> If you're interested and want to know more about GDevelop.js bridging between C++ and JavaScript, look at [this talk from GDevelop original author](https://www.youtube.com/watch?v=6La7jSCnYyk).
|
||||
|
@@ -12,16 +12,16 @@ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
|
||||
External libraries used by GDevelop Core
|
@@ -6,7 +6,7 @@ GDevelop Core is a portable C++ library, compiled to be used in JavaScript in th
|
||||
|
||||
## 1) Getting started 🤓
|
||||
|
||||
First, take a look at the _Readme.md_ at the root of the repository and the [developer documentation](https://docs.gdevelop.io/).
|
||||
First, take a look at the _[README.md](../README.md)_ at the root of the repository and the [developer documentation](https://docs.gdevelop.io/).
|
||||
|
||||
## 2) How to contribute 😎
|
||||
|
||||
@@ -21,5 +21,5 @@ or any pull request so as to add a nice feature, do not hesitate to get in touch
|
||||
|
||||
## License
|
||||
|
||||
GDevelop Core is distributed under the MIT license: see license.txt for
|
||||
GDevelop Core is distributed under the MIT license: see [LICENSE.md](LICENSE.md) for
|
||||
more information.
|
||||
|
@@ -13,6 +13,8 @@
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Tools/Localization.h"
|
||||
#include "GDCore/Events/Builtin/StandardEvent.h"
|
||||
#include "GDCore/Extensions/Metadata/MultipleInstructionMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/ParameterOptions.h"
|
||||
#include "catch.hpp"
|
||||
|
||||
// TODO Remove these 2 classes and write the test with events based behaviors.
|
||||
@@ -122,6 +124,14 @@ void SetupProjectWithDummyPlatform(gd::Project& project,
|
||||
.AddParameter("expression", _("Number parameter"))
|
||||
.SetRequiresBaseObjectCapability("effect")
|
||||
.SetFunctionName("getSomethingRequiringEffectCapability");
|
||||
baseObject
|
||||
.AddExpression("GetFromBaseExpression",
|
||||
"This works on any object.",
|
||||
"",
|
||||
"",
|
||||
"")
|
||||
.AddParameter("object", _("Object"), "")
|
||||
.SetFunctionName("getFromBaseExpression");
|
||||
|
||||
// Create an extension with various stuff inside.
|
||||
std::shared_ptr<gd::PlatformExtension> extension =
|
||||
@@ -281,6 +291,21 @@ void SetupProjectWithDummyPlatform(gd::Project& project,
|
||||
.AddParameter("objectPtr", _("Object parameter"))
|
||||
.SetFunctionName("getObjectStringWith2ObjectParam");
|
||||
|
||||
// Actions and expressions with several parameter types.
|
||||
object
|
||||
.AddAction("SetAnimationName", _("Change the animation (by name)"),
|
||||
_("Change the animation of the object, using the name of the "
|
||||
"animation."),
|
||||
_("Set animation of _PARAM0_ to _PARAM1_"),
|
||||
_("Animations and images"), "", "")
|
||||
.AddParameter("object", _("Object"), "Sprite")
|
||||
.AddParameter("objectAnimationName", _("Animation name"));
|
||||
object
|
||||
.AddExpression("AnimationFrameCount", _("Animation frame count"),
|
||||
_("Return the number of frame in the animation."),
|
||||
_("Animations and images"), "")
|
||||
.AddParameter("object", _("Object"), "Sprite")
|
||||
.AddParameter("objectAnimationName", _("Animation name"));
|
||||
{
|
||||
auto& behavior =
|
||||
extension->AddBehavior("MyBehavior",
|
||||
@@ -381,6 +406,65 @@ void SetupProjectWithDummyPlatform(gd::Project& project,
|
||||
.AddUnsupportedBaseObjectCapability("effect");
|
||||
}
|
||||
|
||||
// Actions and expressions with several parameter types.
|
||||
{
|
||||
extension
|
||||
->AddAction("CreateObjectsFromExternalLayout",
|
||||
_("Create objects from an external layout"),
|
||||
_("Create objects from an external layout."),
|
||||
_("Create objects from the external layout named _PARAM1_"),
|
||||
"", "", "")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("externalLayoutName", _("Name of the external layout"))
|
||||
.AddParameter("expression", _("X position of the origin"), "", true)
|
||||
.SetDefaultValue("0")
|
||||
.AddParameter("expression", _("Y position of the origin"), "", true)
|
||||
.SetDefaultValue("0");
|
||||
|
||||
extension
|
||||
->AddAction("Scene", _("Change the scene"),
|
||||
_("Stop this scene and start the specified one instead."),
|
||||
_("Change to scene _PARAM1_"), "", "", "")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("sceneName", _("Name of the new scene"))
|
||||
.AddParameter("yesorno", _("Stop any other paused scenes?"))
|
||||
.SetDefaultValue("true");
|
||||
|
||||
extension
|
||||
->AddExpressionAndConditionAndAction(
|
||||
"number", "CameraCenterX", _("Camera center X position"),
|
||||
_("the X position of the center of a camera"),
|
||||
_("the X position of camera _PARAM4_ (layer: _PARAM3_)"), "", "")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.UseStandardParameters("number", gd::ParameterOptions::MakeNewOptions())
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
|
||||
.SetDefaultValue("\"\"");
|
||||
|
||||
extension
|
||||
->AddAction("EnableLayerEffect", _("Enable layer effect"),
|
||||
_("Enable an effect on a layer"),
|
||||
_("Enable effect _PARAM2_ on layer _PARAM1_: _PARAM3_"),
|
||||
_("Effects"), "", "")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
.AddParameter("layerEffectName", _("Effect name"))
|
||||
.AddParameter("yesorno", _("Enable"), "", true);
|
||||
|
||||
extension
|
||||
->AddExpression(
|
||||
"LayerEffectParameter",
|
||||
_("Effect parameter (number)"),
|
||||
_("Return the value of a parameter of an effect."),
|
||||
_("Effects"),
|
||||
"")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("layer", _("Layer (base layer if empty)"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
.AddParameter("layerEffectName", _("Effect name"))
|
||||
.AddParameter("layerEffectParameterName", _("Parameter name"));
|
||||
}
|
||||
|
||||
platform.AddExtension(commonInstructionsExtension);
|
||||
platform.AddExtension(baseObjectExtension);
|
||||
platform.AddExtension(extension);
|
||||
|
@@ -197,14 +197,14 @@ TEST_CASE("ExpressionNodeLocationFinder", "[common][events]") {
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Numbers and texts mismatchs") {
|
||||
SECTION("Numbers and texts mismatches") {
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::NumberNode>(parser, "12+\"hello\"", 0) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::NumberNode>(parser, "12+\"hello\"", 1) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::OperatorNode>(parser, "12+\"hello\"", 2) == true);
|
||||
REQUIRE(CheckNodeAtLocationIs<gd::TextNode>(parser, "12+\"hello\"", 3) == true);
|
||||
}
|
||||
|
||||
SECTION("Numbers and texts mismatchs (parent node)") {
|
||||
SECTION("Numbers and texts mismatches (parent node)") {
|
||||
REQUIRE(CheckParentNodeAtLocationIs<gd::OperatorNode>(parser, "12+\"hello\"", 0) == true);
|
||||
REQUIRE(CheckParentNodeAtLocationIs<gd::OperatorNode>(parser, "12+\"hello\"", 1) == true);
|
||||
REQUIRE(CheckNoParentNodeAtLocation(parser, "12+\"hello\"", 2) == true);
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -132,11 +132,11 @@ TEST_CASE("ExpressionParser2NodePrinter", "[common][events]") {
|
||||
testPrinter("number", "123 !!! 456", "123 ! !! 456");
|
||||
}
|
||||
|
||||
SECTION("Numbers and texts mismatchs") {
|
||||
SECTION("Numbers and texts mismatches") {
|
||||
testPrinter("number", "123 + \"hello world\"");
|
||||
testPrinter("string", "\"hello world\" + 123");
|
||||
}
|
||||
SECTION("Numbers and texts mismatchs with parenthesis") {
|
||||
SECTION("Numbers and texts mismatches with parenthesis") {
|
||||
testPrinter("number", "((123)) + (\"hello world\")");
|
||||
testPrinter("string", "((\"hello world\") + (123))");
|
||||
}
|
||||
|
@@ -56,6 +56,12 @@ GetEventFirstActionFirstParameterString(const gd::BaseEvent &event) {
|
||||
return actions.Get(0).GetParameter(0).GetPlainString();
|
||||
}
|
||||
|
||||
bool
|
||||
AreActionsEmpty(const gd::BaseEvent &event) {
|
||||
auto &actions = EnsureStandardEvent(event).GetActions();
|
||||
return actions.IsEmpty();
|
||||
}
|
||||
|
||||
const gd::String &GetEventFirstConditionType(const gd::BaseEvent &event) {
|
||||
auto &conditions = EnsureStandardEvent(event).GetConditions();
|
||||
REQUIRE(conditions.IsEmpty() == false);
|
||||
@@ -78,6 +84,8 @@ enum TestEvent {
|
||||
FreeActionWithOperator,
|
||||
FreeFunctionWithObjects,
|
||||
FreeFunctionWithObjectExpression,
|
||||
FreeFunctionWithGroup,
|
||||
FreeFunctionWithObjectExpressionOnGroup,
|
||||
|
||||
BehaviorAction,
|
||||
BehaviorPropertyAction,
|
||||
@@ -107,11 +115,18 @@ enum TestEvent {
|
||||
ObjectActionWithOperator,
|
||||
};
|
||||
|
||||
const std::vector<const gd::EventsList *> GetEventsLists(gd::Project &project) {
|
||||
const std::vector<const gd::EventsList *> GetEventsListsAssociatedToScene(gd::Project &project) {
|
||||
std::vector<const gd::EventsList *> eventLists;
|
||||
auto &scene = project.GetLayout("Scene").GetEvents();
|
||||
auto &externalEvents =
|
||||
project.GetExternalEvents("ExternalEvents").GetEvents();
|
||||
eventLists.push_back(&scene);
|
||||
eventLists.push_back(&externalEvents);
|
||||
return eventLists;
|
||||
}
|
||||
|
||||
const std::vector<const gd::EventsList *> GetEventsListsNotAssociatedToScene(gd::Project &project) {
|
||||
std::vector<const gd::EventsList *> eventLists;
|
||||
auto &eventsExtension = project.GetEventsFunctionsExtension("MyEventsExtension");
|
||||
auto &objectFunctionEvents =
|
||||
eventsExtension
|
||||
@@ -128,14 +143,24 @@ const std::vector<const gd::EventsList *> GetEventsLists(gd::Project &project) {
|
||||
.GetEvents();
|
||||
auto &freeFunctionEvents =
|
||||
eventsExtension.GetEventsFunction("MyOtherEventsFunction").GetEvents();
|
||||
eventLists.push_back(&scene);
|
||||
eventLists.push_back(&externalEvents);
|
||||
eventLists.push_back(&objectFunctionEvents);
|
||||
eventLists.push_back(&behaviorFunctionEvents);
|
||||
eventLists.push_back(&freeFunctionEvents);
|
||||
return eventLists;
|
||||
}
|
||||
|
||||
const std::vector<const gd::EventsList *> GetEventsLists(gd::Project &project) {
|
||||
std::vector<const gd::EventsList *> eventLists;
|
||||
|
||||
for (auto *eventsList : GetEventsListsAssociatedToScene(project)) {
|
||||
eventLists.push_back(eventsList);
|
||||
}
|
||||
for (auto *eventsList : GetEventsListsNotAssociatedToScene(project)) {
|
||||
eventLists.push_back(eventsList);
|
||||
}
|
||||
return eventLists;
|
||||
}
|
||||
|
||||
const void SetupEvents(gd::EventsList &eventList) {
|
||||
|
||||
// Add some free functions usages in events
|
||||
@@ -285,6 +310,38 @@ const void SetupEvents(gd::EventsList &eventList) {
|
||||
event.GetActions().Insert(action);
|
||||
eventList.InsertEvent(event);
|
||||
}
|
||||
|
||||
if (eventList.GetEventsCount() != FreeFunctionWithGroup) {
|
||||
throw std::logic_error("Invalid events setup: " + std::to_string(eventList.GetEventsCount()));
|
||||
}
|
||||
// Create an event referring to a group.
|
||||
{
|
||||
gd::StandardEvent event;
|
||||
gd::Instruction action;
|
||||
action.SetType("MyExtension::DoSomethingWithObjects");
|
||||
action.SetParametersCount(2);
|
||||
action.SetParameter(0, gd::Expression("GroupWithMyBehavior"));
|
||||
action.SetParameter(1, gd::Expression("MyCustomObject"));
|
||||
event.GetActions().Insert(action);
|
||||
eventList.InsertEvent(event);
|
||||
}
|
||||
|
||||
if (eventList.GetEventsCount() != FreeFunctionWithObjectExpressionOnGroup) {
|
||||
throw std::logic_error("Invalid events setup: " + std::to_string(eventList.GetEventsCount()));
|
||||
}
|
||||
// Create an event referring to a group in an expression.
|
||||
{
|
||||
gd::StandardEvent event;
|
||||
gd::Instruction action;
|
||||
action.SetType("MyExtension::DoSomething");
|
||||
action.SetParametersCount(1);
|
||||
action.SetParameter(
|
||||
0,
|
||||
gd::Expression(
|
||||
"GroupWithMyBehavior.GetObjectNumber()"));
|
||||
event.GetActions().Insert(action);
|
||||
eventList.InsertEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
// Add some events based behavior usages in events
|
||||
@@ -821,7 +878,7 @@ SetupProjectWithEventsFunctionExtension(gd::Project &project) {
|
||||
.SetExtraInfo("MyEventsExtension::MyEventsBasedBehavior"));
|
||||
behaviorAction.GetParameters().push_back(
|
||||
gd::ParameterMetadata()
|
||||
.SetName("OtherObject")
|
||||
.SetName("ObjectWithMyBehavior")
|
||||
.SetType("object")
|
||||
.SetExtraInfo("MyEventsExtension::MyEventsBasedObject"));
|
||||
behaviorAction.GetParameters().push_back(
|
||||
@@ -829,6 +886,8 @@ SetupProjectWithEventsFunctionExtension(gd::Project &project) {
|
||||
.SetName("OtherBehavior")
|
||||
.SetType("behavior")
|
||||
.SetExtraInfo("MyEventsExtension::MyEventsBasedBehavior"));
|
||||
auto &group = behaviorAction.GetObjectGroups().InsertNew("GroupWithMyBehavior");
|
||||
group.AddObject("ObjectWithMyBehavior");
|
||||
|
||||
auto &behaviorExpression =
|
||||
behaviorEventsFunctions
|
||||
@@ -1009,6 +1068,8 @@ SetupProjectWithEventsFunctionExtension(gd::Project &project) {
|
||||
auto &childObject = eventsBasedObject.InsertNewObject(
|
||||
project, "MyExtension::Sprite", "ObjectWithMyBehavior", 0);
|
||||
childObject.AddNewBehavior(project, "MyEventsExtension::MyEventsBasedBehavior", "MyBehavior");
|
||||
auto &group = eventsBasedObject.GetObjectGroups().InsertNew("GroupWithMyBehavior");
|
||||
group.AddObject(childObject.GetName());
|
||||
|
||||
eventsBasedObject.InsertNewObject(
|
||||
project, "MyEventsExtension::MyEventsBasedObject", "MyCustomObject", 1);
|
||||
@@ -1079,6 +1140,8 @@ SetupProjectWithEventsFunctionExtension(gd::Project &project) {
|
||||
.SetName("MyCustomObject")
|
||||
.SetType("object")
|
||||
.SetExtraInfo("MyEventsExtension::MyEventsBasedObject"));
|
||||
auto &group = action.GetObjectGroups().InsertNew("GroupWithMyBehavior");
|
||||
group.AddObject("ObjectWithMyBehavior");
|
||||
}
|
||||
|
||||
// Add some usages in events
|
||||
@@ -1091,6 +1154,8 @@ SetupProjectWithEventsFunctionExtension(gd::Project &project) {
|
||||
auto &object = layout.InsertNewObject(project, "MyExtension::Sprite",
|
||||
"ObjectWithMyBehavior", 0);
|
||||
object.AddNewBehavior(project, "MyEventsExtension::MyEventsBasedBehavior", "MyBehavior");
|
||||
auto &group = layout.GetObjectGroups().InsertNew("GroupWithMyBehavior", 0);
|
||||
group.AddObject("ObjectWithMyBehavior");
|
||||
|
||||
auto &globalObject = project.InsertNewObject(
|
||||
project, "MyExtension::Sprite", "GlobalObjectWithMyBehavior", 0);
|
||||
@@ -1229,6 +1294,29 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
|
||||
REQUIRE(externalLayout2.GetInitialInstances().HasInstancesOfObject(
|
||||
"GlobalObject1") == false);
|
||||
}
|
||||
|
||||
SECTION("Events") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &eventsExtension = SetupProjectWithEventsFunctionExtension(project);
|
||||
|
||||
auto &layout = project.GetLayout("Scene");
|
||||
|
||||
// Trigger the refactoring after removing an object
|
||||
gd::WholeProjectRefactorer::ObjectOrGroupRemovedInLayout(
|
||||
project, layout, "ObjectWithMyBehavior", /* isObjectGroup=*/false);
|
||||
|
||||
for (auto *eventsList : GetEventsListsAssociatedToScene(project)) {
|
||||
// Check actions with the object in parameters have been removed.
|
||||
REQUIRE(
|
||||
AreActionsEmpty(eventsList->GetEvent(FreeFunctionWithObjects)));
|
||||
|
||||
// Check actions with the object in expressions have been removed.
|
||||
REQUIRE(AreActionsEmpty(
|
||||
eventsList->GetEvent(FreeFunctionWithObjectExpression)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Object renamed (in layout)") {
|
||||
@@ -1347,7 +1435,7 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
|
||||
REQUIRE(externalLayout2.GetInitialInstances().HasInstancesOfObject(
|
||||
"GlobalObject3") == true);
|
||||
}
|
||||
|
||||
|
||||
SECTION("Events") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
@@ -1358,57 +1446,145 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
|
||||
|
||||
// Trigger the refactoring after the renaming of an object
|
||||
gd::WholeProjectRefactorer::ObjectOrGroupRenamedInLayout(
|
||||
project, layout, "ObjectWithMyBehavior", "RenamedObjectWithMyBehavior",
|
||||
project, layout, "ObjectWithMyBehavior",
|
||||
"RenamedObjectWithMyBehavior",
|
||||
/* isObjectGroup=*/false);
|
||||
|
||||
// Check object name has been renamed in action parameters.
|
||||
REQUIRE(GetEventFirstActionFirstParameterString(
|
||||
layout.GetEvents().GetEvent(FreeFunctionWithObjects)) ==
|
||||
"RenamedObjectWithMyBehavior");
|
||||
for (auto *eventsList : GetEventsListsAssociatedToScene(project)) {
|
||||
// Check object name has been renamed in action parameters.
|
||||
REQUIRE(GetEventFirstActionFirstParameterString(eventsList->GetEvent(
|
||||
FreeFunctionWithObjects)) == "RenamedObjectWithMyBehavior");
|
||||
|
||||
// Check object name has been renamed in expressions.
|
||||
REQUIRE(GetEventFirstActionFirstParameterString(
|
||||
layout.GetEvents().GetEvent(FreeFunctionWithObjectExpression)) ==
|
||||
// Check object name has been renamed in expressions.
|
||||
REQUIRE(GetEventFirstActionFirstParameterString(
|
||||
eventsList->GetEvent(FreeFunctionWithObjectExpression)) ==
|
||||
"RenamedObjectWithMyBehavior.GetObjectNumber()");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Group deleted (in layout)") {
|
||||
SECTION("Events") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &eventsExtension = SetupProjectWithEventsFunctionExtension(project);
|
||||
|
||||
auto &layout = project.GetLayout("Scene");
|
||||
|
||||
// Trigger the refactoring after removing a group
|
||||
gd::WholeProjectRefactorer::ObjectOrGroupRemovedInLayout(
|
||||
project, layout, "GroupWithMyBehavior", /* isObjectGroup=*/true);
|
||||
|
||||
for (auto *eventsList : GetEventsListsAssociatedToScene(project)) {
|
||||
// Check actions with the group in parameters have been removed.
|
||||
REQUIRE(AreActionsEmpty(eventsList->GetEvent(FreeFunctionWithGroup)));
|
||||
|
||||
// Check actions with the group in expressions have been removed.
|
||||
REQUIRE(AreActionsEmpty(
|
||||
eventsList->GetEvent(FreeFunctionWithObjectExpressionOnGroup)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Group renamed (in layout)") {
|
||||
SECTION("Events") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &eventsExtension = SetupProjectWithEventsFunctionExtension(project);
|
||||
|
||||
auto &layout = project.GetLayout("Scene");
|
||||
|
||||
// Trigger the refactoring after the renaming of a group
|
||||
gd::WholeProjectRefactorer::ObjectOrGroupRenamedInLayout(
|
||||
project, layout, "GroupWithMyBehavior", "RenamedGroupWithMyBehavior",
|
||||
/* isObjectGroup=*/true);
|
||||
|
||||
for (auto *eventsList : GetEventsListsAssociatedToScene(project)) {
|
||||
// Check group name has been renamed in action parameters.
|
||||
REQUIRE(GetEventFirstActionFirstParameterString(eventsList->GetEvent(
|
||||
FreeFunctionWithGroup)) == "RenamedGroupWithMyBehavior");
|
||||
|
||||
// Check group name has been renamed in expressions.
|
||||
REQUIRE(GetEventFirstActionFirstParameterString(eventsList->GetEvent(
|
||||
FreeFunctionWithObjectExpressionOnGroup)) ==
|
||||
"RenamedGroupWithMyBehavior.GetObjectNumber()");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Object renamed (in events function)") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &eventsExtension =
|
||||
project.InsertNewEventsFunctionsExtension("MyEventsExtension", 0);
|
||||
SECTION("Group") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &eventsExtension =
|
||||
project.InsertNewEventsFunctionsExtension("MyEventsExtension", 0);
|
||||
|
||||
// Add a (free) function with an object group
|
||||
gd::EventsFunction &eventsFunction =
|
||||
eventsExtension.InsertNewEventsFunction("MyEventsFunction", 0);
|
||||
gd::ObjectGroup &objectGroup =
|
||||
eventsFunction.GetObjectGroups().InsertNew("MyGroup", 0);
|
||||
objectGroup.AddObject("Object1");
|
||||
objectGroup.AddObject("Object2");
|
||||
// In theory, we would add the object parameters, but we're not testing
|
||||
// events in this test.
|
||||
// Add a (free) function with an object group
|
||||
gd::EventsFunction &eventsFunction =
|
||||
eventsExtension.InsertNewEventsFunction("MyEventsFunction", 0);
|
||||
gd::ObjectGroup &objectGroup =
|
||||
eventsFunction.GetObjectGroups().InsertNew("MyGroup", 0);
|
||||
objectGroup.AddObject("Object1");
|
||||
objectGroup.AddObject("Object2");
|
||||
// In theory, we would add the object parameters, but we're not testing
|
||||
// events in this test.
|
||||
|
||||
// Create the objects container for the events function
|
||||
gd::ObjectsContainer globalObjectsContainer;
|
||||
gd::ObjectsContainer objectsContainer;
|
||||
gd::ParameterMetadataTools::ParametersToObjectsContainer(
|
||||
project, eventsFunction.GetParameters(), objectsContainer);
|
||||
// (this is strictly not necessary because we're not testing events in this
|
||||
// test)
|
||||
// Create the objects container for the events function
|
||||
gd::ObjectsContainer globalObjectsContainer;
|
||||
gd::ObjectsContainer objectsContainer;
|
||||
gd::ParameterMetadataTools::ParametersToObjectsContainer(
|
||||
project, eventsFunction.GetParameters(), objectsContainer);
|
||||
// (this is strictly not necessary because we're not testing events in
|
||||
// this test)
|
||||
|
||||
// Trigger the refactoring after the renaming of an object
|
||||
gd::WholeProjectRefactorer::ObjectOrGroupRenamedInEventsFunction(
|
||||
project, eventsFunction, globalObjectsContainer, objectsContainer,
|
||||
"Object1", "RenamedObject1",
|
||||
/* isObjectGroup=*/false);
|
||||
// Trigger the refactoring after the renaming of an object
|
||||
gd::WholeProjectRefactorer::ObjectOrGroupRenamedInEventsFunction(
|
||||
project, eventsFunction, globalObjectsContainer, objectsContainer,
|
||||
"Object1", "RenamedObject1",
|
||||
/* isObjectGroup=*/false);
|
||||
|
||||
REQUIRE(objectGroup.Find("Object1") == false);
|
||||
REQUIRE(objectGroup.Find("RenamedObject1") == true);
|
||||
REQUIRE(objectGroup.Find("Object2") == true);
|
||||
REQUIRE(objectGroup.Find("Object1") == false);
|
||||
REQUIRE(objectGroup.Find("RenamedObject1") == true);
|
||||
REQUIRE(objectGroup.Find("Object2") == true);
|
||||
|
||||
// Events are not tested
|
||||
// Events are not tested
|
||||
}
|
||||
|
||||
SECTION("Events") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &eventsExtension = SetupProjectWithEventsFunctionExtension(project);
|
||||
auto &eventsFunction =
|
||||
eventsExtension.GetEventsFunction("MyOtherEventsFunction");
|
||||
|
||||
// Create the objects container for the events function
|
||||
gd::ObjectsContainer globalObjectsContainer;
|
||||
gd::ObjectsContainer objectsContainer;
|
||||
gd::ParameterMetadataTools::ParametersToObjectsContainer(
|
||||
project, eventsFunction.GetParameters(), objectsContainer);
|
||||
|
||||
// Trigger the refactoring after the renaming of an object
|
||||
gd::WholeProjectRefactorer::ObjectOrGroupRenamedInEventsFunction(
|
||||
project, eventsFunction, globalObjectsContainer, objectsContainer,
|
||||
"ObjectWithMyBehavior", "RenamedObjectWithMyBehavior",
|
||||
/* isObjectGroup=*/false);
|
||||
|
||||
// Check object name has been renamed in action parameters.
|
||||
REQUIRE(
|
||||
GetEventFirstActionFirstParameterString(
|
||||
eventsFunction.GetEvents().GetEvent(FreeFunctionWithObjects)) ==
|
||||
"RenamedObjectWithMyBehavior");
|
||||
|
||||
// Check object name has been renamed in expressions.
|
||||
REQUIRE(GetEventFirstActionFirstParameterString(
|
||||
eventsFunction.GetEvents().GetEvent(
|
||||
FreeFunctionWithObjectExpression)) ==
|
||||
"RenamedObjectWithMyBehavior.GetObjectNumber()");
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Object renamed (in events-based object)") {
|
||||
@@ -3060,3 +3236,426 @@ TEST_CASE("WholeProjectRefactorer (FindDependentBehaviorNames failing cases)",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("RenameExternalEvents", "[common]") {
|
||||
SECTION("Can update an event link to external events") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
project.AddPlatform(platform);
|
||||
|
||||
auto &layout = project.InsertNewLayout("My layout", 0);
|
||||
auto &externalLayout =
|
||||
project.InsertNewExternalLayout("My external layout", 0);
|
||||
externalLayout.SetAssociatedLayout("My layout");
|
||||
auto &externalEvents =
|
||||
project.InsertNewExternalEvents("My external events", 0);
|
||||
externalEvents.SetAssociatedLayout("My layout");
|
||||
|
||||
auto &events = layout.GetEvents();
|
||||
gd::LinkEvent event;
|
||||
event.SetTarget("My external events");
|
||||
gd::LinkEvent &linkEvent =
|
||||
dynamic_cast<gd::LinkEvent &>(events.InsertEvent(event));
|
||||
|
||||
gd::WholeProjectRefactorer::RenameExternalEvents(
|
||||
project, "My external events", "My renamed external events");
|
||||
|
||||
REQUIRE(linkEvent.GetTarget() == "My renamed external events");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("RenameExternalLayout", "[common]") {
|
||||
SECTION("Can update external layout names in parameters") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
|
||||
auto &layout = project.InsertNewLayout("My layout", 0);
|
||||
auto &externalLayout =
|
||||
project.InsertNewExternalLayout("My external layout", 0);
|
||||
externalLayout.SetAssociatedLayout("My layout");
|
||||
auto &externalEvents =
|
||||
project.InsertNewExternalEvents("My external events", 0);
|
||||
externalEvents.SetAssociatedLayout("My layout");
|
||||
|
||||
auto &events = layout.GetEvents();
|
||||
gd::StandardEvent &event = dynamic_cast<gd::StandardEvent &>(
|
||||
events.InsertNewEvent(project, "BuiltinCommonInstructions::Standard"));
|
||||
|
||||
gd::Instruction action;
|
||||
action.SetType("MyExtension::CreateObjectsFromExternalLayout");
|
||||
action.SetParametersCount(2);
|
||||
action.SetParameter(1, gd::Expression("\"My external layout\""));
|
||||
event.GetActions().Insert(action);
|
||||
|
||||
gd::WholeProjectRefactorer::RenameExternalLayout(
|
||||
project, "My external layout", "My renamed external layout");
|
||||
|
||||
REQUIRE(event.GetActions().at(0).GetParameter(1).GetPlainString() ==
|
||||
"\"My renamed external layout\"");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("RenameLayout", "[common]") {
|
||||
SECTION("Can update layout names in parameters and external targets") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
|
||||
auto &layout = project.InsertNewLayout("My layout", 0);
|
||||
auto &externalLayout =
|
||||
project.InsertNewExternalLayout("My external layout", 0);
|
||||
externalLayout.SetAssociatedLayout("My layout");
|
||||
auto &externalEvents =
|
||||
project.InsertNewExternalEvents("My external events", 0);
|
||||
externalEvents.SetAssociatedLayout("My layout");
|
||||
|
||||
auto &events = layout.GetEvents();
|
||||
gd::StandardEvent &event0 = dynamic_cast<gd::StandardEvent &>(
|
||||
events.InsertNewEvent(project, "BuiltinCommonInstructions::Standard"));
|
||||
|
||||
gd::Instruction action;
|
||||
action.SetType("MyExtension::Scene");
|
||||
action.SetParametersCount(2);
|
||||
action.SetParameter(1, gd::Expression("\"My layout\""));
|
||||
event0.GetActions().Insert(action);
|
||||
|
||||
gd::LinkEvent event1;
|
||||
event1.SetTarget("My layout");
|
||||
gd::LinkEvent &linkEvent =
|
||||
dynamic_cast<gd::LinkEvent &>(events.InsertEvent(event1));
|
||||
|
||||
gd::WholeProjectRefactorer::RenameLayout(project, "My layout",
|
||||
"My renamed layout");
|
||||
|
||||
REQUIRE(event0.GetActions().at(0).GetParameter(1).GetPlainString() ==
|
||||
"\"My renamed layout\"");
|
||||
REQUIRE(linkEvent.GetTarget() == "My renamed layout");
|
||||
REQUIRE(externalLayout.GetAssociatedLayout() == "My renamed layout");
|
||||
REQUIRE(externalEvents.GetAssociatedLayout() == "My renamed layout");
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
const gd::Instruction &CreateActionWithLayerParameter(gd::Project &project,
|
||||
gd::EventsList &events) {
|
||||
gd::StandardEvent &event = dynamic_cast<gd::StandardEvent &>(
|
||||
events.InsertNewEvent(project, "BuiltinCommonInstructions::Standard"));
|
||||
|
||||
gd::Instruction action;
|
||||
action.SetType("MyExtension::SetCameraCenterX");
|
||||
action.SetParametersCount(4);
|
||||
action.SetParameter(3, gd::Expression("\"My layer\""));
|
||||
return event.GetActions().Insert(action);
|
||||
}
|
||||
|
||||
const gd::Instruction &
|
||||
CreateExpressionWithLayerParameter(gd::Project &project,
|
||||
gd::EventsList &events) {
|
||||
gd::StandardEvent &event = dynamic_cast<gd::StandardEvent &>(
|
||||
events.InsertNewEvent(project, "BuiltinCommonInstructions::Standard"));
|
||||
|
||||
gd::Instruction action;
|
||||
action.SetType("MyExtension::DoSomething");
|
||||
action.SetParametersCount(1);
|
||||
action.SetParameter(
|
||||
0, gd::Expression("MyExtension::CameraCenterX(\"My layer\") + "
|
||||
"MyExtension::CameraCenterX(\"My layer\")"));
|
||||
return event.GetActions().Insert(action);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("RenameLayer", "[common]") {
|
||||
SECTION("Can update layer names in events") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
|
||||
auto &layout = project.InsertNewLayout("My layout", 0);
|
||||
auto &otherLayout = project.InsertNewLayout("My other layout", 1);
|
||||
auto &externalEvents =
|
||||
project.InsertNewExternalEvents("My external events", 0);
|
||||
externalEvents.SetAssociatedLayout("My layout");
|
||||
auto &otherExternalEvents =
|
||||
project.InsertNewExternalEvents("My external events", 0);
|
||||
otherExternalEvents.SetAssociatedLayout("My other layout");
|
||||
|
||||
auto &layoutAction =
|
||||
CreateActionWithLayerParameter(project, layout.GetEvents());
|
||||
auto &externalAction =
|
||||
CreateActionWithLayerParameter(project, externalEvents.GetEvents());
|
||||
auto &otherLayoutAction =
|
||||
CreateActionWithLayerParameter(project, otherLayout.GetEvents());
|
||||
auto &otherExternalAction = CreateActionWithLayerParameter(
|
||||
project, otherExternalEvents.GetEvents());
|
||||
|
||||
auto &layoutExpression =
|
||||
CreateExpressionWithLayerParameter(project, layout.GetEvents());
|
||||
auto &externalExpression =
|
||||
CreateExpressionWithLayerParameter(project, externalEvents.GetEvents());
|
||||
auto &otherLayoutExpression =
|
||||
CreateExpressionWithLayerParameter(project, otherLayout.GetEvents());
|
||||
auto &otherExternalExpression = CreateExpressionWithLayerParameter(
|
||||
project, otherExternalEvents.GetEvents());
|
||||
|
||||
gd::WholeProjectRefactorer::RenameLayer(project, layout, "My layer",
|
||||
"My renamed layer");
|
||||
|
||||
REQUIRE(layoutAction.GetParameter(3).GetPlainString() ==
|
||||
"\"My renamed layer\"");
|
||||
REQUIRE(externalAction.GetParameter(3).GetPlainString() ==
|
||||
"\"My renamed layer\"");
|
||||
// The event from the other layout are untouched.
|
||||
REQUIRE(otherLayoutAction.GetParameter(3).GetPlainString() ==
|
||||
"\"My layer\"");
|
||||
REQUIRE(otherExternalAction.GetParameter(3).GetPlainString() ==
|
||||
"\"My layer\"");
|
||||
|
||||
REQUIRE(layoutExpression.GetParameter(0).GetPlainString() ==
|
||||
"MyExtension::CameraCenterX(\"My renamed layer\") + "
|
||||
"MyExtension::CameraCenterX(\"My renamed layer\")");
|
||||
REQUIRE(externalExpression.GetParameter(0).GetPlainString() ==
|
||||
"MyExtension::CameraCenterX(\"My renamed layer\") + "
|
||||
"MyExtension::CameraCenterX(\"My renamed layer\")");
|
||||
// The event from the other layout are untouched.
|
||||
REQUIRE(otherLayoutExpression.GetParameter(0).GetPlainString() ==
|
||||
"MyExtension::CameraCenterX(\"My layer\") + "
|
||||
"MyExtension::CameraCenterX(\"My layer\")");
|
||||
REQUIRE(otherExternalExpression.GetParameter(0).GetPlainString() ==
|
||||
"MyExtension::CameraCenterX(\"My layer\") + "
|
||||
"MyExtension::CameraCenterX(\"My layer\")");
|
||||
}
|
||||
|
||||
SECTION("Can update layer names in expressions with a smaller name") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
|
||||
auto &layout = project.InsertNewLayout("My layout", 0);
|
||||
|
||||
auto &layoutExpression =
|
||||
CreateExpressionWithLayerParameter(project, layout.GetEvents());
|
||||
|
||||
gd::WholeProjectRefactorer::RenameLayer(project, layout, "My layer",
|
||||
"layerA");
|
||||
|
||||
REQUIRE(layoutExpression.GetParameter(0).GetPlainString() ==
|
||||
"MyExtension::CameraCenterX(\"layerA\") + "
|
||||
"MyExtension::CameraCenterX(\"layerA\")");
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
const gd::Instruction &CreateActionWithAnimationParameter(gd::Project &project,
|
||||
gd::EventsList &events,
|
||||
const gd::String &objectName) {
|
||||
gd::StandardEvent &event = dynamic_cast<gd::StandardEvent &>(
|
||||
events.InsertNewEvent(project, "BuiltinCommonInstructions::Standard"));
|
||||
|
||||
gd::Instruction action;
|
||||
action.SetType("MyExtension::SetAnimationName");
|
||||
action.SetParametersCount(2);
|
||||
action.SetParameter(0, objectName);
|
||||
action.SetParameter(1, gd::Expression("\"My animation\""));
|
||||
return event.GetActions().Insert(action);
|
||||
}
|
||||
|
||||
const gd::Instruction &
|
||||
CreateExpressionWithAnimationParameter(gd::Project &project,
|
||||
gd::EventsList &events,
|
||||
const gd::String &objectName) {
|
||||
gd::StandardEvent &event = dynamic_cast<gd::StandardEvent &>(
|
||||
events.InsertNewEvent(project, "BuiltinCommonInstructions::Standard"));
|
||||
|
||||
gd::Instruction action;
|
||||
action.SetType("MyExtension::DoSomething");
|
||||
action.SetParametersCount(1);
|
||||
action.SetParameter(
|
||||
0, gd::Expression(objectName + ".AnimationFrameCount(\"My animation\") + " +
|
||||
objectName + ".AnimationFrameCount(\"My animation\")"));
|
||||
return event.GetActions().Insert(action);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("RenameObjectAnimation", "[common]") {
|
||||
SECTION("Can update object animation names in event") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
|
||||
auto &layout = project.InsertNewLayout("My layout", 0);
|
||||
auto &otherLayout = project.InsertNewLayout("My other layout", 1);
|
||||
auto &externalEvents =
|
||||
project.InsertNewExternalEvents("My external events", 0);
|
||||
externalEvents.SetAssociatedLayout("My layout");
|
||||
auto &otherExternalEvents =
|
||||
project.InsertNewExternalEvents("My external events", 0);
|
||||
otherExternalEvents.SetAssociatedLayout("My other layout");
|
||||
auto &object = layout.InsertNewObject(project, "MyExtension::Sprite", "MySprite", 0);
|
||||
layout.InsertNewObject(project, "MyExtension::Sprite", "MySprite2", 1);
|
||||
otherLayout.InsertNewObject(project, "MyExtension::Sprite", "MySprite", 0);
|
||||
|
||||
auto &layoutAction =
|
||||
CreateActionWithAnimationParameter(project, layout.GetEvents(), "MySprite");
|
||||
auto &externalAction =
|
||||
CreateActionWithAnimationParameter(project, externalEvents.GetEvents(), "MySprite");
|
||||
auto &otherLayoutAction =
|
||||
CreateActionWithAnimationParameter(project, otherLayout.GetEvents(), "MySprite");
|
||||
auto &otherExternalAction = CreateActionWithAnimationParameter(
|
||||
project, otherExternalEvents.GetEvents(), "MySprite");
|
||||
auto &wrongObjectAction =
|
||||
CreateActionWithAnimationParameter(project, layout.GetEvents(), "MySprite2");
|
||||
|
||||
auto &layoutExpression =
|
||||
CreateExpressionWithAnimationParameter(project, layout.GetEvents(), "MySprite");
|
||||
auto &externalExpression =
|
||||
CreateExpressionWithAnimationParameter(project, externalEvents.GetEvents(), "MySprite");
|
||||
auto &otherLayoutExpression =
|
||||
CreateExpressionWithAnimationParameter(project, otherLayout.GetEvents(), "MySprite");
|
||||
auto &otherExternalExpression = CreateExpressionWithAnimationParameter(
|
||||
project, otherExternalEvents.GetEvents(), "MySprite");
|
||||
auto &wrongObjectExpression =
|
||||
CreateExpressionWithAnimationParameter(project, layout.GetEvents(), "MySprite2");
|
||||
|
||||
gd::WholeProjectRefactorer::RenameObjectAnimation(project, layout, object, "My animation",
|
||||
"My renamed animation");
|
||||
|
||||
REQUIRE(layoutAction.GetParameter(1).GetPlainString() ==
|
||||
"\"My renamed animation\"");
|
||||
REQUIRE(externalAction.GetParameter(1).GetPlainString() ==
|
||||
"\"My renamed animation\"");
|
||||
// The event from the other layout are untouched.
|
||||
REQUIRE(otherLayoutAction.GetParameter(1).GetPlainString() ==
|
||||
"\"My animation\"");
|
||||
REQUIRE(otherExternalAction.GetParameter(1).GetPlainString() ==
|
||||
"\"My animation\"");
|
||||
REQUIRE(wrongObjectAction.GetParameter(1).GetPlainString() ==
|
||||
"\"My animation\"");
|
||||
|
||||
REQUIRE(layoutExpression.GetParameter(0).GetPlainString() ==
|
||||
"MySprite.AnimationFrameCount(\"My renamed animation\") + "
|
||||
"MySprite.AnimationFrameCount(\"My renamed animation\")");
|
||||
REQUIRE(externalExpression.GetParameter(0).GetPlainString() ==
|
||||
"MySprite.AnimationFrameCount(\"My renamed animation\") + "
|
||||
"MySprite.AnimationFrameCount(\"My renamed animation\")");
|
||||
// The event from the other layout are untouched.
|
||||
REQUIRE(otherLayoutExpression.GetParameter(0).GetPlainString() ==
|
||||
"MySprite.AnimationFrameCount(\"My animation\") + "
|
||||
"MySprite.AnimationFrameCount(\"My animation\")");
|
||||
REQUIRE(otherExternalExpression.GetParameter(0).GetPlainString() ==
|
||||
"MySprite.AnimationFrameCount(\"My animation\") + "
|
||||
"MySprite.AnimationFrameCount(\"My animation\")");
|
||||
REQUIRE(wrongObjectExpression.GetParameter(0).GetPlainString() ==
|
||||
"MySprite2.AnimationFrameCount(\"My animation\") + "
|
||||
"MySprite2.AnimationFrameCount(\"My animation\")");
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
const gd::Instruction &CreateActionWithLayerEffectParameter(gd::Project &project,
|
||||
gd::EventsList &events,
|
||||
const gd::String &layerName) {
|
||||
gd::StandardEvent &event = dynamic_cast<gd::StandardEvent &>(
|
||||
events.InsertNewEvent(project, "BuiltinCommonInstructions::Standard"));
|
||||
|
||||
gd::Instruction action;
|
||||
action.SetType("MyExtension::EnableLayerEffect");
|
||||
action.SetParametersCount(3);
|
||||
action.SetParameter(1, gd::Expression("\"" + layerName + "\""));
|
||||
action.SetParameter(2, gd::Expression("\"My effect\""));
|
||||
return event.GetActions().Insert(action);
|
||||
}
|
||||
|
||||
const gd::Instruction &
|
||||
CreateExpressionWithLayerEffectParameter(gd::Project &project,
|
||||
gd::EventsList &events,
|
||||
const gd::String &layerName) {
|
||||
gd::StandardEvent &event = dynamic_cast<gd::StandardEvent &>(
|
||||
events.InsertNewEvent(project, "BuiltinCommonInstructions::Standard"));
|
||||
|
||||
gd::Instruction action;
|
||||
action.SetType("MyExtension::DoSomething");
|
||||
action.SetParametersCount(1);
|
||||
action.SetParameter(
|
||||
0, gd::Expression("MyExtension::LayerEffectParameter(\"" + layerName + "\", \"My effect\") + "
|
||||
"MyExtension::LayerEffectParameter(\"" + layerName + "\", \"My effect\")"));
|
||||
return event.GetActions().Insert(action);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("RenameLayerEffect", "[common]") {
|
||||
SECTION("Can update layer effect names in event") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
|
||||
auto &layout = project.InsertNewLayout("My layout", 0);
|
||||
layout.InsertNewLayer("My layer", 0);
|
||||
auto &layer = layout.GetLayer("My layer");
|
||||
auto &otherLayout = project.InsertNewLayout("My other layout", 1);
|
||||
auto &externalEvents =
|
||||
project.InsertNewExternalEvents("My external events", 0);
|
||||
externalEvents.SetAssociatedLayout("My layout");
|
||||
auto &otherExternalEvents =
|
||||
project.InsertNewExternalEvents("My external events", 0);
|
||||
otherExternalEvents.SetAssociatedLayout("My other layout");
|
||||
auto &object = layout.InsertNewObject(project, "MyExtension::Sprite", "MySprite", 0);
|
||||
layout.InsertNewObject(project, "MyExtension::Sprite", "MySprite2", 1);
|
||||
otherLayout.InsertNewObject(project, "MyExtension::Sprite", "MySprite", 0);
|
||||
|
||||
auto &layoutAction =
|
||||
CreateActionWithLayerEffectParameter(project, layout.GetEvents(), "My layer");
|
||||
auto &externalAction =
|
||||
CreateActionWithLayerEffectParameter(project, externalEvents.GetEvents(), "My layer");
|
||||
auto &otherLayoutAction =
|
||||
CreateActionWithLayerEffectParameter(project, otherLayout.GetEvents(), "My layer");
|
||||
auto &otherExternalAction = CreateActionWithLayerEffectParameter(
|
||||
project, otherExternalEvents.GetEvents(), "My layer");
|
||||
auto &wrongLayerAction =
|
||||
CreateActionWithLayerEffectParameter(project, layout.GetEvents(), "My layer 2");
|
||||
|
||||
auto &layoutExpression =
|
||||
CreateExpressionWithLayerEffectParameter(project, layout.GetEvents(), "My layer");
|
||||
auto &externalExpression =
|
||||
CreateExpressionWithLayerEffectParameter(project, externalEvents.GetEvents(), "My layer");
|
||||
auto &otherLayoutExpression =
|
||||
CreateExpressionWithLayerEffectParameter(project, otherLayout.GetEvents(), "My layer");
|
||||
auto &otherExternalExpression = CreateExpressionWithLayerEffectParameter(
|
||||
project, otherExternalEvents.GetEvents(), "My layer");
|
||||
auto &wrongLayerExpression =
|
||||
CreateExpressionWithLayerEffectParameter(project, layout.GetEvents(), "My layer 2");
|
||||
|
||||
std::cout << "RenameLayerEffect" << std::endl;
|
||||
gd::WholeProjectRefactorer::RenameLayerEffect(project, layout, layer, "My effect",
|
||||
"My renamed effect");
|
||||
|
||||
REQUIRE(layoutAction.GetParameter(2).GetPlainString() ==
|
||||
"\"My renamed effect\"");
|
||||
REQUIRE(externalAction.GetParameter(2).GetPlainString() ==
|
||||
"\"My renamed effect\"");
|
||||
// The event from the other layout are untouched.
|
||||
REQUIRE(otherLayoutAction.GetParameter(2).GetPlainString() ==
|
||||
"\"My effect\"");
|
||||
REQUIRE(otherExternalAction.GetParameter(2).GetPlainString() ==
|
||||
"\"My effect\"");
|
||||
REQUIRE(wrongLayerAction.GetParameter(2).GetPlainString() ==
|
||||
"\"My effect\"");
|
||||
|
||||
REQUIRE(layoutExpression.GetParameter(0).GetPlainString() ==
|
||||
"MyExtension::LayerEffectParameter(\"My layer\", \"My renamed effect\") + "
|
||||
"MyExtension::LayerEffectParameter(\"My layer\", \"My renamed effect\")");
|
||||
REQUIRE(externalExpression.GetParameter(0).GetPlainString() ==
|
||||
"MyExtension::LayerEffectParameter(\"My layer\", \"My renamed effect\") + "
|
||||
"MyExtension::LayerEffectParameter(\"My layer\", \"My renamed effect\")");
|
||||
// The event from the other layout are untouched.
|
||||
REQUIRE(otherLayoutExpression.GetParameter(0).GetPlainString() ==
|
||||
"MyExtension::LayerEffectParameter(\"My layer\", \"My effect\") + "
|
||||
"MyExtension::LayerEffectParameter(\"My layer\", \"My effect\")");
|
||||
REQUIRE(otherExternalExpression.GetParameter(0).GetPlainString() ==
|
||||
"MyExtension::LayerEffectParameter(\"My layer\", \"My effect\") + "
|
||||
"MyExtension::LayerEffectParameter(\"My layer\", \"My effect\")");
|
||||
REQUIRE(wrongLayerExpression.GetParameter(0).GetPlainString() ==
|
||||
"MyExtension::LayerEffectParameter(\"My layer 2\", \"My effect\") + "
|
||||
"MyExtension::LayerEffectParameter(\"My layer 2\", \"My effect\")");
|
||||
}
|
||||
}
|
||||
|
474
Extensions/3D/A_RuntimeObject3D.ts
Normal file
474
Extensions/3D/A_RuntimeObject3D.ts
Normal file
@@ -0,0 +1,474 @@
|
||||
namespace gdjs {
|
||||
export interface Object3DDataContent {
|
||||
width: float;
|
||||
height: float;
|
||||
depth: float;
|
||||
}
|
||||
/** Base parameters for {@link gdjs.RuntimeObject3D} */
|
||||
export interface Object3DData extends ObjectData {
|
||||
/** The base parameters of the RuntimeObject3D */
|
||||
content: Object3DDataContent;
|
||||
}
|
||||
|
||||
const getValidDimensionValue = (value: float | undefined) =>
|
||||
value === undefined ? 100 : value <= 0 ? 1 : value;
|
||||
|
||||
/**
|
||||
* Base class for 3D objects.
|
||||
*/
|
||||
export abstract class RuntimeObject3D extends gdjs.RuntimeObject {
|
||||
/**
|
||||
* Position on the Z axis.
|
||||
*/
|
||||
private _z: float = 0;
|
||||
/**
|
||||
* `_width` takes this value when the scale equals 1.
|
||||
*
|
||||
* It can't be 0.
|
||||
*/
|
||||
private _originalWidth: float;
|
||||
/**
|
||||
* `_height` takes this value when the scale equals 1.
|
||||
*
|
||||
* It can't be 0.
|
||||
*/
|
||||
private _originalHeight: float;
|
||||
/**
|
||||
* `depth` takes this value when the scale equals 1.
|
||||
*
|
||||
* It can't be 0.
|
||||
*/
|
||||
private _originalDepth: float;
|
||||
private _width: float;
|
||||
private _height: float;
|
||||
private _depth: float;
|
||||
private _flippedX: boolean = false;
|
||||
private _flippedY: boolean = false;
|
||||
private _flippedZ: boolean = false;
|
||||
/**
|
||||
* Euler angle with the `ZYX` order.
|
||||
*
|
||||
* Note that `_rotationZ` is `angle` from `gdjs.RuntimeObject`.
|
||||
*/
|
||||
private _rotationX: float = 0;
|
||||
/**
|
||||
* Euler angle with the `ZYX` order.
|
||||
*
|
||||
* Note that `_rotationZ` is `angle` from `gdjs.RuntimeObject`.
|
||||
*/
|
||||
private _rotationY: float = 0;
|
||||
private static _temporaryVector = new THREE.Vector3();
|
||||
|
||||
constructor(
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
objectData: Object3DData
|
||||
) {
|
||||
super(instanceContainer, objectData);
|
||||
// TODO Should 0 be replaced by 0.01 instead of using the default value?
|
||||
this._width = this._originalWidth = getValidDimensionValue(
|
||||
objectData.content.width
|
||||
);
|
||||
this._height = this._originalHeight = getValidDimensionValue(
|
||||
objectData.content.height
|
||||
);
|
||||
this._depth = this._originalDepth = getValidDimensionValue(
|
||||
objectData.content.depth
|
||||
);
|
||||
}
|
||||
|
||||
abstract getRenderer(): gdjs.RuntimeObject3DRenderer;
|
||||
|
||||
getRendererObject() {
|
||||
return null;
|
||||
}
|
||||
|
||||
get3DRendererObject() {
|
||||
return this.getRenderer().get3DRendererObject();
|
||||
}
|
||||
|
||||
updateFromObjectData(
|
||||
oldObjectData: Object3DData,
|
||||
newObjectData: Object3DData
|
||||
): boolean {
|
||||
// There is no need to check if they changed because events can't modify them.
|
||||
this._setOriginalWidth(
|
||||
getValidDimensionValue(newObjectData.content.width)
|
||||
);
|
||||
this._setOriginalHeight(
|
||||
getValidDimensionValue(newObjectData.content.height)
|
||||
);
|
||||
this._setOriginalDepth(
|
||||
getValidDimensionValue(newObjectData.content.depth)
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
extraInitializationFromInitialInstance(initialInstanceData: InstanceData) {
|
||||
if (initialInstanceData.customSize) {
|
||||
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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
setX(x: float): void {
|
||||
super.setX(x);
|
||||
this.getRenderer().updatePosition();
|
||||
}
|
||||
|
||||
setY(y: float): void {
|
||||
super.setY(y);
|
||||
this.getRenderer().updatePosition();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the object position on the Z axis.
|
||||
*/
|
||||
setZ(z: float): void {
|
||||
if (z === this._z) return;
|
||||
this._z = z;
|
||||
this.getRenderer().updatePosition();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the object position on the Z axis.
|
||||
*/
|
||||
getZ(): float {
|
||||
return this._z;
|
||||
}
|
||||
|
||||
setAngle(angle: float): void {
|
||||
super.setAngle(angle);
|
||||
this.getRenderer().updateRotation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the object rotation on the X axis.
|
||||
*
|
||||
* This is an Euler angle. Objects use the `ZYX` order.
|
||||
*/
|
||||
setRotationX(angle: float): void {
|
||||
this._rotationX = angle;
|
||||
this.getRenderer().updateRotation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the object rotation on the Y axis.
|
||||
*
|
||||
* This is an Euler angle. Objects use the `ZYX` order.
|
||||
*/
|
||||
setRotationY(angle: float): void {
|
||||
this._rotationY = angle;
|
||||
this.getRenderer().updateRotation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the object rotation on the X axis.
|
||||
*
|
||||
* This is an Euler angle. Objects use the `ZYX` order.
|
||||
*/
|
||||
getRotationX(): float {
|
||||
return this._rotationX;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the object rotation on the Y axis.
|
||||
*
|
||||
* This is an Euler angle. Objects use the `ZYX` order.
|
||||
*/
|
||||
getRotationY(): float {
|
||||
return this._rotationY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn the object around the scene x axis at its center.
|
||||
* @param deltaAngle the rotation angle
|
||||
*/
|
||||
turnAroundX(deltaAngle: float): void {
|
||||
const axisX = gdjs.RuntimeObject3D._temporaryVector;
|
||||
axisX.set(1, 0, 0);
|
||||
|
||||
const mesh = this.getRenderer().get3DRendererObject();
|
||||
mesh.rotateOnWorldAxis(axisX, gdjs.toRad(deltaAngle));
|
||||
this._rotationX = gdjs.toDegrees(mesh.rotation.x);
|
||||
this._rotationY = gdjs.toDegrees(mesh.rotation.y);
|
||||
this.setAngle(gdjs.toDegrees(mesh.rotation.z));
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn the object around the scene y axis at its center.
|
||||
* @param deltaAngle the rotation angle
|
||||
*/
|
||||
turnAroundY(deltaAngle: float): void {
|
||||
const axisY = gdjs.RuntimeObject3D._temporaryVector;
|
||||
axisY.set(0, 1, 0);
|
||||
|
||||
const mesh = this.getRenderer().get3DRendererObject();
|
||||
mesh.rotateOnWorldAxis(axisY, gdjs.toRad(deltaAngle));
|
||||
this._rotationX = gdjs.toDegrees(mesh.rotation.x);
|
||||
this._rotationY = gdjs.toDegrees(mesh.rotation.y);
|
||||
this.setAngle(gdjs.toDegrees(mesh.rotation.z));
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn the object around the scene z axis at its center.
|
||||
* @param deltaAngle the rotation angle
|
||||
*/
|
||||
turnAroundZ(deltaAngle: float): void {
|
||||
const axisZ = gdjs.RuntimeObject3D._temporaryVector;
|
||||
axisZ.set(0, 0, 1);
|
||||
|
||||
const mesh = this.getRenderer().get3DRendererObject();
|
||||
mesh.rotateOnWorldAxis(axisZ, gdjs.toRad(deltaAngle));
|
||||
this._rotationX = gdjs.toDegrees(mesh.rotation.x);
|
||||
this._rotationY = gdjs.toDegrees(mesh.rotation.y);
|
||||
this.setAngle(gdjs.toDegrees(mesh.rotation.z));
|
||||
}
|
||||
|
||||
getWidth(): float {
|
||||
return this._width;
|
||||
}
|
||||
|
||||
getHeight(): float {
|
||||
return this._height;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the object size on the Z axis (called "depth").
|
||||
*/
|
||||
getDepth(): float {
|
||||
return this._depth;
|
||||
}
|
||||
|
||||
setWidth(width: float): void {
|
||||
if (this._width === width) return;
|
||||
|
||||
this._width = width;
|
||||
this.getRenderer().updateSize();
|
||||
this.invalidateHitboxes();
|
||||
}
|
||||
|
||||
setHeight(height: float): void {
|
||||
if (this._height === height) return;
|
||||
|
||||
this._height = height;
|
||||
this.getRenderer().updateSize();
|
||||
this.invalidateHitboxes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the object size on the Z axis (called "depth").
|
||||
*/
|
||||
setDepth(depth: float): void {
|
||||
if (this._depth === depth) return;
|
||||
|
||||
this._depth = depth;
|
||||
this.getRenderer().updateSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the width of the object for a scale of 1.
|
||||
*
|
||||
* It can't be 0.
|
||||
*/
|
||||
_getOriginalWidth(): float {
|
||||
return this._originalWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the height of the object for a scale of 1.
|
||||
*
|
||||
* It can't be 0.
|
||||
*/
|
||||
_getOriginalHeight(): float {
|
||||
return this._originalHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the object size on the Z axis (called "depth") when the scale equals 1.
|
||||
*/
|
||||
_getOriginalDepth(): float {
|
||||
return this._originalDepth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the width of the object for a scale of 1.
|
||||
*/
|
||||
_setOriginalWidth(originalWidth: float): void {
|
||||
if (originalWidth <= 0) {
|
||||
originalWidth = 1;
|
||||
}
|
||||
const oldOriginalWidth = this._originalWidth;
|
||||
this._originalWidth = originalWidth;
|
||||
if (oldOriginalWidth === this._width) {
|
||||
this.setWidth(originalWidth);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the height of the object for a scale of 1.
|
||||
*/
|
||||
_setOriginalHeight(originalHeight: float): void {
|
||||
if (originalHeight <= 0) {
|
||||
originalHeight = 1;
|
||||
}
|
||||
const oldOriginalHeight = this._originalHeight;
|
||||
this._originalHeight = originalHeight;
|
||||
if (oldOriginalHeight === this._height) {
|
||||
this.setHeight(originalHeight);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the object size on the Z axis (called "depth") when the scale equals 1.
|
||||
*/
|
||||
_setOriginalDepth(originalDepth: float): void {
|
||||
if (originalDepth <= 0) {
|
||||
originalDepth = 1;
|
||||
}
|
||||
const oldOriginalDepth = this._originalDepth;
|
||||
this._originalDepth = originalDepth;
|
||||
if (oldOriginalDepth === this._depth) {
|
||||
this.setDepth(originalDepth);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the scale on X, Y and Z axis of the object.
|
||||
*
|
||||
* @param newScale The new scale (must be greater than 0).
|
||||
*/
|
||||
setScale(newScale: number): void {
|
||||
this.setScaleX(newScale);
|
||||
this.setScaleY(newScale);
|
||||
this.setScaleZ(newScale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the scale on X axis of the object (changing its width).
|
||||
*
|
||||
* @param newScale The new scale (must be greater than 0).
|
||||
*/
|
||||
setScaleX(newScale: number): void {
|
||||
if (newScale < 0) {
|
||||
newScale = 0;
|
||||
}
|
||||
this.setWidth(this._originalWidth * newScale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the scale on Y axis of the object (changing its height).
|
||||
*
|
||||
* @param newScale The new scale (must be greater than 0).
|
||||
*/
|
||||
setScaleY(newScale: number): void {
|
||||
if (newScale < 0) {
|
||||
newScale = 0;
|
||||
}
|
||||
this.setHeight(this._originalHeight * newScale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the scale on Z axis of the object (changing its height).
|
||||
*
|
||||
* @param newScale The new scale (must be greater than 0).
|
||||
*/
|
||||
setScaleZ(newScale: number): void {
|
||||
if (newScale < 0) {
|
||||
newScale = 0;
|
||||
}
|
||||
this.setDepth(this._originalDepth * newScale);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the scale of the object (or the geometric average of X, Y and Z scale in case they are different).
|
||||
*
|
||||
* @return the scale of the object (or the geometric average of X, Y and Z scale in case they are different).
|
||||
*/
|
||||
getScale(): number {
|
||||
const scaleX = this.getScaleX();
|
||||
const scaleY = this.getScaleY();
|
||||
const scaleZ = this.getScaleZ();
|
||||
return scaleX === scaleY && scaleX === scaleZ
|
||||
? scaleX
|
||||
: Math.pow(scaleX * scaleY * scaleZ, 1 / 3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the scale of the object on X axis.
|
||||
*
|
||||
* @return the scale of the object on X axis
|
||||
*/
|
||||
getScaleX(): float {
|
||||
return Math.abs(this._width / this._originalWidth);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the scale of the object on Y axis.
|
||||
*
|
||||
* @return the scale of the object on Y axis
|
||||
*/
|
||||
getScaleY(): float {
|
||||
return Math.abs(this._height / this._originalHeight);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the scale of the object on Z axis.
|
||||
*
|
||||
* @return the scale of the object on Z axis
|
||||
*/
|
||||
getScaleZ(): float {
|
||||
return Math.abs(this._depth / this._originalDepth);
|
||||
}
|
||||
|
||||
flipX(enable: boolean) {
|
||||
if (enable !== this._flippedX) {
|
||||
this._flippedX = enable;
|
||||
this.getRenderer().updateSize();
|
||||
}
|
||||
}
|
||||
|
||||
flipY(enable: boolean) {
|
||||
if (enable !== this._flippedY) {
|
||||
this._flippedY = enable;
|
||||
this.getRenderer().updateSize();
|
||||
}
|
||||
}
|
||||
|
||||
flipZ(enable: boolean) {
|
||||
if (enable !== this._flippedZ) {
|
||||
this._flippedZ = enable;
|
||||
this.getRenderer().updateSize();
|
||||
}
|
||||
}
|
||||
|
||||
isFlippedX(): boolean {
|
||||
return this._flippedX;
|
||||
}
|
||||
|
||||
isFlippedY(): boolean {
|
||||
return this._flippedY;
|
||||
}
|
||||
|
||||
isFlippedZ(): boolean {
|
||||
return this._flippedZ;
|
||||
}
|
||||
|
||||
hide(enable: boolean): void {
|
||||
super.hide(enable);
|
||||
this.getRenderer().updateVisibility();
|
||||
}
|
||||
}
|
||||
}
|
55
Extensions/3D/A_RuntimeObject3DRenderer.ts
Normal file
55
Extensions/3D/A_RuntimeObject3DRenderer.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
namespace gdjs {
|
||||
export abstract class RuntimeObject3DRenderer {
|
||||
protected _object: gdjs.RuntimeObject3D;
|
||||
private _threeObject3D: THREE.Object3D;
|
||||
|
||||
constructor(
|
||||
runtimeObject: gdjs.RuntimeObject3D,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
threeObject3D: THREE.Object3D
|
||||
) {
|
||||
this._object = runtimeObject;
|
||||
this._threeObject3D = threeObject3D;
|
||||
this._threeObject3D.rotation.order = 'ZYX';
|
||||
|
||||
instanceContainer
|
||||
.getLayer('')
|
||||
.getRenderer()
|
||||
.add3DRendererObject(this._threeObject3D);
|
||||
}
|
||||
|
||||
get3DRendererObject() {
|
||||
return this._threeObject3D;
|
||||
}
|
||||
|
||||
updatePosition() {
|
||||
this._threeObject3D.position.set(
|
||||
this._object.x + this._object.getWidth() / 2,
|
||||
this._object.y + this._object.getHeight() / 2,
|
||||
this._object.getZ() + this._object.getDepth() / 2
|
||||
);
|
||||
}
|
||||
|
||||
updateRotation() {
|
||||
this._threeObject3D.rotation.set(
|
||||
gdjs.toRad(this._object.getRotationX()),
|
||||
gdjs.toRad(this._object.getRotationY()),
|
||||
gdjs.toRad(this._object.angle)
|
||||
);
|
||||
}
|
||||
|
||||
updateSize() {
|
||||
const object = this._object;
|
||||
this._threeObject3D.scale.set(
|
||||
object.isFlippedX() ? -object.getWidth() : object.getWidth(),
|
||||
object.isFlippedY() ? -object.getHeight() : object.getHeight(),
|
||||
object.isFlippedZ() ? -object.getDepth() : object.getDepth()
|
||||
);
|
||||
this.updatePosition();
|
||||
}
|
||||
|
||||
updateVisibility() {
|
||||
this._threeObject3D.visible = !this._object.isHidden();
|
||||
}
|
||||
}
|
||||
}
|
73
Extensions/3D/AmbientLight.ts
Normal file
73
Extensions/3D/AmbientLight.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
namespace gdjs {
|
||||
gdjs.PixiFiltersTools.registerFilterCreator(
|
||||
'Scene3D::AmbientLight',
|
||||
new (class implements gdjs.PixiFiltersTools.FilterCreator {
|
||||
makeFilter(
|
||||
target: EffectsTarget,
|
||||
effectData: EffectData
|
||||
): gdjs.PixiFiltersTools.Filter {
|
||||
return new (class implements gdjs.PixiFiltersTools.Filter {
|
||||
light: THREE.AmbientLight;
|
||||
_isEnabled: boolean;
|
||||
|
||||
constructor() {
|
||||
this.light = new THREE.AmbientLight();
|
||||
this._isEnabled = false;
|
||||
}
|
||||
|
||||
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.light);
|
||||
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.light);
|
||||
this._isEnabled = false;
|
||||
return true;
|
||||
}
|
||||
updatePreRender(target: gdjs.EffectsTarget): any {}
|
||||
updateDoubleParameter(parameterName: string, value: number): void {
|
||||
if (parameterName === 'intensity') {
|
||||
this.light.intensity = value;
|
||||
}
|
||||
}
|
||||
updateStringParameter(parameterName: string, value: string): void {
|
||||
if (parameterName === 'color') {
|
||||
this.light.color = new THREE.Color(
|
||||
gdjs.PixiFiltersTools.rgbOrHexToHexNumber(value)
|
||||
);
|
||||
}
|
||||
}
|
||||
updateBooleanParameter(parameterName: string, value: boolean): void {}
|
||||
})();
|
||||
}
|
||||
})()
|
||||
);
|
||||
}
|
440
Extensions/3D/Cube3DRuntimeObject.ts
Normal file
440
Extensions/3D/Cube3DRuntimeObject.ts
Normal file
@@ -0,0 +1,440 @@
|
||||
namespace gdjs {
|
||||
/** Base parameters for {@link gdjs.Cube3DRuntimeObject} */
|
||||
export interface Cube3DObjectData extends Object3DData {
|
||||
/** The base parameters of the Cube3D object */
|
||||
content: Object3DDataContent & {
|
||||
enableTextureTransparency: boolean;
|
||||
facesOrientation: 'Y' | 'Z';
|
||||
frontFaceResourceName: string;
|
||||
backFaceResourceName: string;
|
||||
backFaceUpThroughWhichAxisRotation: 'X' | 'Y';
|
||||
leftFaceResourceName: string;
|
||||
rightFaceResourceName: string;
|
||||
topFaceResourceName: string;
|
||||
bottomFaceResourceName: string;
|
||||
frontFaceResourceRepeat: boolean;
|
||||
backFaceResourceRepeat: boolean;
|
||||
leftFaceResourceRepeat: boolean;
|
||||
rightFaceResourceRepeat: boolean;
|
||||
topFaceResourceRepeat: boolean;
|
||||
bottomFaceResourceRepeat: boolean;
|
||||
frontFaceVisible: boolean;
|
||||
backFaceVisible: boolean;
|
||||
leftFaceVisible: boolean;
|
||||
rightFaceVisible: boolean;
|
||||
topFaceVisible: boolean;
|
||||
bottomFaceVisible: boolean;
|
||||
materialType: 'Basic' | 'StandardWithoutMetalness';
|
||||
};
|
||||
}
|
||||
|
||||
type FaceName = 'front' | 'back' | 'left' | 'right' | 'top' | 'bottom';
|
||||
const faceNameToBitmaskIndex = {
|
||||
front: 0,
|
||||
back: 1,
|
||||
left: 2,
|
||||
right: 3,
|
||||
top: 4,
|
||||
bottom: 5,
|
||||
};
|
||||
|
||||
/**
|
||||
* Shows a 3D box object.
|
||||
*/
|
||||
export class Cube3DRuntimeObject extends gdjs.RuntimeObject3D {
|
||||
private _renderer: Cube3DRuntimeObjectRenderer;
|
||||
private _facesOrientation: 'Y' | 'Z';
|
||||
private _backFaceUpThroughWhichAxisRotation: 'X' | 'Y';
|
||||
private _shouldUseTransparentTexture: boolean;
|
||||
// `_rotationZ` is `angle` from `gdjs.RuntimeObject`.
|
||||
private _visibleFacesBitmask: integer;
|
||||
private _textureRepeatFacesBitmask: integer;
|
||||
private _faceResourceNames: [
|
||||
string,
|
||||
string,
|
||||
string,
|
||||
string,
|
||||
string,
|
||||
string
|
||||
];
|
||||
_materialType: gdjs.Cube3DRuntimeObject.MaterialType =
|
||||
gdjs.Cube3DRuntimeObject.MaterialType.Basic;
|
||||
|
||||
constructor(
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
objectData: Cube3DObjectData
|
||||
) {
|
||||
super(instanceContainer, objectData);
|
||||
this._shouldUseTransparentTexture =
|
||||
objectData.content.enableTextureTransparency || false;
|
||||
this._facesOrientation = objectData.content.facesOrientation || 'Y';
|
||||
this._visibleFacesBitmask = 0;
|
||||
if (objectData.content.frontFaceVisible)
|
||||
this._visibleFacesBitmask |= 1 << faceNameToBitmaskIndex['front'];
|
||||
if (objectData.content.backFaceVisible)
|
||||
this._visibleFacesBitmask |= 1 << faceNameToBitmaskIndex['back'];
|
||||
if (objectData.content.leftFaceVisible)
|
||||
this._visibleFacesBitmask |= 1 << faceNameToBitmaskIndex['left'];
|
||||
if (objectData.content.rightFaceVisible)
|
||||
this._visibleFacesBitmask |= 1 << faceNameToBitmaskIndex['right'];
|
||||
if (objectData.content.topFaceVisible)
|
||||
this._visibleFacesBitmask |= 1 << faceNameToBitmaskIndex['top'];
|
||||
if (objectData.content.bottomFaceVisible)
|
||||
this._visibleFacesBitmask |= 1 << faceNameToBitmaskIndex['bottom'];
|
||||
this._textureRepeatFacesBitmask = 0;
|
||||
if (objectData.content.frontFaceResourceRepeat)
|
||||
this._textureRepeatFacesBitmask |= 1 << faceNameToBitmaskIndex['front'];
|
||||
if (objectData.content.backFaceResourceRepeat)
|
||||
this._textureRepeatFacesBitmask |= 1 << faceNameToBitmaskIndex['back'];
|
||||
if (objectData.content.leftFaceResourceRepeat)
|
||||
this._textureRepeatFacesBitmask |= 1 << faceNameToBitmaskIndex['left'];
|
||||
if (objectData.content.rightFaceResourceRepeat)
|
||||
this._textureRepeatFacesBitmask |= 1 << faceNameToBitmaskIndex['right'];
|
||||
if (objectData.content.topFaceResourceRepeat)
|
||||
this._textureRepeatFacesBitmask |= 1 << faceNameToBitmaskIndex['top'];
|
||||
if (objectData.content.bottomFaceResourceRepeat)
|
||||
this._textureRepeatFacesBitmask |=
|
||||
1 << faceNameToBitmaskIndex['bottom'];
|
||||
this._backFaceUpThroughWhichAxisRotation =
|
||||
objectData.content.backFaceUpThroughWhichAxisRotation || 'X';
|
||||
this._faceResourceNames = [
|
||||
objectData.content.frontFaceResourceName,
|
||||
objectData.content.backFaceResourceName,
|
||||
objectData.content.leftFaceResourceName,
|
||||
objectData.content.rightFaceResourceName,
|
||||
objectData.content.topFaceResourceName,
|
||||
objectData.content.bottomFaceResourceName,
|
||||
];
|
||||
this._materialType = this._convertMaterialType(
|
||||
objectData.content.materialType
|
||||
);
|
||||
|
||||
this._renderer = new gdjs.Cube3DRuntimeObjectRenderer(
|
||||
this,
|
||||
instanceContainer
|
||||
);
|
||||
|
||||
// *ALWAYS* call `this.onCreated()` at the very end of your object constructor.
|
||||
this.onCreated();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the visibility of a face of the 3D box.
|
||||
*
|
||||
* @param faceName - The name of the face to set visibility for.
|
||||
* @param value - The visibility value to set.
|
||||
*/
|
||||
setFaceVisibility(faceName: FaceName, enable: boolean) {
|
||||
const faceIndex = faceNameToBitmaskIndex[faceName];
|
||||
if (faceIndex === undefined) {
|
||||
return;
|
||||
}
|
||||
if (enable === this.isFaceAtIndexVisible(faceIndex)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (enable) {
|
||||
this._visibleFacesBitmask |= 1 << faceIndex;
|
||||
} else {
|
||||
this._visibleFacesBitmask &= ~(1 << faceIndex);
|
||||
}
|
||||
this._renderer.updateFace(faceIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the texture repeat of a face of the 3D box.
|
||||
*
|
||||
* @param faceName - The name of the face to set visibility for.
|
||||
* @param value - The visibility value to set.
|
||||
*/
|
||||
setRepeatTextureOnFace(faceName: FaceName, enable: boolean) {
|
||||
const faceIndex = faceNameToBitmaskIndex[faceName];
|
||||
if (faceIndex === undefined) {
|
||||
return;
|
||||
}
|
||||
if (enable === this.shouldRepeatTextureOnFaceAtIndex(faceIndex)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (enable) {
|
||||
this._textureRepeatFacesBitmask |= 1 << faceIndex;
|
||||
} else {
|
||||
this._textureRepeatFacesBitmask &= ~(1 << faceIndex);
|
||||
}
|
||||
this._renderer.updateFace(faceIndex);
|
||||
}
|
||||
|
||||
isFaceVisible(faceName: FaceName): boolean {
|
||||
const faceIndex = faceNameToBitmaskIndex[faceName];
|
||||
if (faceIndex === undefined) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.isFaceAtIndexVisible(faceIndex);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
isFaceAtIndexVisible(faceIndex): boolean {
|
||||
return (this._visibleFacesBitmask & (1 << faceIndex)) !== 0;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
shouldRepeatTextureOnFaceAtIndex(faceIndex): boolean {
|
||||
return (this._textureRepeatFacesBitmask & (1 << faceIndex)) !== 0;
|
||||
}
|
||||
|
||||
setFaceResourceName(faceName: FaceName, resourceName: string): void {
|
||||
const faceIndex = faceNameToBitmaskIndex[faceName];
|
||||
if (faceIndex === undefined) {
|
||||
return;
|
||||
}
|
||||
if (this._faceResourceNames[faceIndex] === resourceName) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._faceResourceNames[faceIndex] = resourceName;
|
||||
this._renderer.updateFace(faceIndex);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
getFaceAtIndexResourceName(faceIndex: integer): string {
|
||||
return this._faceResourceNames[faceIndex];
|
||||
}
|
||||
|
||||
getRenderer(): gdjs.RuntimeObject3DRenderer {
|
||||
return this._renderer;
|
||||
}
|
||||
|
||||
getBackFaceUpThroughWhichAxisRotation(): 'X' | 'Y' {
|
||||
return this._backFaceUpThroughWhichAxisRotation;
|
||||
}
|
||||
|
||||
setBackFaceUpThroughWhichAxisRotation(axis: 'X' | 'Y'): void {
|
||||
this._backFaceUpThroughWhichAxisRotation = axis;
|
||||
this._renderer.updateFace(faceNameToBitmaskIndex['back']);
|
||||
}
|
||||
|
||||
getFacesOrientation(): 'Y' | 'Z' {
|
||||
return this._facesOrientation;
|
||||
}
|
||||
|
||||
setFacesOrientation(orientation: 'Y' | 'Z'): void {
|
||||
this._facesOrientation = orientation;
|
||||
this._renderer.updateFace(faceNameToBitmaskIndex['left']);
|
||||
this._renderer.updateFace(faceNameToBitmaskIndex['right']);
|
||||
this._renderer.updateFace(faceNameToBitmaskIndex['top']);
|
||||
// Bottom texture should not change based on that setting.
|
||||
}
|
||||
|
||||
updateFromObjectData(
|
||||
oldObjectData: Cube3DObjectData,
|
||||
newObjectData: Cube3DObjectData
|
||||
): boolean {
|
||||
super.updateFromObjectData(oldObjectData, newObjectData);
|
||||
if (
|
||||
oldObjectData.content.frontFaceVisible !==
|
||||
newObjectData.content.frontFaceVisible
|
||||
) {
|
||||
this.setFaceVisibility('front', newObjectData.content.frontFaceVisible);
|
||||
}
|
||||
if (
|
||||
oldObjectData.content.backFaceVisible !==
|
||||
newObjectData.content.backFaceVisible
|
||||
) {
|
||||
this.setFaceVisibility('back', newObjectData.content.backFaceVisible);
|
||||
}
|
||||
if (
|
||||
oldObjectData.content.leftFaceVisible !==
|
||||
newObjectData.content.leftFaceVisible
|
||||
) {
|
||||
this.setFaceVisibility('left', newObjectData.content.leftFaceVisible);
|
||||
}
|
||||
if (
|
||||
oldObjectData.content.rightFaceVisible !==
|
||||
newObjectData.content.rightFaceVisible
|
||||
) {
|
||||
this.setFaceVisibility('right', newObjectData.content.rightFaceVisible);
|
||||
}
|
||||
if (
|
||||
oldObjectData.content.topFaceVisible !==
|
||||
newObjectData.content.topFaceVisible
|
||||
) {
|
||||
this.setFaceVisibility('top', newObjectData.content.topFaceVisible);
|
||||
}
|
||||
if (
|
||||
oldObjectData.content.bottomFaceVisible !==
|
||||
newObjectData.content.bottomFaceVisible
|
||||
) {
|
||||
this.setFaceVisibility(
|
||||
'bottom',
|
||||
newObjectData.content.bottomFaceVisible
|
||||
);
|
||||
}
|
||||
if (
|
||||
oldObjectData.content.frontFaceResourceName !==
|
||||
newObjectData.content.frontFaceResourceName
|
||||
) {
|
||||
this.setFaceResourceName(
|
||||
'front',
|
||||
newObjectData.content.frontFaceResourceName
|
||||
);
|
||||
}
|
||||
if (
|
||||
oldObjectData.content.backFaceResourceName !==
|
||||
newObjectData.content.backFaceResourceName
|
||||
) {
|
||||
this.setFaceResourceName(
|
||||
'back',
|
||||
newObjectData.content.backFaceResourceName
|
||||
);
|
||||
}
|
||||
if (
|
||||
oldObjectData.content.leftFaceResourceName !==
|
||||
newObjectData.content.leftFaceResourceName
|
||||
) {
|
||||
this.setFaceResourceName(
|
||||
'left',
|
||||
newObjectData.content.leftFaceResourceName
|
||||
);
|
||||
}
|
||||
if (
|
||||
oldObjectData.content.rightFaceResourceName !==
|
||||
newObjectData.content.rightFaceResourceName
|
||||
) {
|
||||
this.setFaceResourceName(
|
||||
'right',
|
||||
newObjectData.content.rightFaceResourceName
|
||||
);
|
||||
}
|
||||
if (
|
||||
oldObjectData.content.topFaceResourceName !==
|
||||
newObjectData.content.topFaceResourceName
|
||||
) {
|
||||
this.setFaceResourceName(
|
||||
'top',
|
||||
newObjectData.content.topFaceResourceName
|
||||
);
|
||||
}
|
||||
if (
|
||||
oldObjectData.content.bottomFaceResourceName !==
|
||||
newObjectData.content.bottomFaceResourceName
|
||||
) {
|
||||
this.setFaceResourceName(
|
||||
'bottom',
|
||||
newObjectData.content.bottomFaceResourceName
|
||||
);
|
||||
}
|
||||
if (
|
||||
oldObjectData.content.frontFaceResourceRepeat !==
|
||||
newObjectData.content.frontFaceResourceRepeat
|
||||
) {
|
||||
this.setRepeatTextureOnFace(
|
||||
'front',
|
||||
newObjectData.content.frontFaceResourceRepeat
|
||||
);
|
||||
}
|
||||
if (
|
||||
oldObjectData.content.backFaceResourceRepeat !==
|
||||
newObjectData.content.backFaceResourceRepeat
|
||||
) {
|
||||
this.setRepeatTextureOnFace(
|
||||
'back',
|
||||
newObjectData.content.backFaceResourceRepeat
|
||||
);
|
||||
}
|
||||
if (
|
||||
oldObjectData.content.leftFaceResourceRepeat !==
|
||||
newObjectData.content.leftFaceResourceRepeat
|
||||
) {
|
||||
this.setRepeatTextureOnFace(
|
||||
'left',
|
||||
newObjectData.content.leftFaceResourceRepeat
|
||||
);
|
||||
}
|
||||
if (
|
||||
oldObjectData.content.rightFaceResourceRepeat !==
|
||||
newObjectData.content.rightFaceResourceRepeat
|
||||
) {
|
||||
this.setRepeatTextureOnFace(
|
||||
'right',
|
||||
newObjectData.content.rightFaceResourceRepeat
|
||||
);
|
||||
}
|
||||
if (
|
||||
oldObjectData.content.topFaceResourceRepeat !==
|
||||
newObjectData.content.topFaceResourceRepeat
|
||||
) {
|
||||
this.setRepeatTextureOnFace(
|
||||
'top',
|
||||
newObjectData.content.topFaceResourceRepeat
|
||||
);
|
||||
}
|
||||
if (
|
||||
oldObjectData.content.bottomFaceResourceRepeat !==
|
||||
newObjectData.content.bottomFaceResourceRepeat
|
||||
) {
|
||||
this.setRepeatTextureOnFace(
|
||||
'bottom',
|
||||
newObjectData.content.bottomFaceResourceRepeat
|
||||
);
|
||||
}
|
||||
if (
|
||||
oldObjectData.content.backFaceUpThroughWhichAxisRotation !==
|
||||
newObjectData.content.backFaceUpThroughWhichAxisRotation
|
||||
) {
|
||||
this.setBackFaceUpThroughWhichAxisRotation(
|
||||
newObjectData.content.backFaceUpThroughWhichAxisRotation
|
||||
);
|
||||
}
|
||||
if (
|
||||
oldObjectData.content.facesOrientation !==
|
||||
newObjectData.content.facesOrientation
|
||||
) {
|
||||
this.setFacesOrientation(newObjectData.content.facesOrientation);
|
||||
}
|
||||
if (
|
||||
oldObjectData.content.materialType !==
|
||||
newObjectData.content.materialType
|
||||
) {
|
||||
this.setMaterialType(newObjectData.content.materialType);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the texture transparency should be enabled.
|
||||
*/
|
||||
shouldUseTransparentTexture(): boolean {
|
||||
return this._shouldUseTransparentTexture;
|
||||
}
|
||||
|
||||
_convertMaterialType(
|
||||
materialTypeString: string
|
||||
): gdjs.Cube3DRuntimeObject.MaterialType {
|
||||
if (materialTypeString === 'StandardWithoutMetalness') {
|
||||
return gdjs.Cube3DRuntimeObject.MaterialType.StandardWithoutMetalness;
|
||||
} else {
|
||||
return gdjs.Cube3DRuntimeObject.MaterialType.Basic;
|
||||
}
|
||||
}
|
||||
|
||||
setMaterialType(materialTypeString: string) {
|
||||
const newMaterialType = this._convertMaterialType(materialTypeString);
|
||||
if (this._materialType === newMaterialType) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._materialType = newMaterialType;
|
||||
this._renderer._updateMaterials();
|
||||
}
|
||||
}
|
||||
|
||||
export namespace Cube3DRuntimeObject {
|
||||
export enum MaterialType {
|
||||
Basic,
|
||||
StandardWithoutMetalness,
|
||||
}
|
||||
}
|
||||
gdjs.registerObject('Scene3D::Cube3DObject', gdjs.Cube3DRuntimeObject);
|
||||
}
|
319
Extensions/3D/Cube3DRuntimeObjectPixiRenderer.ts
Normal file
319
Extensions/3D/Cube3DRuntimeObjectPixiRenderer.ts
Normal file
@@ -0,0 +1,319 @@
|
||||
namespace gdjs {
|
||||
// Three.js materials for a cube and the order of faces in the object is different,
|
||||
// so we keep the mapping from one to the other.
|
||||
const faceIndexToMaterialIndex = {
|
||||
3: 0, // right
|
||||
2: 1, // left
|
||||
5: 2, // bottom
|
||||
4: 3, // top
|
||||
0: 4, // front
|
||||
1: 5, // back
|
||||
};
|
||||
const materialIndexToFaceIndex = {
|
||||
0: 3,
|
||||
1: 2,
|
||||
2: 5,
|
||||
3: 4,
|
||||
4: 0,
|
||||
5: 1,
|
||||
};
|
||||
|
||||
const noRepeatTextureVertexIndexToUvMapping = {
|
||||
0: [0, 0],
|
||||
1: [1, 0],
|
||||
2: [0, 1],
|
||||
3: [1, 1],
|
||||
};
|
||||
|
||||
const noRepeatTextureVertexIndexToUvMappingForLeftAndRightFacesTowardsZ = {
|
||||
0: [0, 1],
|
||||
1: [0, 0],
|
||||
2: [1, 1],
|
||||
3: [1, 0],
|
||||
};
|
||||
|
||||
let transparentMaterial: THREE.MeshBasicMaterial;
|
||||
const getTransparentMaterial = () => {
|
||||
if (!transparentMaterial)
|
||||
transparentMaterial = new THREE.MeshBasicMaterial({
|
||||
transparent: true,
|
||||
opacity: 0,
|
||||
// Set the alpha test to to ensure the faces behind are rendered
|
||||
// (no "back face culling" that would still be done if alphaTest is not set).
|
||||
alphaTest: 1,
|
||||
});
|
||||
|
||||
return transparentMaterial;
|
||||
};
|
||||
|
||||
const getFaceMaterial = (
|
||||
runtimeObject: gdjs.Cube3DRuntimeObject,
|
||||
faceIndex: integer
|
||||
) => {
|
||||
if (!runtimeObject.isFaceAtIndexVisible(faceIndex))
|
||||
return getTransparentMaterial();
|
||||
|
||||
return runtimeObject
|
||||
.getInstanceContainer()
|
||||
.getGame()
|
||||
.getImageManager()
|
||||
.getThreeMaterial(runtimeObject.getFaceAtIndexResourceName(faceIndex), {
|
||||
useTransparentTexture: runtimeObject.shouldUseTransparentTexture(),
|
||||
forceBasicMaterial:
|
||||
runtimeObject._materialType ===
|
||||
gdjs.Cube3DRuntimeObject.MaterialType.Basic,
|
||||
});
|
||||
};
|
||||
|
||||
class Cube3DRuntimeObjectPixiRenderer extends gdjs.RuntimeObject3DRenderer {
|
||||
private _cube3DRuntimeObject: gdjs.Cube3DRuntimeObject;
|
||||
private _boxMesh: THREE.Mesh;
|
||||
|
||||
constructor(
|
||||
runtimeObject: gdjs.Cube3DRuntimeObject,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer
|
||||
) {
|
||||
const geometry = new THREE.BoxGeometry(1, 1, 1);
|
||||
// TODO (3D) - feature: support color instead of texture?
|
||||
const materials = [
|
||||
getFaceMaterial(runtimeObject, materialIndexToFaceIndex[0]),
|
||||
getFaceMaterial(runtimeObject, materialIndexToFaceIndex[1]),
|
||||
getFaceMaterial(runtimeObject, materialIndexToFaceIndex[2]),
|
||||
getFaceMaterial(runtimeObject, materialIndexToFaceIndex[3]),
|
||||
getFaceMaterial(runtimeObject, materialIndexToFaceIndex[4]),
|
||||
getFaceMaterial(runtimeObject, materialIndexToFaceIndex[5]),
|
||||
];
|
||||
const boxMesh = new THREE.Mesh(geometry, materials);
|
||||
|
||||
super(runtimeObject, instanceContainer, boxMesh);
|
||||
this._boxMesh = boxMesh;
|
||||
this._cube3DRuntimeObject = runtimeObject;
|
||||
|
||||
this.updateSize();
|
||||
this.updatePosition();
|
||||
this.updateRotation();
|
||||
}
|
||||
|
||||
updateFace(faceIndex: integer) {
|
||||
const materialIndex = faceIndexToMaterialIndex[faceIndex];
|
||||
if (materialIndex === undefined) return;
|
||||
|
||||
this._boxMesh.material[materialIndex] = getFaceMaterial(
|
||||
this._cube3DRuntimeObject,
|
||||
faceIndex
|
||||
);
|
||||
if (this._cube3DRuntimeObject.isFaceAtIndexVisible(faceIndex)) {
|
||||
this.updateTextureUvMapping(faceIndex);
|
||||
}
|
||||
}
|
||||
|
||||
updateSize(): void {
|
||||
super.updateSize();
|
||||
this.updateTextureUvMapping();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the UV mapping of the geometry in order to repeat a material
|
||||
* over the different faces of the cube.
|
||||
* The mesh must be configured with a list of materials in order
|
||||
* for the method to work.
|
||||
* @param faceIndex The face index to update. If undefined, updates all the faces.
|
||||
*/
|
||||
updateTextureUvMapping(faceIndex?: number) {
|
||||
// @ts-ignore - position is stored as a Float32BufferAttribute
|
||||
const pos: THREE.BufferAttribute = this._boxMesh.geometry.getAttribute(
|
||||
'position'
|
||||
);
|
||||
// @ts-ignore - uv is stored as a Float32BufferAttribute
|
||||
const uvMapping: THREE.BufferAttribute = this._boxMesh.geometry.getAttribute(
|
||||
'uv'
|
||||
);
|
||||
const startIndex =
|
||||
faceIndex === undefined ? 0 : faceIndexToMaterialIndex[faceIndex] * 4;
|
||||
const endIndex =
|
||||
faceIndex === undefined
|
||||
? 23
|
||||
: faceIndexToMaterialIndex[faceIndex] * 4 + 3;
|
||||
for (
|
||||
let vertexIndex = startIndex;
|
||||
vertexIndex <= endIndex;
|
||||
vertexIndex++
|
||||
) {
|
||||
const materialIndex = Math.floor(
|
||||
vertexIndex /
|
||||
// Each face of the cube has 4 points
|
||||
4
|
||||
);
|
||||
const material = this._boxMesh.material[materialIndex];
|
||||
if (!material || !material.map) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const shouldRepeatTexture = this._cube3DRuntimeObject.shouldRepeatTextureOnFaceAtIndex(
|
||||
materialIndexToFaceIndex[materialIndex]
|
||||
);
|
||||
|
||||
const shouldOrientateFacesTowardsY =
|
||||
this._cube3DRuntimeObject.getFacesOrientation() === 'Y';
|
||||
|
||||
let x: float, y: float;
|
||||
switch (materialIndex) {
|
||||
case 0:
|
||||
// Right face
|
||||
if (shouldRepeatTexture) {
|
||||
if (shouldOrientateFacesTowardsY) {
|
||||
x =
|
||||
-(this._boxMesh.scale.z / material.map.source.data.width) *
|
||||
(pos.getZ(vertexIndex) - 0.5);
|
||||
y =
|
||||
-(this._boxMesh.scale.y / material.map.source.data.height) *
|
||||
(pos.getY(vertexIndex) + 0.5);
|
||||
} else {
|
||||
x =
|
||||
-(this._boxMesh.scale.y / material.map.source.data.width) *
|
||||
(pos.getY(vertexIndex) - 0.5);
|
||||
y =
|
||||
(this._boxMesh.scale.z / material.map.source.data.height) *
|
||||
(pos.getZ(vertexIndex) - 0.5);
|
||||
}
|
||||
} else {
|
||||
if (shouldOrientateFacesTowardsY) {
|
||||
[x, y] = noRepeatTextureVertexIndexToUvMapping[vertexIndex % 4];
|
||||
} else {
|
||||
[
|
||||
x,
|
||||
y,
|
||||
] = noRepeatTextureVertexIndexToUvMappingForLeftAndRightFacesTowardsZ[
|
||||
vertexIndex % 4
|
||||
];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
// Left face
|
||||
if (shouldRepeatTexture) {
|
||||
if (shouldOrientateFacesTowardsY) {
|
||||
x =
|
||||
(this._boxMesh.scale.z / material.map.source.data.width) *
|
||||
(pos.getZ(vertexIndex) + 0.5);
|
||||
y =
|
||||
-(this._boxMesh.scale.y / material.map.source.data.height) *
|
||||
(pos.getY(vertexIndex) + 0.5);
|
||||
} else {
|
||||
x =
|
||||
(this._boxMesh.scale.y / material.map.source.data.width) *
|
||||
(pos.getY(vertexIndex) + 0.5);
|
||||
y =
|
||||
(this._boxMesh.scale.z / material.map.source.data.height) *
|
||||
(pos.getZ(vertexIndex) - 0.5);
|
||||
}
|
||||
} else {
|
||||
if (shouldOrientateFacesTowardsY) {
|
||||
[x, y] = noRepeatTextureVertexIndexToUvMapping[vertexIndex % 4];
|
||||
} else {
|
||||
[
|
||||
x,
|
||||
y,
|
||||
] = noRepeatTextureVertexIndexToUvMappingForLeftAndRightFacesTowardsZ[
|
||||
vertexIndex % 4
|
||||
];
|
||||
x = -x;
|
||||
y = -y;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
// Bottom face
|
||||
if (shouldRepeatTexture) {
|
||||
x =
|
||||
(this._boxMesh.scale.x / material.map.source.data.width) *
|
||||
(pos.getX(vertexIndex) + 0.5);
|
||||
y =
|
||||
(this._boxMesh.scale.z / material.map.source.data.height) *
|
||||
(pos.getZ(vertexIndex) - 0.5);
|
||||
} else {
|
||||
[x, y] = noRepeatTextureVertexIndexToUvMapping[vertexIndex % 4];
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
// Top face
|
||||
if (shouldRepeatTexture) {
|
||||
if (shouldOrientateFacesTowardsY) {
|
||||
x =
|
||||
(this._boxMesh.scale.x / material.map.source.data.width) *
|
||||
(pos.getX(vertexIndex) + 0.5);
|
||||
y =
|
||||
-(this._boxMesh.scale.z / material.map.source.data.height) *
|
||||
(pos.getZ(vertexIndex) + 0.5);
|
||||
} else {
|
||||
x =
|
||||
-(this._boxMesh.scale.x / material.map.source.data.width) *
|
||||
(pos.getX(vertexIndex) - 0.5);
|
||||
y =
|
||||
(this._boxMesh.scale.z / material.map.source.data.height) *
|
||||
(pos.getZ(vertexIndex) - 0.5);
|
||||
}
|
||||
} else {
|
||||
[x, y] = noRepeatTextureVertexIndexToUvMapping[vertexIndex % 4];
|
||||
if (!shouldOrientateFacesTowardsY) {
|
||||
x = -x;
|
||||
y = -y;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
// Front face
|
||||
if (shouldRepeatTexture) {
|
||||
x =
|
||||
(this._boxMesh.scale.x / material.map.source.data.width) *
|
||||
(pos.getX(vertexIndex) + 0.5);
|
||||
y =
|
||||
-(this._boxMesh.scale.y / material.map.source.data.height) *
|
||||
(pos.getY(vertexIndex) + 0.5);
|
||||
} else {
|
||||
[x, y] = noRepeatTextureVertexIndexToUvMapping[vertexIndex % 4];
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
// Back face
|
||||
const shouldBackFaceBeUpThroughXAxisRotation =
|
||||
this._cube3DRuntimeObject.getBackFaceUpThroughWhichAxisRotation() ===
|
||||
'X';
|
||||
|
||||
if (shouldRepeatTexture) {
|
||||
x =
|
||||
(shouldBackFaceBeUpThroughXAxisRotation ? 1 : -1) *
|
||||
(this._boxMesh.scale.x / material.map.source.data.width) *
|
||||
(pos.getX(vertexIndex) +
|
||||
(shouldBackFaceBeUpThroughXAxisRotation ? 1 : -1) * 0.5);
|
||||
y =
|
||||
(shouldBackFaceBeUpThroughXAxisRotation ? 1 : -1) *
|
||||
(this._boxMesh.scale.y / material.map.source.data.height) *
|
||||
(pos.getY(vertexIndex) +
|
||||
(shouldBackFaceBeUpThroughXAxisRotation ? -1 : 1) * 0.5);
|
||||
} else {
|
||||
[x, y] = noRepeatTextureVertexIndexToUvMapping[vertexIndex % 4];
|
||||
if (shouldBackFaceBeUpThroughXAxisRotation) {
|
||||
x = -x;
|
||||
y = -y;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
[x, y] = noRepeatTextureVertexIndexToUvMapping[vertexIndex % 4];
|
||||
}
|
||||
uvMapping.setXY(vertexIndex, x, y);
|
||||
}
|
||||
uvMapping.needsUpdate = true;
|
||||
}
|
||||
|
||||
_updateMaterials() {
|
||||
for (let index = 0; index < 6; index++) {
|
||||
this.updateFace(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const Cube3DRuntimeObjectRenderer = Cube3DRuntimeObjectPixiRenderer;
|
||||
export type Cube3DRuntimeObjectRenderer = Cube3DRuntimeObjectPixiRenderer;
|
||||
}
|
101
Extensions/3D/DirectionalLight.ts
Normal file
101
Extensions/3D/DirectionalLight.ts
Normal file
@@ -0,0 +1,101 @@
|
||||
namespace gdjs {
|
||||
gdjs.PixiFiltersTools.registerFilterCreator(
|
||||
'Scene3D::DirectionalLight',
|
||||
new (class implements gdjs.PixiFiltersTools.FilterCreator {
|
||||
makeFilter(
|
||||
target: EffectsTarget,
|
||||
effectData: EffectData
|
||||
): gdjs.PixiFiltersTools.Filter {
|
||||
return new (class implements gdjs.PixiFiltersTools.Filter {
|
||||
light: THREE.DirectionalLight;
|
||||
rotationObject: THREE.Group;
|
||||
_isEnabled: boolean = false;
|
||||
top: string = 'Y-';
|
||||
elevation: float = 45;
|
||||
rotation: float = 0;
|
||||
|
||||
constructor() {
|
||||
this.light = new THREE.DirectionalLight();
|
||||
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 === 'color') {
|
||||
this.light.color = 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);
|
||||
}
|
||||
}
|
||||
})();
|
||||
}
|
||||
})()
|
||||
);
|
||||
}
|
70
Extensions/3D/ExponentialFog.ts
Normal file
70
Extensions/3D/ExponentialFog.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
namespace gdjs {
|
||||
gdjs.PixiFiltersTools.registerFilterCreator(
|
||||
'Scene3D::ExponentialFog',
|
||||
new (class implements gdjs.PixiFiltersTools.FilterCreator {
|
||||
makeFilter(
|
||||
target: EffectsTarget,
|
||||
effectData: EffectData
|
||||
): gdjs.PixiFiltersTools.Filter {
|
||||
return new (class implements gdjs.PixiFiltersTools.Filter {
|
||||
fog: THREE.FogExp2;
|
||||
|
||||
constructor() {
|
||||
this.fog = new THREE.FogExp2(0xffffff);
|
||||
}
|
||||
|
||||
isEnabled(target: EffectsTarget): boolean {
|
||||
const scene = target.get3DRendererObject() as
|
||||
| THREE.Scene
|
||||
| null
|
||||
| undefined;
|
||||
return scene ? scene.fog === this.fog : false;
|
||||
}
|
||||
setEnabled(target: EffectsTarget, enabled: boolean): boolean {
|
||||
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 || scene.fog === undefined) {
|
||||
return false;
|
||||
}
|
||||
scene.fog = this.fog;
|
||||
return true;
|
||||
}
|
||||
removeEffect(target: EffectsTarget): boolean {
|
||||
const scene = target.get3DRendererObject() as
|
||||
| THREE.Scene
|
||||
| null
|
||||
| undefined;
|
||||
if (!scene || scene.fog === undefined) {
|
||||
return false;
|
||||
}
|
||||
scene.fog = null;
|
||||
return true;
|
||||
}
|
||||
updatePreRender(target: gdjs.EffectsTarget): any {}
|
||||
updateDoubleParameter(parameterName: string, value: number): void {
|
||||
if (parameterName === 'density') {
|
||||
this.fog.density = value;
|
||||
}
|
||||
}
|
||||
updateStringParameter(parameterName: string, value: string): void {
|
||||
if (parameterName === 'color') {
|
||||
this.fog.color = new THREE.Color(
|
||||
gdjs.PixiFiltersTools.rgbOrHexToHexNumber(value)
|
||||
);
|
||||
}
|
||||
}
|
||||
updateBooleanParameter(parameterName: string, value: boolean): void {}
|
||||
})();
|
||||
}
|
||||
})()
|
||||
);
|
||||
}
|
2687
Extensions/3D/JsExtension.js
Normal file
2687
Extensions/3D/JsExtension.js
Normal file
File diff suppressed because it is too large
Load Diff
72
Extensions/3D/LinearFog.ts
Normal file
72
Extensions/3D/LinearFog.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
namespace gdjs {
|
||||
gdjs.PixiFiltersTools.registerFilterCreator(
|
||||
'Scene3D::LinearFog',
|
||||
new (class implements gdjs.PixiFiltersTools.FilterCreator {
|
||||
makeFilter(
|
||||
target: EffectsTarget,
|
||||
effectData: EffectData
|
||||
): gdjs.PixiFiltersTools.Filter {
|
||||
return new (class implements gdjs.PixiFiltersTools.Filter {
|
||||
fog: THREE.Fog;
|
||||
|
||||
constructor() {
|
||||
this.fog = new THREE.Fog(0xffffff);
|
||||
}
|
||||
|
||||
isEnabled(target: EffectsTarget): boolean {
|
||||
const scene = target.get3DRendererObject() as
|
||||
| THREE.Scene
|
||||
| null
|
||||
| undefined;
|
||||
return scene ? scene.fog === this.fog : false;
|
||||
}
|
||||
setEnabled(target: EffectsTarget, enabled: boolean): boolean {
|
||||
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 || scene.fog === undefined) {
|
||||
return false;
|
||||
}
|
||||
scene.fog = this.fog;
|
||||
return true;
|
||||
}
|
||||
removeEffect(target: EffectsTarget): boolean {
|
||||
const scene = target.get3DRendererObject() as
|
||||
| THREE.Scene
|
||||
| null
|
||||
| undefined;
|
||||
if (!scene || scene.fog === undefined) {
|
||||
return false;
|
||||
}
|
||||
scene.fog = null;
|
||||
return true;
|
||||
}
|
||||
updatePreRender(target: gdjs.EffectsTarget): any {}
|
||||
updateDoubleParameter(parameterName: string, value: number): void {
|
||||
if (parameterName === 'near') {
|
||||
this.fog.near = value;
|
||||
} else if (parameterName === 'far') {
|
||||
this.fog.far = value;
|
||||
}
|
||||
}
|
||||
updateStringParameter(parameterName: string, value: string): void {
|
||||
if (parameterName === 'color') {
|
||||
this.fog.color = new THREE.Color(
|
||||
gdjs.PixiFiltersTools.rgbOrHexToHexNumber(value)
|
||||
);
|
||||
}
|
||||
}
|
||||
updateBooleanParameter(parameterName: string, value: boolean): void {}
|
||||
})();
|
||||
}
|
||||
})()
|
||||
);
|
||||
}
|
116
Extensions/3D/Model3DRuntimeObject.ts
Normal file
116
Extensions/3D/Model3DRuntimeObject.ts
Normal file
@@ -0,0 +1,116 @@
|
||||
namespace gdjs {
|
||||
/** Base parameters for {@link gdjs.Cube3DRuntimeObject} */
|
||||
export interface Model3DObjectData extends Object3DData {
|
||||
/** The base parameters of the Model3D object */
|
||||
content: Object3DDataContent & {
|
||||
modelResourceName: string;
|
||||
rotationX: number;
|
||||
rotationY: number;
|
||||
rotationZ: number;
|
||||
keepAspectRatio: boolean;
|
||||
materialType: 'Basic' | 'StandardWithoutMetalness' | 'KeepOriginal';
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* A 3D object which displays a 3D model.
|
||||
*/
|
||||
export class Model3DRuntimeObject extends gdjs.RuntimeObject3D {
|
||||
_renderer: gdjs.Model3DRuntimeObjectRenderer;
|
||||
|
||||
_modelResourceName: string;
|
||||
_materialType: gdjs.Model3DRuntimeObject.MaterialType =
|
||||
gdjs.Model3DRuntimeObject.MaterialType.Basic;
|
||||
|
||||
constructor(
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
objectData: Model3DObjectData
|
||||
) {
|
||||
super(instanceContainer, objectData);
|
||||
this._modelResourceName = objectData.content.modelResourceName;
|
||||
this._renderer = new gdjs.Model3DRuntimeObjectRenderer(
|
||||
this,
|
||||
instanceContainer
|
||||
);
|
||||
this._updateMaterialType(objectData);
|
||||
|
||||
// *ALWAYS* call `this.onCreated()` at the very end of your object constructor.
|
||||
this.onCreated();
|
||||
}
|
||||
|
||||
updateFromObjectData(
|
||||
oldObjectData: Model3DObjectData,
|
||||
newObjectData: Model3DObjectData
|
||||
): boolean {
|
||||
super.updateFromObjectData(oldObjectData, newObjectData);
|
||||
if (
|
||||
oldObjectData.content.width !== newObjectData.content.width ||
|
||||
oldObjectData.content.height !== newObjectData.content.height ||
|
||||
oldObjectData.content.depth !== newObjectData.content.depth ||
|
||||
oldObjectData.content.rotationX !== newObjectData.content.rotationX ||
|
||||
oldObjectData.content.rotationY !== newObjectData.content.rotationY ||
|
||||
oldObjectData.content.rotationZ !== newObjectData.content.rotationZ ||
|
||||
oldObjectData.content.keepAspectRatio !==
|
||||
newObjectData.content.keepAspectRatio
|
||||
) {
|
||||
this._updateDefaultTransformation(newObjectData);
|
||||
}
|
||||
if (
|
||||
oldObjectData.content.materialType !==
|
||||
newObjectData.content.materialType
|
||||
) {
|
||||
this._updateMaterialType(newObjectData);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
_updateDefaultTransformation(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(
|
||||
rotationX,
|
||||
rotationY,
|
||||
rotationZ,
|
||||
this._getOriginalWidth(),
|
||||
this._getOriginalHeight(),
|
||||
this._getOriginalDepth(),
|
||||
keepAspectRatio
|
||||
);
|
||||
}
|
||||
|
||||
getRenderer(): RuntimeObject3DRenderer {
|
||||
return this._renderer;
|
||||
}
|
||||
|
||||
_convertMaterialType(
|
||||
materialTypeString: string
|
||||
): gdjs.Model3DRuntimeObject.MaterialType {
|
||||
if (materialTypeString === 'KeepOriginal') {
|
||||
return gdjs.Model3DRuntimeObject.MaterialType.KeepOriginal;
|
||||
} else if (materialTypeString === 'StandardWithoutMetalness') {
|
||||
return gdjs.Model3DRuntimeObject.MaterialType.StandardWithoutMetalness;
|
||||
} else {
|
||||
return gdjs.Model3DRuntimeObject.MaterialType.Basic;
|
||||
}
|
||||
}
|
||||
|
||||
_updateMaterialType(objectData: Model3DObjectData) {
|
||||
this._materialType = this._convertMaterialType(
|
||||
objectData.content.materialType
|
||||
);
|
||||
this._renderer._updateMaterials();
|
||||
this._updateDefaultTransformation(objectData);
|
||||
}
|
||||
}
|
||||
|
||||
export namespace Model3DRuntimeObject {
|
||||
export enum MaterialType {
|
||||
Basic,
|
||||
StandardWithoutMetalness,
|
||||
KeepOriginal,
|
||||
}
|
||||
}
|
||||
gdjs.registerObject('Scene3D::Model3DObject', gdjs.Model3DRuntimeObject);
|
||||
}
|
184
Extensions/3D/Model3DRuntimeObject3DRenderer.ts
Normal file
184
Extensions/3D/Model3DRuntimeObject3DRenderer.ts
Normal file
@@ -0,0 +1,184 @@
|
||||
namespace gdjs {
|
||||
class Model3DRuntimeObject3DRenderer extends gdjs.RuntimeObject3DRenderer {
|
||||
private _model3DRuntimeObject: gdjs.Model3DRuntimeObject;
|
||||
/**
|
||||
* The 3D model stretched in a 1x1x1 cube.
|
||||
*/
|
||||
private _threeObject: THREE.Object3D;
|
||||
|
||||
constructor(
|
||||
runtimeObject: gdjs.Model3DRuntimeObject,
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer
|
||||
) {
|
||||
// @ts-ignore It can't be null if THREE exists.
|
||||
const originalModelMesh: THREE.Object3D = instanceContainer
|
||||
.getGame()
|
||||
.getModel3DManager()
|
||||
.getModel(runtimeObject._modelResourceName);
|
||||
const modelObject3D = originalModelMesh.clone();
|
||||
|
||||
// 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);
|
||||
super(runtimeObject, instanceContainer, group);
|
||||
|
||||
this._model3DRuntimeObject = runtimeObject;
|
||||
this._threeObject = modelObject3D;
|
||||
|
||||
this.updateSize();
|
||||
this.updatePosition();
|
||||
this.updateRotation();
|
||||
}
|
||||
|
||||
_updateDefaultTransformation(
|
||||
rotationX: float,
|
||||
rotationY: float,
|
||||
rotationZ: float,
|
||||
originalWidth: float,
|
||||
originalHeight: float,
|
||||
originalDepth: float,
|
||||
keepAspectRatio: boolean
|
||||
) {
|
||||
const boundingBox = this._getModelAABB(rotationX, rotationY, rotationZ);
|
||||
|
||||
// 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)
|
||||
);
|
||||
|
||||
// Rotate the model.
|
||||
this._threeObject.scale.set(1, 1, 1);
|
||||
this._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);
|
||||
|
||||
if (keepAspectRatio) {
|
||||
// Reduce the object dimensions to keep aspect ratio.
|
||||
const widthRatio = originalWidth / modelWidth;
|
||||
const heightRatio = originalHeight / modelHeight;
|
||||
const depthRatio = originalDepth / modelDepth;
|
||||
const scaleRatio = Math.min(widthRatio, heightRatio, depthRatio);
|
||||
|
||||
this._object._setOriginalWidth(scaleRatio * modelWidth);
|
||||
this._object._setOriginalHeight(scaleRatio * modelHeight);
|
||||
this._object._setOriginalDepth(scaleRatio * modelDepth);
|
||||
}
|
||||
|
||||
this._threeObject.updateMatrix();
|
||||
}
|
||||
|
||||
private _getModelAABB(
|
||||
rotationX: float,
|
||||
rotationY: float,
|
||||
rotationZ: float
|
||||
) {
|
||||
// The original model is used because `setFromObject` is working in
|
||||
// world transformation.
|
||||
|
||||
// @ts-ignore It can't be null if THREE exists.
|
||||
const originalModelMesh: THREE.Object3D = this._object
|
||||
.getInstanceContainer()
|
||||
.getGame()
|
||||
.getModel3DManager()
|
||||
.getModel(this._model3DRuntimeObject._modelResourceName);
|
||||
|
||||
originalModelMesh.rotation.set(
|
||||
gdjs.toRad(rotationX),
|
||||
gdjs.toRad(rotationY),
|
||||
gdjs.toRad(rotationZ)
|
||||
);
|
||||
|
||||
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();
|
||||
|
||||
this.get3DRendererObject().remove(this._threeObject);
|
||||
this.get3DRendererObject().add(modelObject3D);
|
||||
|
||||
this._threeObject = modelObject3D;
|
||||
|
||||
this._replaceMaterials();
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace materials to better work with lights (or no light).
|
||||
*/
|
||||
_replaceMaterials() {
|
||||
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;
|
||||
}
|
||||
}
|
||||
});
|
||||
} 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;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const Model3DRuntimeObjectRenderer = Model3DRuntimeObject3DRenderer;
|
||||
export type Model3DRuntimeObjectRenderer = Model3DRuntimeObject3DRenderer;
|
||||
}
|
235
Extensions/3D/Scene3DTools.ts
Normal file
235
Extensions/3D/Scene3DTools.ts
Normal file
@@ -0,0 +1,235 @@
|
||||
namespace gdjs {
|
||||
export namespace scene3d {
|
||||
const assumedFovIn2D = 45;
|
||||
|
||||
export namespace camera {
|
||||
export const getCameraZ = (
|
||||
runtimeScene: RuntimeScene,
|
||||
layerName: string,
|
||||
cameraIndex: integer
|
||||
): float => {
|
||||
const layer = runtimeScene.getLayer(layerName);
|
||||
const layerRenderer = layer.getRenderer();
|
||||
const threeCamera = layerRenderer.getThreeCamera();
|
||||
const fov = threeCamera ? threeCamera.fov : assumedFovIn2D;
|
||||
return layer.getCameraZ(fov, cameraIndex);
|
||||
};
|
||||
|
||||
export const setCameraZ = (
|
||||
runtimeScene: RuntimeScene,
|
||||
z: float,
|
||||
layerName: string,
|
||||
cameraIndex: integer
|
||||
) => {
|
||||
const layer = runtimeScene.getLayer(layerName);
|
||||
const layerRenderer = layer.getRenderer();
|
||||
const threeCamera = layerRenderer.getThreeCamera();
|
||||
const fov = threeCamera ? threeCamera.fov : assumedFovIn2D;
|
||||
layer.setCameraZ(z, fov, cameraIndex);
|
||||
};
|
||||
|
||||
export const getCameraRotationX = (
|
||||
runtimeScene: RuntimeScene,
|
||||
layerName: string,
|
||||
cameraIndex: integer
|
||||
): float => {
|
||||
const layer = runtimeScene.getLayer(layerName);
|
||||
const layerRenderer = layer.getRenderer();
|
||||
|
||||
const threeCamera = layerRenderer.getThreeCamera();
|
||||
if (!threeCamera) return 0;
|
||||
return gdjs.toDegrees(threeCamera.rotation.x);
|
||||
};
|
||||
|
||||
export const setCameraRotationX = (
|
||||
runtimeScene: RuntimeScene,
|
||||
angle: float,
|
||||
layerName: string,
|
||||
cameraIndex: integer
|
||||
) => {
|
||||
const layer = runtimeScene.getLayer(layerName);
|
||||
const layerRenderer = layer.getRenderer();
|
||||
|
||||
const threeCamera = layerRenderer.getThreeCamera();
|
||||
if (!threeCamera) return;
|
||||
|
||||
threeCamera.rotation.x = gdjs.toRad(angle);
|
||||
};
|
||||
|
||||
export const getCameraRotationY = (
|
||||
runtimeScene: RuntimeScene,
|
||||
layerName: string,
|
||||
cameraIndex: integer
|
||||
): float => {
|
||||
const layer = runtimeScene.getLayer(layerName);
|
||||
const layerRenderer = layer.getRenderer();
|
||||
|
||||
const threeCamera = layerRenderer.getThreeCamera();
|
||||
if (!threeCamera) return 0;
|
||||
return gdjs.toDegrees(threeCamera.rotation.y);
|
||||
};
|
||||
|
||||
export const setCameraRotationY = (
|
||||
runtimeScene: RuntimeScene,
|
||||
angle: float,
|
||||
layerName: string,
|
||||
cameraIndex: integer
|
||||
) => {
|
||||
const layer = runtimeScene.getLayer(layerName);
|
||||
const layerRenderer = layer.getRenderer();
|
||||
|
||||
const threeCamera = layerRenderer.getThreeCamera();
|
||||
if (!threeCamera) return;
|
||||
|
||||
threeCamera.rotation.y = gdjs.toRad(angle);
|
||||
};
|
||||
|
||||
export const turnCameraTowardObject = (
|
||||
runtimeScene: RuntimeScene,
|
||||
object: gdjs.RuntimeObject,
|
||||
layerName: string,
|
||||
cameraIndex: integer,
|
||||
isStandingOnY: boolean
|
||||
) => {
|
||||
const layer = runtimeScene.getLayer(layerName);
|
||||
const layerRenderer = layer.getRenderer();
|
||||
|
||||
const threeCamera = layerRenderer.getThreeCamera();
|
||||
if (!threeCamera) return;
|
||||
|
||||
if (isStandingOnY) {
|
||||
threeCamera.up.set(0, 1, 0);
|
||||
} else {
|
||||
threeCamera.up.set(0, 0, 1);
|
||||
}
|
||||
threeCamera.lookAt(
|
||||
object.getCenterXInScene(),
|
||||
-object.getCenterYInScene(),
|
||||
//@ts-ignore
|
||||
object.getZ ? object.getZ() : 0
|
||||
);
|
||||
// The layer angle takes over the 3D camera Z rotation.
|
||||
layer.setCameraRotation(gdjs.toDegrees(-threeCamera.rotation.z));
|
||||
};
|
||||
|
||||
export const turnCameraTowardPosition = (
|
||||
runtimeScene: RuntimeScene,
|
||||
x: float,
|
||||
y: float,
|
||||
z: float,
|
||||
layerName: string,
|
||||
cameraIndex: integer,
|
||||
isStandingOnY: boolean
|
||||
) => {
|
||||
const layer = runtimeScene.getLayer(layerName);
|
||||
const layerRenderer = layer.getRenderer();
|
||||
|
||||
const threeCamera = layerRenderer.getThreeCamera();
|
||||
if (!threeCamera) return;
|
||||
|
||||
if (isStandingOnY) {
|
||||
threeCamera.up.set(0, 1, 0);
|
||||
} else {
|
||||
threeCamera.up.set(0, 0, 1);
|
||||
}
|
||||
threeCamera.lookAt(x, -y, z);
|
||||
// The layer angle takes over the 3D camera Z rotation.
|
||||
layer.setCameraRotation(gdjs.toDegrees(-threeCamera.rotation.z));
|
||||
};
|
||||
|
||||
export const getNearPlane = (
|
||||
runtimeScene: RuntimeScene,
|
||||
layerName: string,
|
||||
cameraIndex: integer
|
||||
): float => {
|
||||
const layer = runtimeScene.getLayer(layerName);
|
||||
const layerRenderer = layer.getRenderer();
|
||||
|
||||
const threeCamera = layerRenderer.getThreeCamera();
|
||||
if (!threeCamera) return 0;
|
||||
return threeCamera.near;
|
||||
};
|
||||
|
||||
export const setNearPlane = (
|
||||
runtimeScene: RuntimeScene,
|
||||
distance: float,
|
||||
layerName: string,
|
||||
cameraIndex: integer
|
||||
) => {
|
||||
const layer = runtimeScene.getLayer(layerName);
|
||||
const layerRenderer = layer.getRenderer();
|
||||
|
||||
const threeCamera = layerRenderer.getThreeCamera();
|
||||
if (!threeCamera) return;
|
||||
|
||||
threeCamera.near = Math.min(
|
||||
// 0 is not a valid value for three js perspective camera:
|
||||
// https://threejs.org/docs/#api/en/cameras/PerspectiveCamera.
|
||||
Math.max(distance, 0.0001),
|
||||
// Near value cannot exceed far value.
|
||||
threeCamera.far
|
||||
);
|
||||
layerRenderer.setThreeCameraDirty(true);
|
||||
};
|
||||
|
||||
export const getFarPlane = (
|
||||
runtimeScene: RuntimeScene,
|
||||
layerName: string,
|
||||
cameraIndex: integer
|
||||
): float => {
|
||||
const layer = runtimeScene.getLayer(layerName);
|
||||
const layerRenderer = layer.getRenderer();
|
||||
|
||||
const threeCamera = layerRenderer.getThreeCamera();
|
||||
if (!threeCamera) return 0;
|
||||
return threeCamera.far;
|
||||
};
|
||||
|
||||
export const setFarPlane = (
|
||||
runtimeScene: RuntimeScene,
|
||||
distance: float,
|
||||
layerName: string,
|
||||
cameraIndex: integer
|
||||
) => {
|
||||
const layer = runtimeScene.getLayer(layerName);
|
||||
const layerRenderer = layer.getRenderer();
|
||||
|
||||
const threeCamera = layerRenderer.getThreeCamera();
|
||||
if (!threeCamera) return;
|
||||
|
||||
// Far value cannot be lower than near value
|
||||
threeCamera.far = Math.max(distance, threeCamera.near);
|
||||
layerRenderer.setThreeCameraDirty(true);
|
||||
};
|
||||
|
||||
export const getFov = (
|
||||
runtimeScene: RuntimeScene,
|
||||
layerName: string,
|
||||
cameraIndex: integer
|
||||
): float => {
|
||||
const layer = runtimeScene.getLayer(layerName);
|
||||
const layerRenderer = layer.getRenderer();
|
||||
|
||||
const threeCamera = layerRenderer.getThreeCamera();
|
||||
if (!threeCamera) return 45;
|
||||
return threeCamera.fov;
|
||||
};
|
||||
|
||||
export const setFov = (
|
||||
runtimeScene: RuntimeScene,
|
||||
angle: float,
|
||||
layerName: string,
|
||||
cameraIndex: integer
|
||||
) => {
|
||||
const layer = runtimeScene.getLayer(layerName);
|
||||
const layerRenderer = layer.getRenderer();
|
||||
|
||||
const threeCamera = layerRenderer.getThreeCamera();
|
||||
if (!threeCamera) return;
|
||||
|
||||
threeCamera.fov = Math.min(Math.max(angle, 0), 180);
|
||||
layerRenderer.setThreeCameraDirty(true);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@@ -181,7 +181,7 @@ module.exports = {
|
||||
)
|
||||
.addParameter(
|
||||
'yesorno',
|
||||
_('Display in landscape? (portait otherwise)'),
|
||||
_('Display in landscape? (portrait otherwise)'),
|
||||
'',
|
||||
false
|
||||
)
|
||||
|
@@ -117,7 +117,7 @@ namespace gdjs {
|
||||
|
||||
await admob.start();
|
||||
|
||||
logger.info('AdMob succesfully started.');
|
||||
logger.info('AdMob successfully started.');
|
||||
admobStarted = true;
|
||||
},
|
||||
false
|
||||
|
@@ -439,7 +439,7 @@ module.exports = {
|
||||
|
||||
/**
|
||||
* You can optionally add sanity tests that will check the basic working
|
||||
* of your extension behaviors/objects by instanciating behaviors/objects
|
||||
* of your extension behaviors/objects by instantiating behaviors/objects
|
||||
* and setting the property to a given value.
|
||||
*
|
||||
* If you don't have any tests, you can simply return an empty array.
|
||||
|
50
Extensions/BBText/pixi-multistyle-text/README.md
vendored
50
Extensions/BBText/pixi-multistyle-text/README.md
vendored
@@ -12,31 +12,32 @@ In the example below, we are defining 4 text styles.
|
||||
```js
|
||||
let text = new MultiStyleText("Let's make some <ml>multiline</ml>\nand <ms>multistyle</ms> text for\n<pixi>Pixi.js!</pixi>",
|
||||
{
|
||||
"default": {
|
||||
fontFamily: "Arial",
|
||||
fontSize: "24px",
|
||||
fill: "#cccccc",
|
||||
align: "center"
|
||||
},
|
||||
"ml": {
|
||||
fontStyle: "italic",
|
||||
fill: "#ff8888"
|
||||
},
|
||||
"ms": {
|
||||
fontStyle: "italic",
|
||||
fill: "#4488ff"
|
||||
},
|
||||
"pixi": {
|
||||
fontSize: "64px",
|
||||
fill: "#efefef"
|
||||
}
|
||||
"default": {
|
||||
fontFamily: "Arial",
|
||||
fontSize: "24px",
|
||||
fill: "#cccccc",
|
||||
align: "center"
|
||||
},
|
||||
"ml": {
|
||||
fontStyle: "italic",
|
||||
fill: "#ff8888"
|
||||
},
|
||||
"ms": {
|
||||
fontStyle: "italic",
|
||||
fill: "#4488ff"
|
||||
},
|
||||
"pixi": {
|
||||
fontSize: "64px",
|
||||
fill: "#efefef"
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## Build instructions
|
||||
|
||||
```
|
||||
$ yarn install
|
||||
$ yarn build
|
||||
```bash
|
||||
yarn install
|
||||
yarn build
|
||||
```
|
||||
|
||||
## Usage
|
||||
@@ -46,6 +47,7 @@ $ yarn build
|
||||
Creates a new `MultiStyleText` with the given text and styles.
|
||||
|
||||
#### `textStyles`
|
||||
|
||||
Type: `{ [key: string]: ExtendedTextStyle }`
|
||||
|
||||
Each key of this dictionary should match with a tag in the text. Use the key `default` for the default style.
|
||||
@@ -57,10 +59,10 @@ The `align`, `wordWrap`, `wordWrapWidth`, and `breakWord` properties are ignored
|
||||
If text is rendered without any value assigned to a given parameter, Pixi's defaults are used.
|
||||
|
||||
## Demo
|
||||
```
|
||||
$ yarn demo
|
||||
```
|
||||
|
||||
```bash
|
||||
yarn demo
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
|
@@ -392,7 +392,7 @@ module.exports = {
|
||||
|
||||
/**
|
||||
* You can optionally add sanity tests that will check the basic working
|
||||
* of your extension behaviors/objects by instanciating behaviors/objects
|
||||
* of your extension behaviors/objects by instantiating behaviors/objects
|
||||
* and setting the property to a given value.
|
||||
*
|
||||
* If you don't have any tests, you can simply return an empty array.
|
||||
@@ -554,7 +554,7 @@ module.exports = {
|
||||
if (!texture.valid) {
|
||||
// Post pone texture update if texture is not loaded.
|
||||
// (otherwise, the bitmap font would not get updated when the
|
||||
// texture is loaded and udpated).
|
||||
// texture is loaded and updated).
|
||||
return new Promise((resolve) => {
|
||||
texture.once('update', () => {
|
||||
resolve(loadBitmapFont());
|
||||
|
@@ -14,7 +14,7 @@ namespace gdjs {
|
||||
/**
|
||||
* Vibrate the mobile device in a pattern.
|
||||
* You can add multiple comma separated values where every second one determines the silence between vibrations.
|
||||
* Example: "200,1000,500" (200ms vibration, 1sec silense, 500ms vibration)
|
||||
* Example: "200,1000,500" (200ms vibration, 1sec silence, 500ms vibration)
|
||||
* @param intervals Comma separated list of values (in ms).
|
||||
*/
|
||||
export const startVibrationPattern = function (intervals: string) {
|
||||
|
@@ -1,11 +1,12 @@
|
||||
# bondage.js [](https://travis-ci.org/jhayley/bondage.js)
|
||||
|
||||
[Yarn](https://github.com/InfiniteAmmoInc/Yarn) parser for Javascript, in the same vein as [YarnSpinner](https://github.com/thesecretlab/YarnSpinner).
|
||||
|
||||
# Usage
|
||||
|
||||
#### As a Web Tool
|
||||
|
||||
To run through your yarn files in your browser, go to http://hayley.zone/bondage.js, paste your yarn data in the field, then hit "compile".
|
||||
To run through your yarn files in your browser, go to <http://hayley.zone/bondage.js>, paste your yarn data in the field, then hit "compile".
|
||||
|
||||
#### As a Command Line Tool
|
||||
Installation: `npm install -g bondage`
|
||||
|
@@ -103,7 +103,7 @@ namespace gdjs {
|
||||
return;
|
||||
}
|
||||
|
||||
// Autoscroll commands so the user doesnt have to press again
|
||||
// Autoscroll commands so the user doesn't have to press again.
|
||||
if (
|
||||
gdjs.dialogueTree._isLineTypeCommand() &&
|
||||
this.dialogueDataType === 'text' &&
|
||||
@@ -458,7 +458,7 @@ namespace gdjs {
|
||||
*
|
||||
* There are three types:
|
||||
* - text - regular dialogue text is being parsed at the moment
|
||||
* - options - the player has reached a branching choise moment where they must select one of multiple options
|
||||
* - options - the player has reached a branching choice moment where they must select one of multiple options
|
||||
* - command - a <<command>> was called in the background, that can be used to trigger game events, but will not be displayed in the dialogue box.
|
||||
*
|
||||
* @param type The type you want to check for ( one of the three above )
|
||||
@@ -485,7 +485,7 @@ namespace gdjs {
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if a branch exists. It is also used internaly whenever you use the start from action.
|
||||
* Check if a branch exists. It is also used internally whenever you use the start from action.
|
||||
* @param branchName The Dialogue Branch name you want to check.
|
||||
*/
|
||||
gdjs.dialogueTree.hasDialogueBranch = function (branchName: string) {
|
||||
|
@@ -48,6 +48,7 @@ module.exports = {
|
||||
'Adjust gamma, contrast, saturation, brightness, alpha or color-channel shift.'
|
||||
)
|
||||
)
|
||||
.markAsOnlyWorkingFor2D()
|
||||
.addIncludeFile('Extensions/Effects/pixi-filters/filter-adjustment.js')
|
||||
.addIncludeFile('Extensions/Effects/adjustment-pixi-filter.js');
|
||||
const adjustmentProperties = adjustmentEffect.getProperties();
|
||||
@@ -96,6 +97,7 @@ module.exports = {
|
||||
.addEffect('AdvancedBloom')
|
||||
.setFullName(_('Advanced bloom'))
|
||||
.setDescription(_('Applies a bloom effect.'))
|
||||
.markAsOnlyWorkingFor2D()
|
||||
.addIncludeFile('Extensions/Effects/pixi-filters/filter-kawase-blur.js')
|
||||
.addIncludeFile(
|
||||
'Extensions/Effects/pixi-filters/filter-advanced-bloom.js'
|
||||
@@ -138,6 +140,7 @@ module.exports = {
|
||||
.addEffect('Ascii')
|
||||
.setFullName(_('ASCII'))
|
||||
.setDescription(_('Render the image with ASCII characters only.'))
|
||||
.markAsOnlyWorkingFor2D()
|
||||
.addIncludeFile('Extensions/Effects/pixi-filters/filter-ascii.js')
|
||||
.addIncludeFile('Extensions/Effects/ascii-pixi-filter.js');
|
||||
const asciiProperties = asciiEffect.getProperties();
|
||||
@@ -151,6 +154,7 @@ module.exports = {
|
||||
.addEffect('Bevel')
|
||||
.setFullName(_('Beveled edges'))
|
||||
.setDescription(_('Add beveled edges around the rendered image.'))
|
||||
.markAsOnlyWorkingFor2D()
|
||||
.addIncludeFile('Extensions/Effects/pixi-filters/filter-bevel.js')
|
||||
.addIncludeFile('Extensions/Effects/bevel-pixi-filter.js');
|
||||
const bevelProperties = bevelEffect.getProperties();
|
||||
@@ -194,6 +198,7 @@ module.exports = {
|
||||
.addEffect('BlackAndWhite')
|
||||
.setFullName(_('Black and White'))
|
||||
.setDescription(_('Alter the colors to make the image black and white'))
|
||||
.markAsOnlyWorkingFor2D()
|
||||
.addIncludeFile('Extensions/Effects/black-and-white-pixi-filter.js');
|
||||
const blackAndWhiteProperties = blackAndWhiteEffect.getProperties();
|
||||
blackAndWhiteProperties
|
||||
@@ -208,6 +213,7 @@ module.exports = {
|
||||
.setDescription(
|
||||
_('Alter the rendered image with the specified blend mode.')
|
||||
)
|
||||
.markAsOnlyWorkingFor2D()
|
||||
.addIncludeFile('Extensions/Effects/blending-mode-pixi-filter.js');
|
||||
const blendingModeProperties = blendingModeEffect.getProperties();
|
||||
blendingModeProperties
|
||||
@@ -225,6 +231,7 @@ module.exports = {
|
||||
.addEffect('Blur')
|
||||
.setFullName(_('Blur (Gaussian, slow - prefer to use Kawase blur)'))
|
||||
.setDescription(_('Blur the rendered image. This is slow, so prefer to use Kawase blur in most cases.'))
|
||||
.markAsOnlyWorkingFor2D()
|
||||
.addIncludeFile('Extensions/Effects/blur-pixi-filter.js');
|
||||
const blurProperties = blurEffect.getProperties();
|
||||
blurProperties
|
||||
@@ -256,6 +263,7 @@ module.exports = {
|
||||
.addEffect('Brightness')
|
||||
.setFullName(_('Brightness'))
|
||||
.setDescription(_('Make the image brighter.'))
|
||||
.markAsOnlyWorkingFor2D()
|
||||
.addIncludeFile('Extensions/Effects/brightness-pixi-filter.js');
|
||||
const brightnessProperties = brightnessEffect.getProperties();
|
||||
brightnessProperties
|
||||
@@ -268,6 +276,7 @@ module.exports = {
|
||||
.addEffect('BulgePinch')
|
||||
.setFullName(_('Bulge Pinch'))
|
||||
.setDescription(_('Bulges or pinches the image in a circle.'))
|
||||
.markAsOnlyWorkingFor2D()
|
||||
.addIncludeFile('Extensions/Effects/pixi-filters/filter-bulge-pinch.js')
|
||||
.addIncludeFile('Extensions/Effects/bulge-pinch-pixi-filter.js');
|
||||
const bulgePinchProperties = bulgePinchEffect.getProperties();
|
||||
@@ -299,6 +308,7 @@ module.exports = {
|
||||
.addEffect('ColorMap')
|
||||
.setFullName(_('Color Map'))
|
||||
.setDescription(_('Change the color rendered on screen.'))
|
||||
.markAsOnlyWorkingFor2D()
|
||||
.addIncludeFile('Extensions/Effects/color-map-pixi-filter.js')
|
||||
.addIncludeFile('Extensions/Effects/pixi-filters/filter-color-map.js');
|
||||
const colorMapProperties = colorMapEffect.getProperties();
|
||||
@@ -309,7 +319,7 @@ module.exports = {
|
||||
.setLabel(_('Color map texture for the effect'))
|
||||
.setDescription(
|
||||
_(
|
||||
'You can change colors of pixels by modifing a reference color image, containing each colors, called the *Color Map Texture*. To get started, **download** [a default color map texture here](https://wiki.gdevelop.io/gdevelop5/interface/scene-editor/layer-effects).'
|
||||
'You can change colors of pixels by modifying a reference color image, containing each colors, called the *Color Map Texture*. To get started, **download** [a default color map texture here](https://wiki.gdevelop.io/gdevelop5/interface/scene-editor/layer-effects).'
|
||||
)
|
||||
);
|
||||
colorMapProperties
|
||||
@@ -328,6 +338,7 @@ module.exports = {
|
||||
.addEffect('ColorReplace')
|
||||
.setFullName(_('Color Replace'))
|
||||
.setDescription(_('Effect replacing a color (or similar) by another.'))
|
||||
.markAsOnlyWorkingFor2D()
|
||||
.addIncludeFile('Extensions/Effects/pixi-filters/filter-color-replace.js')
|
||||
.addIncludeFile('Extensions/Effects/color-replace-pixi-filter.js');
|
||||
const colorReplaceProperties = colorReplaceEffect.getProperties();
|
||||
@@ -358,6 +369,7 @@ module.exports = {
|
||||
.addEffect('CRT')
|
||||
.setFullName(_('CRT'))
|
||||
.setDescription(_('Apply an effect resembling old CRT monitors.'))
|
||||
.markAsOnlyWorkingFor2D()
|
||||
.addIncludeFile('Extensions/Effects/pixi-filters/filter-crt.js')
|
||||
.addIncludeFile('Extensions/Effects/crt-pixi-filter.js');
|
||||
const crtProperties = crtEffect.getProperties();
|
||||
@@ -435,6 +447,7 @@ module.exports = {
|
||||
'Uses the pixel values from the specified texture (called the displacement map) to perform a displacement of an object.'
|
||||
)
|
||||
)
|
||||
.markAsOnlyWorkingFor2D()
|
||||
.addIncludeFile('Extensions/Effects/displacement-pixi-filter.js');
|
||||
const displacementProperties = displacementEffect.getProperties();
|
||||
displacementProperties
|
||||
@@ -466,6 +479,7 @@ module.exports = {
|
||||
'Applies a dotscreen effect making objects appear to be made out of black and white halftone dots like an old printer.'
|
||||
)
|
||||
)
|
||||
.markAsOnlyWorkingFor2D()
|
||||
.addIncludeFile('Extensions/Effects/pixi-filters/filter-dot.js')
|
||||
.addIncludeFile('Extensions/Effects/dot-pixi-filter.js');
|
||||
const dotProperties = dotEffect.getProperties();
|
||||
@@ -486,6 +500,7 @@ module.exports = {
|
||||
.addEffect('DropShadow')
|
||||
.setFullName(_('Drop shadow'))
|
||||
.setDescription(_('Add a shadow around the rendered image.'))
|
||||
.markAsOnlyWorkingFor2D()
|
||||
.addIncludeFile('Extensions/Effects/pixi-filters/filter-kawase-blur.js')
|
||||
.addIncludeFile('Extensions/Effects/pixi-filters/filter-drop-shadow.js')
|
||||
.addIncludeFile('Extensions/Effects/drop-shadow-pixi-filter.js');
|
||||
@@ -536,6 +551,7 @@ module.exports = {
|
||||
.addEffect('Glitch')
|
||||
.setFullName(_('Glitch'))
|
||||
.setDescription(_('Applies a glitch effect to an object.'))
|
||||
.markAsOnlyWorkingFor2D()
|
||||
.addIncludeFile('Extensions/Effects/pixi-filters/filter-glitch.js')
|
||||
.addIncludeFile('Extensions/Effects/glitch-pixi-filter.js');
|
||||
const glitchProperties = glitchEffect.getProperties();
|
||||
@@ -626,6 +642,7 @@ module.exports = {
|
||||
.addEffect('Glow')
|
||||
.setFullName(_('Glow'))
|
||||
.setDescription(_('Add a glow effect around the rendered image.'))
|
||||
.markAsOnlyWorkingFor2D()
|
||||
.addIncludeFile('Extensions/Effects/pixi-filters/filter-glow.js')
|
||||
.addIncludeFile('Extensions/Effects/glow-pixi-filter.js');
|
||||
const glowProperties = glowEffect.getProperties();
|
||||
@@ -654,6 +671,7 @@ module.exports = {
|
||||
.addEffect('Godray')
|
||||
.setFullName(_('Godray'))
|
||||
.setDescription(_('Apply and animate atmospheric light rays.'))
|
||||
.markAsOnlyWorkingFor2D()
|
||||
.addIncludeFile('Extensions/Effects/pixi-filters/filter-godray.js')
|
||||
.addIncludeFile('Extensions/Effects/godray-pixi-filter.js');
|
||||
const godrayProperties = godrayEffect.getProperties();
|
||||
@@ -713,6 +731,7 @@ module.exports = {
|
||||
.setDescription(
|
||||
_('Blur the rendered image, with much better performance than Gaussian blur.')
|
||||
)
|
||||
.markAsOnlyWorkingFor2D()
|
||||
.addIncludeFile('Extensions/Effects/pixi-filters/filter-kawase-blur.js')
|
||||
.addIncludeFile('Extensions/Effects/kawase-blur-pixi-filter.js');
|
||||
const kawaseBlurProperties = kawaseBlurEffect.getProperties();
|
||||
@@ -747,6 +766,7 @@ module.exports = {
|
||||
.addEffect('LightNight')
|
||||
.setFullName(_('Light Night'))
|
||||
.setDescription(_('Alter the colors to simulate night.'))
|
||||
.markAsOnlyWorkingFor2D()
|
||||
.addIncludeFile('Extensions/Effects/light-night-pixi-filter.js');
|
||||
const lightNightProperties = lightNightEffect.getProperties();
|
||||
lightNightProperties
|
||||
@@ -759,6 +779,7 @@ module.exports = {
|
||||
.addEffect('Night')
|
||||
.setFullName(_('Dark Night'))
|
||||
.setDescription(_('Alter the colors to simulate a dark night.'))
|
||||
.markAsOnlyWorkingFor2D()
|
||||
.addIncludeFile('Extensions/Effects/night-pixi-filter.js');
|
||||
const nightProperties = nightEffect.getProperties();
|
||||
nightProperties
|
||||
@@ -776,6 +797,7 @@ module.exports = {
|
||||
.addEffect('Noise')
|
||||
.setFullName(_('Noise'))
|
||||
.setDescription(_('Add some noise on the rendered image.'))
|
||||
.markAsOnlyWorkingFor2D()
|
||||
.addIncludeFile('Extensions/Effects/noise-pixi-filter.js');
|
||||
const noiseProperties = noiseEffect.getProperties();
|
||||
noiseProperties
|
||||
@@ -788,6 +810,7 @@ module.exports = {
|
||||
.addEffect('OldFilm')
|
||||
.setFullName(_('Old Film'))
|
||||
.setDescription(_('Add a Old film effect around the rendered image.'))
|
||||
.markAsOnlyWorkingFor2D()
|
||||
.addIncludeFile('Extensions/Effects/pixi-filters/filter-old-film.js')
|
||||
.addIncludeFile('Extensions/Effects/old-film-pixi-filter.js');
|
||||
const oldFilmProperties = oldFilmEffect.getProperties();
|
||||
@@ -858,6 +881,7 @@ module.exports = {
|
||||
.addEffect('Outline')
|
||||
.setFullName(_('Outline'))
|
||||
.setDescription(_('Draws an outline around the rendered image.'))
|
||||
.markAsOnlyWorkingFor2D()
|
||||
.addIncludeFile('Extensions/Effects/pixi-filters/filter-outline.js')
|
||||
.addIncludeFile('Extensions/Effects/outline-pixi-filter.js');
|
||||
const outlineProperties = outlineEffect.getProperties();
|
||||
@@ -884,6 +908,7 @@ module.exports = {
|
||||
.setDescription(
|
||||
_("Applies a pixelate effect, making display objects appear 'blocky'.")
|
||||
)
|
||||
.markAsOnlyWorkingFor2D()
|
||||
.addIncludeFile('Extensions/Effects/pixi-filters/filter-pixelate.js')
|
||||
.addIncludeFile('Extensions/Effects/pixelate-pixi-filter.js');
|
||||
const pixelateProperties = pixelateEffect.getProperties();
|
||||
@@ -898,6 +923,7 @@ module.exports = {
|
||||
.addEffect('RadialBlur')
|
||||
.setFullName(_('Radial Blur'))
|
||||
.setDescription(_('Applies a Motion blur to an object.'))
|
||||
.markAsOnlyWorkingFor2D()
|
||||
.addIncludeFile('Extensions/Effects/pixi-filters/filter-radial-blur.js')
|
||||
.addIncludeFile('Extensions/Effects/radial-blur-pixi-filter.js')
|
||||
.markAsNotWorkingForObjects(); // See https://github.com/pixijs/filters/issues/304
|
||||
@@ -945,6 +971,7 @@ module.exports = {
|
||||
'Applies a reflection effect to simulate the reflection on water with waves.'
|
||||
)
|
||||
)
|
||||
.markAsOnlyWorkingFor2D()
|
||||
.addIncludeFile('Extensions/Effects/pixi-filters/filter-reflection.js')
|
||||
.addIncludeFile('Extensions/Effects/reflection-pixi-filter.js');
|
||||
const reflectionProperties = reflectionEffect.getProperties();
|
||||
@@ -1014,6 +1041,7 @@ module.exports = {
|
||||
.setDescription(
|
||||
_('Applies a RGB split effect also known as chromatic aberration.')
|
||||
)
|
||||
.markAsOnlyWorkingFor2D()
|
||||
.addIncludeFile('Extensions/Effects/pixi-filters/filter-rgb-split.js')
|
||||
.addIncludeFile('Extensions/Effects/rgb-split-pixi-filter.js');
|
||||
const rgbSplitProperties = rgbSplitEffect.getProperties();
|
||||
@@ -1052,6 +1080,7 @@ module.exports = {
|
||||
.addEffect('Sepia')
|
||||
.setFullName(_('Sepia'))
|
||||
.setDescription(_('Alter the colors to sepia.'))
|
||||
.markAsOnlyWorkingFor2D()
|
||||
.addIncludeFile('Extensions/Effects/sepia-pixi-filter.js');
|
||||
const sepiaProperties = sepiaEffect.getProperties();
|
||||
sepiaProperties
|
||||
@@ -1064,6 +1093,7 @@ module.exports = {
|
||||
.addEffect('TiltShift')
|
||||
.setFullName(_('Tilt shift'))
|
||||
.setDescription(_('Render a tilt-shift-like camera effect.'))
|
||||
.markAsOnlyWorkingFor2D()
|
||||
.addIncludeFile('Extensions/Effects/pixi-filters/filter-tilt-shift.js')
|
||||
.addIncludeFile('Extensions/Effects/tilt-shift-pixi-filter.js');
|
||||
const tiltShiftProperties = tiltShiftEffect.getProperties();
|
||||
@@ -1086,6 +1116,7 @@ module.exports = {
|
||||
'Applies a twist effect making objects appear twisted in the given direction.'
|
||||
)
|
||||
)
|
||||
.markAsOnlyWorkingFor2D()
|
||||
.addIncludeFile('Extensions/Effects/pixi-filters/filter-twist.js')
|
||||
.addIncludeFile('Extensions/Effects/twist-pixi-filter.js')
|
||||
.markAsNotWorkingForObjects(); // See https://github.com/pixijs/filters/issues/304
|
||||
@@ -1123,6 +1154,7 @@ module.exports = {
|
||||
.addEffect('ZoomBlur')
|
||||
.setFullName(_('Zoom blur'))
|
||||
.setDescription(_('Applies a Zoom blur.'))
|
||||
.markAsOnlyWorkingFor2D()
|
||||
.addIncludeFile('Extensions/Effects/pixi-filters/filter-zoom-blur.js')
|
||||
.addIncludeFile('Extensions/Effects/zoom-blur-pixi-filter.js')
|
||||
.markAsNotWorkingForObjects(); // See https://github.com/pixijs/filters/issues/304
|
||||
|
@@ -1,31 +1,34 @@
|
||||
namespace gdjs {
|
||||
gdjs.PixiFiltersTools.registerFilterCreator('Adjustment', {
|
||||
makePIXIFilter: function (target, effectData) {
|
||||
const adjustmentFilter = new PIXI.filters.AdjustmentFilter();
|
||||
return adjustmentFilter;
|
||||
},
|
||||
updatePreRender: function (filter, target) {},
|
||||
updateDoubleParameter: function (filter, parameterName, value) {
|
||||
const adjustmentFilter = (filter as unknown) as PIXI.filters.AdjustmentFilter;
|
||||
if (parameterName === 'gamma') {
|
||||
adjustmentFilter.gamma = value;
|
||||
} else if (parameterName === 'saturation') {
|
||||
adjustmentFilter.saturation = value;
|
||||
} else if (parameterName === 'contrast') {
|
||||
adjustmentFilter.contrast = value;
|
||||
} else if (parameterName === 'brightness') {
|
||||
adjustmentFilter.brightness = value;
|
||||
} else if (parameterName === 'red') {
|
||||
adjustmentFilter.red = value;
|
||||
} else if (parameterName === 'green') {
|
||||
adjustmentFilter.green = value;
|
||||
} else if (parameterName === 'blue') {
|
||||
adjustmentFilter.blue = value;
|
||||
} else if (parameterName === 'alpha') {
|
||||
adjustmentFilter.alpha = value;
|
||||
gdjs.PixiFiltersTools.registerFilterCreator(
|
||||
'Adjustment',
|
||||
new (class extends gdjs.PixiFiltersTools.PixiFilterCreator {
|
||||
makePIXIFilter(target, effectData) {
|
||||
const adjustmentFilter = new PIXI.filters.AdjustmentFilter();
|
||||
return adjustmentFilter;
|
||||
}
|
||||
},
|
||||
updateStringParameter: function (filter, parameterName, value) {},
|
||||
updateBooleanParameter: function (filter, parameterName, value) {},
|
||||
});
|
||||
updatePreRender(filter, target) {}
|
||||
updateDoubleParameter(filter, parameterName, value) {
|
||||
const adjustmentFilter = (filter as unknown) as PIXI.filters.AdjustmentFilter;
|
||||
if (parameterName === 'gamma') {
|
||||
adjustmentFilter.gamma = value;
|
||||
} else if (parameterName === 'saturation') {
|
||||
adjustmentFilter.saturation = value;
|
||||
} else if (parameterName === 'contrast') {
|
||||
adjustmentFilter.contrast = value;
|
||||
} else if (parameterName === 'brightness') {
|
||||
adjustmentFilter.brightness = value;
|
||||
} else if (parameterName === 'red') {
|
||||
adjustmentFilter.red = value;
|
||||
} else if (parameterName === 'green') {
|
||||
adjustmentFilter.green = value;
|
||||
} else if (parameterName === 'blue') {
|
||||
adjustmentFilter.blue = value;
|
||||
} else if (parameterName === 'alpha') {
|
||||
adjustmentFilter.alpha = value;
|
||||
}
|
||||
}
|
||||
updateStringParameter(filter, parameterName, value) {}
|
||||
updateBooleanParameter(filter, parameterName, value) {}
|
||||
})()
|
||||
);
|
||||
}
|
||||
|
@@ -1,27 +1,30 @@
|
||||
namespace gdjs {
|
||||
gdjs.PixiFiltersTools.registerFilterCreator('AdvancedBloom', {
|
||||
makePIXIFilter: function (target, effectData) {
|
||||
const advancedBloomFilter = new PIXI.filters.AdvancedBloomFilter();
|
||||
return advancedBloomFilter;
|
||||
},
|
||||
updatePreRender: function (filter, target) {},
|
||||
updateDoubleParameter: function (filter, parameterName, value) {
|
||||
const advancedBloomFilter = (filter as unknown) as PIXI.filters.AdvancedBloomFilter;
|
||||
if (parameterName === 'threshold') {
|
||||
advancedBloomFilter.threshold = value;
|
||||
} else if (parameterName === 'bloomScale') {
|
||||
advancedBloomFilter.bloomScale = value;
|
||||
} else if (parameterName === 'brightness') {
|
||||
advancedBloomFilter.brightness = value;
|
||||
} else if (parameterName === 'blur') {
|
||||
advancedBloomFilter.blur = value;
|
||||
} else if (parameterName === 'quality') {
|
||||
advancedBloomFilter.quality = value;
|
||||
} else if (parameterName === 'padding') {
|
||||
advancedBloomFilter.padding = value;
|
||||
gdjs.PixiFiltersTools.registerFilterCreator(
|
||||
'AdvancedBloom',
|
||||
new (class extends gdjs.PixiFiltersTools.PixiFilterCreator {
|
||||
makePIXIFilter(target, effectData) {
|
||||
const advancedBloomFilter = new PIXI.filters.AdvancedBloomFilter();
|
||||
return advancedBloomFilter;
|
||||
}
|
||||
},
|
||||
updateStringParameter: function (filter, parameterName, value) {},
|
||||
updateBooleanParameter: function (filter, parameterName, value) {},
|
||||
});
|
||||
updatePreRender(filter, target) {}
|
||||
updateDoubleParameter(filter, parameterName, value) {
|
||||
const advancedBloomFilter = (filter as unknown) as PIXI.filters.AdvancedBloomFilter;
|
||||
if (parameterName === 'threshold') {
|
||||
advancedBloomFilter.threshold = value;
|
||||
} else if (parameterName === 'bloomScale') {
|
||||
advancedBloomFilter.bloomScale = value;
|
||||
} else if (parameterName === 'brightness') {
|
||||
advancedBloomFilter.brightness = value;
|
||||
} else if (parameterName === 'blur') {
|
||||
advancedBloomFilter.blur = value;
|
||||
} else if (parameterName === 'quality') {
|
||||
advancedBloomFilter.quality = value;
|
||||
} else if (parameterName === 'padding') {
|
||||
advancedBloomFilter.padding = value;
|
||||
}
|
||||
}
|
||||
updateStringParameter(filter, parameterName, value) {}
|
||||
updateBooleanParameter(filter, parameterName, value) {}
|
||||
})()
|
||||
);
|
||||
}
|
||||
|
@@ -1,17 +1,20 @@
|
||||
namespace gdjs {
|
||||
gdjs.PixiFiltersTools.registerFilterCreator('Ascii', {
|
||||
makePIXIFilter: function (target, effectData) {
|
||||
const asciiFilter = new PIXI.filters.AsciiFilter();
|
||||
return asciiFilter;
|
||||
},
|
||||
updatePreRender: function (filter, target) {},
|
||||
updateDoubleParameter: function (filter, parameterName, value) {
|
||||
const asciiFilter = (filter as unknown) as PIXI.filters.AsciiFilter;
|
||||
if (parameterName === 'size') {
|
||||
asciiFilter.size = value;
|
||||
gdjs.PixiFiltersTools.registerFilterCreator(
|
||||
'Ascii',
|
||||
new (class extends gdjs.PixiFiltersTools.PixiFilterCreator {
|
||||
makePIXIFilter(target, effectData) {
|
||||
const asciiFilter = new PIXI.filters.AsciiFilter();
|
||||
return asciiFilter;
|
||||
}
|
||||
},
|
||||
updateStringParameter: function (filter, parameterName, value) {},
|
||||
updateBooleanParameter: function (filter, parameterName, value) {},
|
||||
});
|
||||
updatePreRender(filter, target) {}
|
||||
updateDoubleParameter(filter, parameterName, value) {
|
||||
const asciiFilter = (filter as unknown) as PIXI.filters.AsciiFilter;
|
||||
if (parameterName === 'size') {
|
||||
asciiFilter.size = value;
|
||||
}
|
||||
}
|
||||
updateStringParameter(filter, parameterName, value) {}
|
||||
updateBooleanParameter(filter, parameterName, value) {}
|
||||
})()
|
||||
);
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user