Skip to content

Commit

Permalink
Add support for visual effects ("shaders") on objects. (#2901)
Browse files Browse the repository at this point in the history
* This allows to generate interesting visual effects, which can be controlled by events. For example, you can use an outline on an object to highlight, make the player glow when launching a spell, blur objects, etc...
* A new "effects" tab is now present in the objects editor. From there, you can add visual effects, that were already available for layers, customize them from this editor.
* Actions and conditions are available to manipulate effects and change their parameters during the game.
* Learn more on the wiki: http://wiki.compilgames.net/doku.php/gdevelop5/objects/effects

Co-authored-by: Florian Rival <[email protected]>
  • Loading branch information
HarsimranVirk and 4ian authored Aug 20, 2021
1 parent b97f716 commit 599ccb6
Show file tree
Hide file tree
Showing 108 changed files with 1,882 additions and 780 deletions.
25 changes: 23 additions & 2 deletions Core/GDCore/Events/CodeGeneration/EffectsCodeGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@
* Copyright 2008-present Florian Rival ([email protected]). All rights
* reserved. This project is released under the MIT License.
*/
#include <iostream>
#include "EffectsCodeGenerator.h"

#include <iostream>

#include "GDCore/Extensions/Metadata/EffectMetadata.h"
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
#include "GDCore/Project/Effect.h"
#include "GDCore/Project/Layer.h"
#include "GDCore/Project/EffectsContainer.h"
#include "GDCore/Project/Layer.h"
#include "GDCore/Project/Layout.h"
#include "GDCore/Project/Object.h"
#include "GDCore/Project/Project.h"

namespace gd {
Expand All @@ -33,6 +36,24 @@ void ExposeProjectEffects(
worker(effect);
}
}

for (std::size_t i; i < layout.GetObjectsCount(); i++) {
auto& object = layout.GetObject(i);
auto& effects = object.GetEffects();
for (std::size_t e = 0; e < effects.GetEffectsCount(); e++) {
auto& effect = effects.GetEffect(e);
worker(effect);
}
}
}

// Add global object effects
for (std::size_t s = 0; s < project.GetObjectsCount(); s++) {
auto& effects = project.GetObject(s).GetEffects();
for (std::size_t e = 0; e < effects.GetEffectsCount(); e++) {
auto& effect = effects.GetEffect(e);
worker(effect);
}
}
}

Expand Down
68 changes: 68 additions & 0 deletions Core/GDCore/Extensions/Builtin/BaseObjectExtension.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1072,6 +1072,74 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
.AddParameter("expression", _("Target X position"))
.AddParameter("expression", _("Target Y position"));

obj.AddAction("EnableEffect",
_("Enable an object effect"),
_("Enable an effect on the object"),
_("Enable effect _PARAM1_ on _PARAM0_: _PARAM2_"),
_("Effects"),
"res/actions/effect24.png",
"res/actions/effect.png")
.AddParameter("object", _("Object"))
.AddParameter("string", _("Effect Name"))
.AddParameter("yesorno", _("Enable?"))
.MarkAsSimple();

obj.AddAction("SetEffectDoubleParameter",
_("Effect parameter (number)"),
_("Change the value of a parameter of an effect.") + "\n" +
_("You can find the parameter names (and change the effect "
"names) in the effects window."),
_("Set _PARAM2_ to _PARAM3_ for effect _PARAM1_ of _PARAM0_"),
_("Effects"),
"res/actions/effect24.png",
"res/actions/effect.png")
.AddParameter("object", _("Object"))
.AddParameter("string", _("Effect Name"))
.AddParameter("string", _("Parameter name"))
.AddParameter("expression", _("New value"))
.MarkAsSimple();

obj.AddAction("SetEffectStringParameter",
_("Effect parameter (string)"),
_("Change the value (string) of a parameter of an effect.") + "\n" +
_("You can find the parameter names (and change the effect "
"names) in the effects window."),
_("Set _PARAM2_ to _PARAM3_ for effect _PARAM1_ of _PARAM0_"),
_("Effects"),
"res/actions/effect24.png",
"res/actions/effect.png")
.AddParameter("object", _("Object"))
.AddParameter("string", _("Effect Name"))
.AddParameter("string", _("Parameter name"))
.AddParameter("string", _("New value"))
.MarkAsSimple();

obj.AddAction("SetEffectBooleanParameter",
_("Effect parameter (enable or disable)"),
_("Enable or disable a parameter of an effect.") + "\n" +
_("You can find the parameter names (and change the effect "
"names) in the effects window."),
_("Enable _PARAM2_ for effect _PARAM1_ of _PARAM0_: _PARAM3_"),
_("Effects"),
"res/actions/effect24.png",
"res/actions/effect.png")
.AddParameter("object", _("Object"))
.AddParameter("string", _("Effect Name"))
.AddParameter("string", _("Parameter Name"))
.AddParameter("yesorno", _("Enable?"))
.MarkAsSimple();

obj.AddCondition("IsEffectEnabled",
_("Effect is enabled"),
_("Check if the effect on an object is enabled."),
_("Effect _PARAM1_ of _PARAM0_ is enabled"),
_("Effects"),
"res/actions/effect24.png",
"res/actions/effect.png")
.AddParameter("object", _("Object"))
.AddParameter("string", _("Effect Name"))
.MarkAsSimple();

extension
.AddAction("Create",
_("Create an object"),
Expand Down
8 changes: 7 additions & 1 deletion Core/GDCore/Extensions/Metadata/EffectMetadata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@

namespace gd {

EffectMetadata::EffectMetadata(const gd::String& type_) : type(type_) {}
EffectMetadata::EffectMetadata(const gd::String& type_)
: type(type_), isMarkedAsNotWorkingForObjects(false) {}

EffectMetadata& EffectMetadata::SetIncludeFile(const gd::String& includeFile) {
includeFiles.clear();
Expand All @@ -22,4 +23,9 @@ EffectMetadata& EffectMetadata::AddIncludeFile(const gd::String& includeFile) {
return *this;
}

EffectMetadata& EffectMetadata::MarkAsNotWorkingForObjects() {
isMarkedAsNotWorkingForObjects = true;
return *this;
}

} // namespace gd
21 changes: 18 additions & 3 deletions Core/GDCore/Extensions/Metadata/EffectMetadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <functional>
#include <map>
#include <memory>

#include "GDCore/Project/PropertyDescriptor.h"
#include "GDCore/String.h"

Expand Down Expand Up @@ -49,7 +50,8 @@ class GD_CORE_API EffectMetadata {
};

/**
* Set the help path of the effect, relative to the GDevelop documentation root.
* Set the help path of the effect, relative to the GDevelop documentation
* root.
*/
EffectMetadata& SetHelpPath(const gd::String& path) {
helpPath = path;
Expand All @@ -66,6 +68,11 @@ 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.
*/
Expand All @@ -81,12 +88,14 @@ class GD_CORE_API EffectMetadata {
}

/**
* \brief Get the help path of the effect, relative to the GDevelop documentation root.
* \brief Get the help path of the effect, relative to the GDevelop
* documentation root.
*/
const gd::String& GetHelpPath() const { return helpPath; }

/**
* \brief Get the type of the effect (its internal name, like "BlackAndWhite").
* \brief Get the type of the effect (its internal name, like
* "BlackAndWhite").
*/
const gd::String& GetType() const { return type; }

Expand All @@ -107,13 +116,19 @@ class GD_CORE_API EffectMetadata {
return includeFiles;
}

/**
* \brief Check if the effect is marked as not working as an object effect.
*/
bool IsMarkedAsNotWorkingForObjects() const { return isMarkedAsNotWorkingForObjects; };

private:
gd::String extensionNamespace;
gd::String type;
gd::String helpPath;
gd::String fullname;
gd::String description;
std::vector<gd::String> includeFiles;
bool isMarkedAsNotWorkingForObjects;
std::map<gd::String, gd::PropertyDescriptor> properties;
};

Expand Down
9 changes: 6 additions & 3 deletions Extensions/Effects/JsExtension.js
Original file line number Diff line number Diff line change
Expand Up @@ -897,7 +897,8 @@ module.exports = {
.setFullName(_('Radial Blur'))
.setDescription(_('Applies a Motion blur to an object.'))
.addIncludeFile('Extensions/Effects/pixi-filters/filter-radial-blur.js')
.addIncludeFile('Extensions/Effects/radial-blur-pixi-filter.js');
.addIncludeFile('Extensions/Effects/radial-blur-pixi-filter.js')
.markAsNotWorkingForObjects(); // See https://github.com/pixijs/filters/issues/304
const radialBlurProperties = radialBlurEffect.getProperties();
radialBlurProperties
.getOrCreate('radius')
Expand Down Expand Up @@ -1084,7 +1085,8 @@ module.exports = {
)
)
.addIncludeFile('Extensions/Effects/pixi-filters/filter-twist.js')
.addIncludeFile('Extensions/Effects/twist-pixi-filter.js');
.addIncludeFile('Extensions/Effects/twist-pixi-filter.js')
.markAsNotWorkingForObjects(); // See https://github.com/pixijs/filters/issues/304
const twistProperties = twistEffect.getProperties();
twistProperties
.getOrCreate('radius')
Expand Down Expand Up @@ -1120,7 +1122,8 @@ module.exports = {
.setFullName(_('Zoom blur'))
.setDescription(_('Applies a Zoom blur.'))
.addIncludeFile('Extensions/Effects/pixi-filters/filter-zoom-blur.js')
.addIncludeFile('Extensions/Effects/zoom-blur-pixi-filter.js');
.addIncludeFile('Extensions/Effects/zoom-blur-pixi-filter.js')
.markAsNotWorkingForObjects(); // See https://github.com/pixijs/filters/issues/304
const zoomBlurProperties = zoomBlurEffect.getProperties();
zoomBlurProperties
.getOrCreate('centerX')
Expand Down
4 changes: 2 additions & 2 deletions Extensions/Effects/adjustment-pixi-filter.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
namespace gdjs {
gdjs.PixiFiltersTools.registerFilterCreator('Adjustment', {
makePIXIFilter: function (layer, effectData) {
makePIXIFilter: function (target, effectData) {
const adjustmentFilter = new PIXI.filters.AdjustmentFilter();
return adjustmentFilter;
},
update: function (filter, layer) {},
updatePreRender: function (filter, target) {},
updateDoubleParameter: function (filter, parameterName, value) {
const adjustmentFilter = (filter as unknown) as PIXI.filters.AdjustmentFilter;
if (parameterName === 'gamma') {
Expand Down
4 changes: 2 additions & 2 deletions Extensions/Effects/advanced-bloom-pixi-filter.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
namespace gdjs {
gdjs.PixiFiltersTools.registerFilterCreator('AdvancedBloom', {
makePIXIFilter: function (layer, effectData) {
makePIXIFilter: function (target, effectData) {
const advancedBloomFilter = new PIXI.filters.AdvancedBloomFilter();
return advancedBloomFilter;
},
update: function (filter, layer) {},
updatePreRender: function (filter, target) {},
updateDoubleParameter: function (filter, parameterName, value) {
const advancedBloomFilter = (filter as unknown) as PIXI.filters.AdvancedBloomFilter;
if (parameterName === 'threshold') {
Expand Down
4 changes: 2 additions & 2 deletions Extensions/Effects/ascii-pixi-filter.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
namespace gdjs {
gdjs.PixiFiltersTools.registerFilterCreator('Ascii', {
makePIXIFilter: function (layer, effectData) {
makePIXIFilter: function (target, effectData) {
const asciiFilter = new PIXI.filters.AsciiFilter();
return asciiFilter;
},
update: function (filter, layer) {},
updatePreRender: function (filter, target) {},
updateDoubleParameter: function (filter, parameterName, value) {
const asciiFilter = (filter as unknown) as PIXI.filters.AsciiFilter;
if (parameterName === 'size') {
Expand Down
4 changes: 2 additions & 2 deletions Extensions/Effects/bevel-pixi-filter.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
namespace gdjs {
gdjs.PixiFiltersTools.registerFilterCreator('Bevel', {
makePIXIFilter: function (layer, effectData) {
makePIXIFilter: function (target, effectData) {
const bevelFilter = new PIXI.filters.BevelFilter();
return bevelFilter;
},
update: function (filter, layer) {},
updatePreRender: function (filter, target) {},
updateDoubleParameter: function (filter, parameterName, value) {
const bevelFilter = (filter as unknown) as PIXI.filters.BevelFilter;
if (parameterName === 'rotation') {
Expand Down
4 changes: 2 additions & 2 deletions Extensions/Effects/black-and-white-pixi-filter.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
namespace gdjs {
import PIXI = GlobalPIXIModule.PIXI;
gdjs.PixiFiltersTools.registerFilterCreator('BlackAndWhite', {
makePIXIFilter: function (layer, effectData) {
makePIXIFilter: function (target, effectData) {
const colorMatrix = new PIXI.filters.ColorMatrixFilter();
colorMatrix.blackAndWhite(false);
return colorMatrix;
},
update: function (filter, layer) {},
updatePreRender: function (filter, target) {},
updateDoubleParameter: function (filter, parameterName, value) {
// @ts-ignore - unsure why PIXI.filters is not recognised.
const colorMatrix = (filter as unknown) as PIXI.filters.ColorMatrixFilter;
Expand Down
4 changes: 2 additions & 2 deletions Extensions/Effects/blending-mode-pixi-filter.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
namespace gdjs {
import PIXI = GlobalPIXIModule.PIXI;
gdjs.PixiFiltersTools.registerFilterCreator('BlendingMode', {
makePIXIFilter: function (layer, effectData) {
makePIXIFilter: function (target, effectData) {
const blendingModeFilter = new PIXI.filters.AlphaFilter();
return blendingModeFilter;
},
update: function (filter, layer) {},
updatePreRender: function (filter, target) {},
updateDoubleParameter: function (filter, parameterName, value) {
// @ts-ignore - unsure why PIXI.filters is not recognised.
const blendingModeFilter = (filter as unknown) as PIXI.filters.AlphaFilter;
Expand Down
4 changes: 2 additions & 2 deletions Extensions/Effects/blur-pixi-filter.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
namespace gdjs {
import PIXI = GlobalPIXIModule.PIXI;
gdjs.PixiFiltersTools.registerFilterCreator('Blur', {
makePIXIFilter: function (layer, effectData) {
makePIXIFilter: function (target, effectData) {
const blur = new PIXI.filters.BlurFilter();
return blur;
},
update: function (filter, layer) {},
updatePreRender: function (filter, target) {},
updateDoubleParameter: function (filter, parameterName, value) {
if (
parameterName !== 'blur' &&
Expand Down
4 changes: 2 additions & 2 deletions Extensions/Effects/brightness-pixi-filter.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
namespace gdjs {
import PIXI = GlobalPIXIModule.PIXI;
gdjs.PixiFiltersTools.registerFilterCreator('Brightness', {
makePIXIFilter: function (layer, effectData) {
makePIXIFilter: function (target, effectData) {
const brightness = new PIXI.filters.ColorMatrixFilter();
brightness.brightness(1, false);
return brightness;
},
update: function (filter, layer) {},
updatePreRender: function (filter, target) {},
updateDoubleParameter: function (filter, parameterName, value) {
// @ts-ignore - unsure why PIXI.filters is not recognised.
const brightnessFilter = (filter as unknown) as PIXI.filters.ColorMatrixFilter;
Expand Down
4 changes: 2 additions & 2 deletions Extensions/Effects/bulge-pinch-pixi-filter.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
namespace gdjs {
gdjs.PixiFiltersTools.registerFilterCreator('BulgePinch', {
makePIXIFilter: function (layer, effectData) {
makePIXIFilter: function (target, effectData) {
const bulgePinchFilter = new PIXI.filters.BulgePinchFilter();
return bulgePinchFilter;
},
update: function (filter, layer) {},
updatePreRender: function (filter, target) {},
updateDoubleParameter: function (filter, parameterName, value) {
const bulgePinchFilter = (filter as unknown) as PIXI.filters.BulgePinchFilter;
if (parameterName === 'centerX') {
Expand Down
6 changes: 3 additions & 3 deletions Extensions/Effects/color-map-pixi-filter.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
namespace gdjs {
gdjs.PixiFiltersTools.registerFilterCreator('ColorMap', {
makePIXIFilter: function (layer, effectData) {
const colorMapTexture = layer
makePIXIFilter: function (target, effectData) {
const colorMapTexture = target
.getRuntimeScene()
.getGame()
.getImageManager()
Expand All @@ -17,7 +17,7 @@ namespace gdjs {
);
return colorMapFilter;
},
update: function (filter, layer) {},
updatePreRender: function (filter, target) {},
updateDoubleParameter: function (filter, parameterName, value) {
const colorMapFilter = (filter as unknown) as PIXI.filters.ColorMapFilter;
if (parameterName === 'mix') {
Expand Down
4 changes: 2 additions & 2 deletions Extensions/Effects/color-replace-pixi-filter.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
namespace gdjs {
gdjs.PixiFiltersTools.registerFilterCreator('ColorReplace', {
makePIXIFilter: function (layer, effectData) {
makePIXIFilter: function (target, effectData) {
const colorReplaceFilter = new PIXI.filters.ColorReplaceFilter();
return colorReplaceFilter;
},
update: function (filter, layer) {},
updatePreRender: function (filter, target) {},
updateDoubleParameter: function (filter, parameterName, value) {
const colorReplaceFilter = (filter as unknown) as PIXI.filters.ColorReplaceFilter;
if (parameterName === 'epsilon') {
Expand Down
Loading

0 comments on commit 599ccb6

Please sign in to comment.