mirror of https://github.com/minetest/minetest.git
Merge 69b2a3b9f1
into d4b10db998
This commit is contained in:
commit
cf4e871b6d
|
@ -39,6 +39,7 @@ core.features = {
|
||||||
dynamic_add_media_filepath = true,
|
dynamic_add_media_filepath = true,
|
||||||
lsystem_decoration_type = true,
|
lsystem_decoration_type = true,
|
||||||
item_meta_range = true,
|
item_meta_range = true,
|
||||||
|
particle_blend_clip = true,
|
||||||
}
|
}
|
||||||
|
|
||||||
function core.has_feature(arg)
|
function core.has_feature(arg)
|
||||||
|
|
|
@ -5431,6 +5431,8 @@ Utilities
|
||||||
lsystem_decoration_type = true,
|
lsystem_decoration_type = true,
|
||||||
-- Overrideable pointing range using the itemstack meta key `"range"` (5.9.0)
|
-- Overrideable pointing range using the itemstack meta key `"range"` (5.9.0)
|
||||||
item_meta_range = true,
|
item_meta_range = true,
|
||||||
|
-- Particles can specify a "clip" blend mode
|
||||||
|
particle_blend_clip = true,
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -10562,7 +10564,9 @@ Used by `minetest.add_particle`.
|
||||||
texture = "image.png",
|
texture = "image.png",
|
||||||
-- The texture of the particle
|
-- The texture of the particle
|
||||||
-- v5.6.0 and later: also supports the table format described in the
|
-- v5.6.0 and later: also supports the table format described in the
|
||||||
-- following section
|
-- following section, but due to a bug this did not take effect
|
||||||
|
-- (beyond the texture name).
|
||||||
|
-- v5.9.0 and later: fixes the bug.
|
||||||
|
|
||||||
playername = "singleplayer",
|
playername = "singleplayer",
|
||||||
-- Optional, if specified spawns particle only on the player's client
|
-- Optional, if specified spawns particle only on the player's client
|
||||||
|
@ -10909,6 +10913,14 @@ texture = {
|
||||||
-- (default) blends transparent pixels with those they are drawn atop
|
-- (default) blends transparent pixels with those they are drawn atop
|
||||||
-- according to the alpha channel of the source texture. useful for
|
-- according to the alpha channel of the source texture. useful for
|
||||||
-- e.g. material objects like rocks, dirt, smoke, or node chunks
|
-- e.g. material objects like rocks, dirt, smoke, or node chunks
|
||||||
|
blend = "clip",
|
||||||
|
-- pixels are either fully opaque or fully transparent,
|
||||||
|
-- depending on whether alpha is greater than or less than 50%
|
||||||
|
-- (similar to `use_texture_alpha = "clip"` for nodes).
|
||||||
|
-- this fixes rendering bugs (invisibility) that occur when particles
|
||||||
|
-- interact with translucent nodes
|
||||||
|
-- (see https://github.com/minetest/minetest/issues/3761).
|
||||||
|
-- in the future, it may be useful for better performance.
|
||||||
blend = "add",
|
blend = "add",
|
||||||
-- adds the value of pixels to those underneath them, modulo the sources
|
-- adds the value of pixels to those underneath them, modulo the sources
|
||||||
-- alpha channel. useful for e.g. bright light effects like sparks or fire
|
-- alpha channel. useful for e.g. bright light effects like sparks or fire
|
||||||
|
|
|
@ -1,14 +1,27 @@
|
||||||
|
local function spawn_clip_test_particle(pos)
|
||||||
|
minetest.add_particle({
|
||||||
|
pos = pos,
|
||||||
|
size = 5,
|
||||||
|
expirationtime = 10,
|
||||||
|
texture = {
|
||||||
|
name = "testtools_particle_clip.png",
|
||||||
|
blend = "clip",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
minetest.register_tool("testtools:particle_spawner", {
|
minetest.register_tool("testtools:particle_spawner", {
|
||||||
description = "Particle Spawner".."\n"..
|
description = table.concat({
|
||||||
|
"Particle Spawner",
|
||||||
"Punch: Spawn random test particle",
|
"Punch: Spawn random test particle",
|
||||||
|
"Place: Spawn clip test particle",
|
||||||
|
}, "\n"),
|
||||||
inventory_image = "testtools_particle_spawner.png",
|
inventory_image = "testtools_particle_spawner.png",
|
||||||
groups = { testtool = 1, disable_repair = 1 },
|
groups = { testtool = 1, disable_repair = 1 },
|
||||||
on_use = function(itemstack, user, pointed_thing)
|
on_use = function(itemstack, user, pointed_thing)
|
||||||
local pos = minetest.get_pointed_thing_position(pointed_thing, true)
|
local pos = minetest.get_pointed_thing_position(pointed_thing, true)
|
||||||
if pos == nil then
|
if pos == nil then
|
||||||
if user then
|
pos = assert(user):get_pos()
|
||||||
pos = user:get_pos()
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
pos = vector.add(pos, {x=0, y=0.5, z=0})
|
pos = vector.add(pos, {x=0, y=0.5, z=0})
|
||||||
local tex, anim
|
local tex, anim
|
||||||
|
@ -32,5 +45,12 @@ minetest.register_tool("testtools:particle_spawner", {
|
||||||
glow = math.random(0, 5),
|
glow = math.random(0, 5),
|
||||||
})
|
})
|
||||||
end,
|
end,
|
||||||
|
on_place = function(itemstack, user, pointed_thing)
|
||||||
|
local pos = assert(minetest.get_pointed_thing_position(pointed_thing, true))
|
||||||
|
spawn_clip_test_particle(pos)
|
||||||
|
end,
|
||||||
|
on_secondary_use = function(_, user)
|
||||||
|
spawn_clip_test_particle(assert(user):get_pos())
|
||||||
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 179 B |
|
@ -18,7 +18,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "particles.h"
|
#include "particles.h"
|
||||||
|
#include <EMaterialTypes.h>
|
||||||
|
#include <SMaterial.h>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <stdexcept>
|
||||||
#include "client.h"
|
#include "client.h"
|
||||||
#include "collision.h"
|
#include "collision.h"
|
||||||
#include "client/content_cao.h"
|
#include "client/content_cao.h"
|
||||||
|
@ -75,36 +78,30 @@ Particle::Particle(
|
||||||
// Set material
|
// Set material
|
||||||
{
|
{
|
||||||
// translate blend modes to GL blend functions
|
// translate blend modes to GL blend functions
|
||||||
video::E_BLEND_FACTOR bfsrc, bfdst;
|
bool blend = true;
|
||||||
video::E_BLEND_OPERATION blendop;
|
video::E_BLEND_FACTOR bfsrc = video::EBF_SRC_ALPHA, bfdst = video::EBF_DST_ALPHA;
|
||||||
|
video::E_BLEND_OPERATION blendop = video::EBO_ADD;
|
||||||
const auto blendmode = texture.tex != nullptr
|
const auto blendmode = texture.tex != nullptr
|
||||||
? texture.tex->blendmode
|
? texture.tex->blendmode
|
||||||
: ParticleParamTypes::BlendMode::alpha;
|
: ParticleParamTypes::BlendMode::alpha;
|
||||||
|
|
||||||
switch (blendmode) {
|
switch (blendmode) {
|
||||||
case ParticleParamTypes::BlendMode::add:
|
case ParticleParamTypes::BlendMode::clip:
|
||||||
bfsrc = video::EBF_SRC_ALPHA;
|
blend = false;
|
||||||
bfdst = video::EBF_DST_ALPHA;
|
break;
|
||||||
blendop = video::EBO_ADD;
|
case ParticleParamTypes::BlendMode::alpha:
|
||||||
break;
|
bfdst = video::EBF_ONE_MINUS_SRC_ALPHA;
|
||||||
|
break;
|
||||||
|
case ParticleParamTypes::BlendMode::add: break;
|
||||||
case ParticleParamTypes::BlendMode::sub:
|
case ParticleParamTypes::BlendMode::sub:
|
||||||
bfsrc = video::EBF_SRC_ALPHA;
|
|
||||||
bfdst = video::EBF_DST_ALPHA;
|
|
||||||
blendop = video::EBO_REVSUBTRACT;
|
blendop = video::EBO_REVSUBTRACT;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ParticleParamTypes::BlendMode::screen:
|
case ParticleParamTypes::BlendMode::screen:
|
||||||
bfsrc = video::EBF_ONE;
|
bfsrc = video::EBF_ONE;
|
||||||
bfdst = video::EBF_ONE_MINUS_SRC_COLOR;
|
bfdst = video::EBF_ONE_MINUS_SRC_COLOR;
|
||||||
blendop = video::EBO_ADD;
|
break;
|
||||||
break;
|
case ParticleParamTypes::BlendMode::BlendMode_END:
|
||||||
|
throw std::logic_error("invalid blend mode");
|
||||||
default: // includes ParticleParamTypes::BlendMode::alpha
|
|
||||||
bfsrc = video::EBF_SRC_ALPHA;
|
|
||||||
bfdst = video::EBF_ONE_MINUS_SRC_ALPHA;
|
|
||||||
blendop = video::EBO_ADD;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Texture
|
// Texture
|
||||||
|
@ -120,12 +117,16 @@ Particle::Particle(
|
||||||
m_material.ZWriteEnable = video::EZW_AUTO;
|
m_material.ZWriteEnable = video::EZW_AUTO;
|
||||||
|
|
||||||
// enable alpha blending and set blend mode
|
// enable alpha blending and set blend mode
|
||||||
m_material.MaterialType = video::EMT_ONETEXTURE_BLEND;
|
if (blend) {
|
||||||
m_material.MaterialTypeParam = video::pack_textureBlendFunc(
|
m_material.MaterialType = video::EMT_ONETEXTURE_BLEND;
|
||||||
bfsrc, bfdst,
|
m_material.MaterialTypeParam = video::pack_textureBlendFunc(
|
||||||
video::EMFN_MODULATE_1X,
|
bfsrc, bfdst,
|
||||||
video::EAS_TEXTURE | video::EAS_VERTEX_COLOR);
|
video::EMFN_MODULATE_1X,
|
||||||
m_material.BlendOperation = blendop;
|
video::EAS_TEXTURE | video::EAS_VERTEX_COLOR);
|
||||||
|
m_material.BlendOperation = blendop;
|
||||||
|
} else {
|
||||||
|
m_material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
|
||||||
|
}
|
||||||
m_material.setTexture(0, m_texture.ref);
|
m_material.setTexture(0, m_texture.ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,8 +142,11 @@ Particle::Particle(
|
||||||
|
|
||||||
void Particle::OnRegisterSceneNode()
|
void Particle::OnRegisterSceneNode()
|
||||||
{
|
{
|
||||||
if (IsVisible)
|
if (IsVisible) {
|
||||||
SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT_EFFECT);
|
bool solid = m_material.MaterialType == video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
|
||||||
|
SceneManager->registerNodeForRendering(this,
|
||||||
|
solid ? scene::ESNRP_SOLID : scene::ESNRP_TRANSPARENT_EFFECT);
|
||||||
|
}
|
||||||
|
|
||||||
ISceneNode::OnRegisterSceneNode();
|
ISceneNode::OnRegisterSceneNode();
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "particles.h"
|
#include "particles.h"
|
||||||
|
#include "exceptions.h"
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
using namespace ParticleParamTypes;
|
using namespace ParticleParamTypes;
|
||||||
|
@ -204,8 +205,9 @@ void ServerParticleTexture::serialize(std::ostream &os, u16 protocol_ver, bool n
|
||||||
FlagT flags = 0;
|
FlagT flags = 0;
|
||||||
if (animated)
|
if (animated)
|
||||||
flags |= FlagT(ParticleTextureFlags::animated);
|
flags |= FlagT(ParticleTextureFlags::animated);
|
||||||
if (blendmode != BlendMode::alpha)
|
// Default to `blend = "alpha"` for older clients that don't support `blend = "clip"`
|
||||||
flags |= FlagT(blendmode) << 1;
|
flags |= FlagT(protocol_ver < 44 && blendmode == BlendMode::clip
|
||||||
|
? BlendMode::alpha : blendmode) << 1;
|
||||||
serializeParameterValue(os, flags);
|
serializeParameterValue(os, flags);
|
||||||
|
|
||||||
alpha.serialize(os);
|
alpha.serialize(os);
|
||||||
|
@ -221,9 +223,14 @@ void ServerParticleTexture::deSerialize(std::istream &is, u16 protocol_ver, bool
|
||||||
{
|
{
|
||||||
FlagT flags = 0;
|
FlagT flags = 0;
|
||||||
deSerializeParameterValue(is, flags);
|
deSerializeParameterValue(is, flags);
|
||||||
|
// Backwards compatibility: Older clients don't send these, leave them at the defaults
|
||||||
|
if (is.eof())
|
||||||
|
return;
|
||||||
|
|
||||||
animated = !!(flags & FlagT(ParticleTextureFlags::animated));
|
animated = !!(flags & FlagT(ParticleTextureFlags::animated));
|
||||||
blendmode = BlendMode((flags & FlagT(ParticleTextureFlags::blend)) >> 1);
|
blendmode = BlendMode((flags & FlagT(ParticleTextureFlags::blend)) >> 1);
|
||||||
|
if (blendmode >= BlendMode::BlendMode_END)
|
||||||
|
throw SerializationError("invalid blend mode");
|
||||||
|
|
||||||
alpha.deSerialize(is);
|
alpha.deSerialize(is);
|
||||||
scale.deSerialize(is);
|
scale.deSerialize(is);
|
||||||
|
@ -254,6 +261,7 @@ void ParticleParameters::serialize(std::ostream &os, u16 protocol_ver) const
|
||||||
writeV3F32(os, drag);
|
writeV3F32(os, drag);
|
||||||
jitter.serialize(os);
|
jitter.serialize(os);
|
||||||
bounce.serialize(os);
|
bounce.serialize(os);
|
||||||
|
texture.serialize(os, protocol_ver, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, T (reader)(std::istream& is)>
|
template <typename T, T (reader)(std::istream& is)>
|
||||||
|
@ -291,4 +299,5 @@ void ParticleParameters::deSerialize(std::istream &is, u16 protocol_ver)
|
||||||
return;
|
return;
|
||||||
jitter.deSerialize(is);
|
jitter.deSerialize(is);
|
||||||
bounce.deSerialize(is);
|
bounce.deSerialize(is);
|
||||||
|
texture.deSerialize(is, protocol_ver, true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -249,7 +249,8 @@ namespace ParticleParamTypes
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class AttractorKind : u8 { none, point, line, plane };
|
enum class AttractorKind : u8 { none, point, line, plane };
|
||||||
enum class BlendMode : u8 { alpha, add, sub, screen };
|
// Note: Allows at most 8 enum members (due to how this is serialized)
|
||||||
|
enum class BlendMode : u8 { alpha, add, sub, screen, clip, BlendMode_END };
|
||||||
|
|
||||||
// these are consistently-named convenience aliases to make code more readable without `using ParticleParamTypes` declarations
|
// these are consistently-named convenience aliases to make code more readable without `using ParticleParamTypes` declarations
|
||||||
using v3fRange = RangedParameter<v3fParameter>;
|
using v3fRange = RangedParameter<v3fParameter>;
|
||||||
|
|
|
@ -133,13 +133,14 @@ namespace LuaParticleParams
|
||||||
{(int)BlendMode::add, "add"},
|
{(int)BlendMode::add, "add"},
|
||||||
{(int)BlendMode::sub, "sub"},
|
{(int)BlendMode::sub, "sub"},
|
||||||
{(int)BlendMode::screen, "screen"},
|
{(int)BlendMode::screen, "screen"},
|
||||||
|
{(int)BlendMode::clip, "clip"},
|
||||||
{0, nullptr},
|
{0, nullptr},
|
||||||
};
|
};
|
||||||
|
|
||||||
luaL_checktype(L, -1, LUA_TSTRING);
|
luaL_checktype(L, -1, LUA_TSTRING);
|
||||||
int v = (int)BlendMode::alpha;
|
int v = (int)BlendMode::alpha;
|
||||||
if (!string_to_enum(opts, v, lua_tostring(L, -1))) {
|
if (!string_to_enum(opts, v, lua_tostring(L, -1))) {
|
||||||
throw LuaError("blend mode must be one of ('alpha', 'add', 'sub', 'screen')");
|
throw LuaError("blend mode must be one of ('alpha', 'clip', 'add', 'sub', 'screen')");
|
||||||
}
|
}
|
||||||
ret = (BlendMode)v;
|
ret = (BlendMode)v;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue