Adding particle blend, glow and animation (#4705)
authorFoghrye4 <foghrye4@gmail.com>
Mon, 14 Nov 2016 14:09:59 +0000 (18:09 +0400)
committerZeno- <kde.psych@gmail.com>
Mon, 14 Nov 2016 14:09:59 +0000 (00:09 +1000)
15 files changed:
builtin/common/misc_helpers.lua
doc/lua_api.txt
src/client.h
src/network/clientpackethandler.cpp
src/nodedef.cpp
src/nodedef.h
src/particles.cpp
src/particles.h
src/script/common/c_content.cpp
src/script/common/c_content.h
src/script/common/c_converter.cpp
src/script/common/c_converter.h
src/script/lua_api/l_particles.cpp
src/server.cpp
src/server.h

index c2dc7514d71118dcdbb8d321ad67549676a59394..a495058d93a36549dfa96157e0fc8222fc033154 100644 (file)
@@ -237,6 +237,43 @@ function math.sign(x, tolerance)
        return 0
 end
 
+--------------------------------------------------------------------------------
+-- Video enums and pack function
+
+-- E_BLEND_FACTOR
+minetest.ebf = {                            
+       zero                    = 0, -- src & dest (0, 0, 0, 0)
+       one                     = 1, -- src & dest (1, 1, 1, 1)
+       dst_color               = 2, -- src (destR, destG, destB, destA)
+       one_minus_dst_color     = 3, -- src (1-destR, 1-destG, 1-destB, 1-destA)
+       src_color               = 4, -- dest (srcR, srcG, srcB, srcA)
+       one_minus_src_color     = 5, -- dest (1-srcR, 1-srcG, 1-srcB, 1-srcA)
+       src_alpha               = 6, -- src & dest (srcA, srcA, srcA, srcA)
+       one_minus_src_alpha     = 7, -- src & dest (1-srcA, 1-srcA, 1-srcA, 1-srcA)
+       dst_alpha               = 8, -- src & dest (destA, destA, destA, destA)
+       one_minus_dst_alpha     = 9, -- src & dest (1-destA, 1-destA, 1-destA, 1-destA)
+       src_alpha_saturate      = 10,-- src (min(srcA, 1-destA), idem, ...) 
+}
+
+-- E_MODULATE_FUNC
+minetest.emfn = {
+       modulate_1x    = 1,
+       modulate_2x    = 2,
+       modulate_4x    = 4,
+}
+
+-- E_ALPHA_SOURCE
+minetest.eas = {
+       none     = 0,
+       vertex_color = 1,
+       texture  = 2,
+}
+
+-- BlendFunc = source * sourceFactor + dest * destFactor
+function minetest.pack_texture_blend_func(srcFact, dstFact, modulate, alphaSource) 
+       return alphaSource * 4096 + modulate * 256 + srcFact * 16 + dstFact
+end
+
 --------------------------------------------------------------------------------
 function get_last_folder(text,count)
        local parts = text:split(DIR_DELIM)
index 7d552c98012366f336183860441af302a68e8862..3b3f176346e219f28f26dc50400f15bbd2061771 100644 (file)
@@ -414,6 +414,119 @@ the word "`alpha`", then each texture pixel will contain the RGB of
 `<color>` and the alpha of `<color>` multiplied by the alpha of the
 texture pixel.
 
+Particle blend
+--------------
+Blend function is defined by integer number.
+There is a huge number of acceptable blend modificators.
+Colour of a resulting pixel calculated using formulae:
+
+       red = source_red * source_factor + destination_red * destination_factor
+
+and so on for every channel.
+
+Here is a some examples:
+
+Default value:
+
+       material_type_param = 0,
+
+Use this value to disable blending. Texture will be applied to existing pixels
+using alpha channel of it. Its recomended to use 1-bit alpha
+in that case. This value will leave z-buffer writeable.
+
+Additive blend:
+
+       material_type_param = 12641,
+
+Source = src_alpha, destination = one, alpha source is a texture and 
+vertex_color, modulate_1x.
+Black color is completely transparent, white color is completely opaque.
+Alpha channel still used to calculate result color, but not nessesary.
+'destination = one' means that resulting color will be calculated using 
+overwritten pixels values.
+For example with color of source (our texture) RGBA = (0,192,255,63)
+"blue-cyan", 1/4 opaque.
+and already rendered pixel color (40,192,0) "dark lime green" we will get color:
+
+R = source_red(0) * source_factor(src_alpha=63/255) + 
+       destination_red(40) * destination_factor(one) =
+       0 * 63/255 + 40 * 1 = 40
+
+G = 192 * 63/255 + 192 * 1 = 239
+B = 255 * 63/255 + 0 * 1 = 63
+
+Result: (40,239,63), "green" (a kind of).
+Note, if you made a texture with some kind of shape with colour 662211h 
+it will appear dark red with a single particle, then yellow with a 
+several of them and white if player looking thru a lot of them. With 
+this you could made a nice-looking fire.
+
+Substractive blend:
+       
+       material_type_param = 12548,
+
+Source = zero, destination = src_color, alpha source is a texture and 
+vertex_color, modulate_1x.
+Texture darkness act like an alpha channel.
+Black color is completely opaque, white color is completely transparent.
+'destination = src_color' means that destination in multiplied by
+a source values. 'source = zero' means that source values ignored
+(multiplied by 0).
+
+Invert blend:
+
+       material_type_param = 12597,
+       
+Source = one_minus_dst_color, destination = one_minus_src_alpha, alpha source 
+is a texture and vertex_color, modulate_1x.
+Pixels invert color if source color value is big enough. If not, they just
+black.
+'destination = one_minus_src_alpha' means, that effect is masked by a
+source alpha channel.
+
+You can design and use your own blend using those enum values and function
+'minetest.pack_texture_blend_func'. Returned value of a function is 
+your 'material_type_param'.
+
+A values in a brackets is a multiplicators of a red, green, blue 
+and alpha channels respectively.
+
+* 'minetest.ebf': global table, containing blend factor enum values. Such as:
+    *  zero                    = 0  -- src & dest (0, 0, 0, 0)
+    *  one                     = 1  -- src & dest (1, 1, 1, 1)
+    *  dst_color               = 2  -- src (destR, destG, destB, destA)
+    *  one_minus_dst_color     = 3  -- src (1-destR, 1-destG, 1-destB, 1-destA)
+    *  src_color               = 4  -- dest (srcR, srcG, srcB, srcA)
+    *  one_minus_src_color     = 5  -- dest (1-srcR, 1-srcG, 1-srcB, 1-srcA)
+    *  src_alpha               = 6  -- src & dest (srcA, srcA, srcA, srcA)
+    *  one_minus_src_alpha     = 7  -- src & dest (1-srcA, 1-srcA, 1-srcA, 1-srcA)
+    *  dst_alpha               = 8  -- src & dest (destA, destA, destA, destA)
+    *  one_minus_dst_alpha     = 9  -- src & dest (1-destA, 1-destA, 1-destA, 1-destA)
+    *  src_alpha_saturate      = 10 -- src (min(srcA, 1-destA), idem, ...) 
+
+* 'minetest.emfn': global table, containing modulate enum values. 
+    * Multiply the components of the arguments, and shift the products to the 
+    * left by x bits for brightening. Contain:
+    *  modulate_1x    = 1 -- no bit shift
+    *  modulate_2x    = 2 -- 1 bits shift
+    *  modulate_4x    = 4 -- 2 bits shift
+
+'modulate_4x' is quite useful when you want to make additive blend stronger
+with a lower amount of particles.
+
+* 'minetest.eas': global table, containing alpha source enum values. Such as:
+    *  none            = 0 -- do not use alpha.
+    *  vertex_color    = 1 -- use vertex color alpha.
+    *  texture         = 2 -- use texture alpha.
+
+You can use both 'vertex_color' and 'texture' source by using value 3.
+
+* 'minetest.pack_texture_blend_func(srcFact, dstFact, modulate, alphaSource)': return integer
+    * Pack texture blend funcion variable. Depending from that variable blend 
+    * function will be applied in time of a render poligons with selected material.
+    * Therefore resulting pixel will be 'source * srcFact + destination * dstFact'
+    * Use result of this function as 'material_type_param'.
+
 Sounds
 ------
 Only Ogg Vorbis files are supported.
@@ -3650,7 +3763,7 @@ Definition tables
 
 ### Tile definition
 * `"image.png"`
-* `{name="image.png", animation={Tile Animation definition}}`
+* `{name="image.png", animation={Animation definition}}`
 * `{name="image.png", backface_culling=bool, tileable_vertical=bool,
     tileable_horizontal=bool}`
     * backface culling enabled by default for most nodes
@@ -3661,8 +3774,50 @@ Definition tables
 * deprecated, yet still supported field names:
     * `image` (name)
 
-### Tile animation definition
-* `{type="vertical_frames", aspect_w=16, aspect_h=16, length=3.0}`
+### Animation definition
+
+#### Node animation, particle and particle spawners
+* `{   type="vertical_frames", 
+       aspect_w=16, 
+    --  ^ specify width of a picture in pixels. 
+       aspect_h=16, 
+    --  ^ specify height of a frame in pixels. 
+       length=3.0
+    --  ^ specify full loop length. 
+       first_frame = 0, -- <- only for particles, use
+       min_first_frame = 0, -- <- for particle spawners
+       max_first_frame = 0,
+       loop_animation = true,  -- <- only for particles and particle spawners
+    --  specify if animation should start from beginning after last frame.
+}`
+
+#### Particle and particle spawners only
+* `{   
+       type="2d_animation_sheet", -- <- only for particles and particle spawners
+       vertical_frame_num = 1,
+       horizontal_frame_num = 1,
+    --  ^ specify amount of frames in texture. 
+    -- Can be used both for animation or for texture transform 
+    -- together with first_frame variable.
+    -- A animation texture separated on equal parts of frames,
+    -- by horizontal and vertical numbers. For example with 
+    -- vertical_frame_num = 4 and horizontal_frame_num = 3 we got
+    -- 4*3 = 12 frames in total. Animation sequence start from
+    -- left top frame and go on to the right until reach end of
+    -- row. Next row also start from left frame.
+       first_frame = 0, -- <- only for particles, use
+       min_first_frame = 0, -- <- for particle spawners
+       max_first_frame = 0,
+    --  ^ specify first frame to start animation.
+       frame_length = -1,
+    --  ^ specify length of a frame in seconds. Negative and zero values
+    -- disable animation. A sequence with vertical_frame_num = 4 and 
+    -- horizontal_frame_num = 3, first_frame = 4 and frame_length = 0.1 
+    -- will end in (4*3-4)*0.1 = 0.8 seconds.
+       loop_animation = true,
+    --  specify if animation should start from beginning after last frame.
+}`
+    * All settings are optional. Default values is located in this example.
 
 ### Node definition (`register_node`)
 
@@ -4117,6 +4272,20 @@ The Biome API is still in an experimental phase and subject to change.
     --  ^ Uses texture (string)
         playername = "singleplayer"
     --  ^ optional, if specified spawns particle only on the player's client
+       material_type_param = 12641,
+    --  ^ optional, if specified spawns particle with 
+    --  specified material type param and disable z-buffer.
+    --  Some examples:
+    --  Default value: 0,
+    --  Additive blend: 12641,
+    --  Substractive blend: 12548,
+    --  Invert blend: 12597,
+    --  See also "Particle blend".
+       animation = {Animation definition},
+    -- ^ see above. Note, that particle and particle spawners have differences.
+       glow = 15,
+    --  ^ optional, specify particle self-luminescence in darkness. 
+       values may vary from 0 (no glow) to 15 (bright glow). 
     }
 
 ### `ParticleSpawner` definition (`add_particlespawner`)
@@ -4151,6 +4320,20 @@ The Biome API is still in an experimental phase and subject to change.
     --  ^ Uses texture (string)
         playername = "singleplayer"
     --  ^ Playername is optional, if specified spawns particle only on the player's client
+       material_type_param = 12641,
+    -- ^ optional, if specified spawns particle with specified material type 
+    -- param and disable z-buffer.
+    --  Some examples:
+    --  Default value: 0,
+    --  Additive blend: 12641,
+    --  Substractive blend: 12548,
+    --  Invert blend: 12597,
+    --  See also "Particle blend".
+       animation = {Animation definition},
+    -- ^ see above. Note, that particle and particle spawners have differences.
+       glow = 15,
+    --  ^ optional, specify particle self-luminescence in darkness. 
+       values may vary from 0 (no glow) to 15 (bright glow).
     }
 
 ### `HTTPRequest` definition (`HTTPApiTable.fetch_async`, `HTTPApiTable.fetch_async`)
index 9f5bda059ce3c26058263fae3868ff40a8c7bef7..c51daf7bcf77ef3d96eafefba9dabba83b78c4dc 100644 (file)
@@ -35,6 +35,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "hud.h"
 #include "particles.h"
 #include "network/networkpacket.h"
+#include "nodedef.h" // AnimationType
 
 struct MeshMakeData;
 class MapBlockMesh;
@@ -185,6 +186,14 @@ struct ClientEvent
                        bool collision_removal;
                        bool vertical;
                        std::string *texture;
+                       u32 material_type_param;
+                       AnimationType animation_type;
+                       u16 vertical_frame_num;
+                       u16 horizontal_frame_num;
+                       u16 first_frame;
+                       float frame_length;
+                       bool loop_animation;
+                       u8 glow;
                } spawn_particle;
                struct{
                        u16 amount;
@@ -205,6 +214,15 @@ struct ClientEvent
                        bool vertical;
                        std::string *texture;
                        u32 id;
+                       u32 material_type_param;
+                       AnimationType animation_type;
+                       u16 vertical_frame_num;
+                       u16 horizontal_frame_num;
+                       u16 min_first_frame;
+                       u16 max_first_frame;
+                       float frame_length;
+                       bool loop_animation;
+                       u8 glow;
                } add_particlespawner;
                struct{
                        u32 id;
index 411982f69109d72b81aa4ac3c45f743ee53782fd..03baf078a039a7683820562f9c331d148e6350bc 100644 (file)
@@ -896,23 +896,46 @@ void Client::handleCommand_SpawnParticle(NetworkPacket* pkt)
        std::string texture     = deSerializeLongString(is);
        bool vertical           = false;
        bool collision_removal  = false;
+       u32 material_type_param = 0;
+       AnimationType animation_type = AT_NONE;
+       u16 vertical_frame_num = 1;
+       u16 horizontal_frame_num = 1;
+       u16 first_frame = 0;
+       float frame_length = -1;
+       bool loop_animation = true;
+       u8 glow = 0;
        try {
                vertical = readU8(is);
                collision_removal = readU8(is);
+               material_type_param = readU32(is);
+               animation_type = (AnimationType)readU8(is);
+               vertical_frame_num = readU16(is);
+               horizontal_frame_num = readU16(is);
+               first_frame = readU16(is);
+               frame_length = readF1000(is);
+               loop_animation = readU8(is);
+               glow = readU8(is);
        } catch (...) {}
 
        ClientEvent event;
-       event.type                              = CE_SPAWN_PARTICLE;
-       event.spawn_particle.pos                = new v3f (pos);
-       event.spawn_particle.vel                = new v3f (vel);
-       event.spawn_particle.acc                = new v3f (acc);
-       event.spawn_particle.expirationtime     = expirationtime;
-       event.spawn_particle.size               = size;
-       event.spawn_particle.collisiondetection = collisiondetection;
-       event.spawn_particle.collision_removal  = collision_removal;
-       event.spawn_particle.vertical           = vertical;
-       event.spawn_particle.texture            = new std::string(texture);
-
+       event.type                                 = CE_SPAWN_PARTICLE;
+       event.spawn_particle.pos                   = new v3f (pos);
+       event.spawn_particle.vel                   = new v3f (vel);
+       event.spawn_particle.acc                   = new v3f (acc);
+       event.spawn_particle.expirationtime        = expirationtime;
+       event.spawn_particle.size                  = size;
+       event.spawn_particle.collisiondetection    = collisiondetection;
+       event.spawn_particle.collision_removal     = collision_removal;
+       event.spawn_particle.vertical              = vertical;
+       event.spawn_particle.texture               = new std::string(texture);
+       event.spawn_particle.material_type_param   = material_type_param;
+       event.spawn_particle.animation_type        = animation_type;
+       event.spawn_particle.vertical_frame_num    = vertical_frame_num;
+       event.spawn_particle.horizontal_frame_num  = horizontal_frame_num;
+       event.spawn_particle.first_frame           = first_frame;
+       event.spawn_particle.frame_length          = frame_length;
+       event.spawn_particle.loop_animation        = loop_animation;
+       event.spawn_particle.glow                  = glow;
        m_client_event_queue.push(event);
 }
 
@@ -932,6 +955,15 @@ void Client::handleCommand_AddParticleSpawner(NetworkPacket* pkt)
        float maxsize;
        bool collisiondetection;
        u32 id;
+       u32 material_type_param = 0;
+       u8 animation_type = (u8)AT_NONE;
+       u16 vertical_frame_num = 1;
+       u16 horizontal_frame_num = 1;
+       u16 min_first_frame = 0;
+       u16 max_first_frame = 0;
+       float frame_length = -1;
+       bool loop_animation = true;
+       u8 glow = 0;
 
        *pkt >> amount >> spawntime >> minpos >> maxpos >> minvel >> maxvel
                >> minacc >> maxacc >> minexptime >> maxexptime >> minsize
@@ -948,29 +980,46 @@ void Client::handleCommand_AddParticleSpawner(NetworkPacket* pkt)
                *pkt >> vertical;
                *pkt >> collision_removal;
                *pkt >> attached_id;
-
+               *pkt >> material_type_param;
+               *pkt >> animation_type;
+               *pkt >> vertical_frame_num;
+               *pkt >> horizontal_frame_num;
+               *pkt >> min_first_frame;
+               *pkt >> max_first_frame;
+               *pkt >> frame_length;
+               *pkt >> loop_animation;
+               *pkt >> glow;
        } catch (...) {}
 
        ClientEvent event;
-       event.type                                   = CE_ADD_PARTICLESPAWNER;
-       event.add_particlespawner.amount             = amount;
-       event.add_particlespawner.spawntime          = spawntime;
-       event.add_particlespawner.minpos             = new v3f (minpos);
-       event.add_particlespawner.maxpos             = new v3f (maxpos);
-       event.add_particlespawner.minvel             = new v3f (minvel);
-       event.add_particlespawner.maxvel             = new v3f (maxvel);
-       event.add_particlespawner.minacc             = new v3f (minacc);
-       event.add_particlespawner.maxacc             = new v3f (maxacc);
-       event.add_particlespawner.minexptime         = minexptime;
-       event.add_particlespawner.maxexptime         = maxexptime;
-       event.add_particlespawner.minsize            = minsize;
-       event.add_particlespawner.maxsize            = maxsize;
-       event.add_particlespawner.collisiondetection = collisiondetection;
-       event.add_particlespawner.collision_removal  = collision_removal;
-       event.add_particlespawner.attached_id        = attached_id;
-       event.add_particlespawner.vertical           = vertical;
-       event.add_particlespawner.texture            = new std::string(texture);
-       event.add_particlespawner.id                 = id;
+       event.type                                     = CE_ADD_PARTICLESPAWNER;
+       event.add_particlespawner.amount               = amount;
+       event.add_particlespawner.spawntime            = spawntime;
+       event.add_particlespawner.minpos               = new v3f (minpos);
+       event.add_particlespawner.maxpos               = new v3f (maxpos);
+       event.add_particlespawner.minvel               = new v3f (minvel);
+       event.add_particlespawner.maxvel               = new v3f (maxvel);
+       event.add_particlespawner.minacc               = new v3f (minacc);
+       event.add_particlespawner.maxacc               = new v3f (maxacc);
+       event.add_particlespawner.minexptime           = minexptime;
+       event.add_particlespawner.maxexptime           = maxexptime;
+       event.add_particlespawner.minsize              = minsize;
+       event.add_particlespawner.maxsize              = maxsize;
+       event.add_particlespawner.collisiondetection   = collisiondetection;
+       event.add_particlespawner.collision_removal    = collision_removal;
+       event.add_particlespawner.attached_id          = attached_id;
+       event.add_particlespawner.vertical             = vertical;
+       event.add_particlespawner.texture              = new std::string(texture);
+       event.add_particlespawner.id                   = id;
+       event.add_particlespawner.material_type_param  = material_type_param;
+       event.add_particlespawner.animation_type       = (AnimationType)animation_type;
+       event.add_particlespawner.vertical_frame_num   = vertical_frame_num;
+       event.add_particlespawner.horizontal_frame_num = horizontal_frame_num;
+       event.add_particlespawner.min_first_frame      = min_first_frame;
+       event.add_particlespawner.max_first_frame      = max_first_frame;
+       event.add_particlespawner.frame_length         = frame_length;
+       event.add_particlespawner.loop_animation       = loop_animation;
+       event.add_particlespawner.glow                 = glow;
 
        m_client_event_queue.push(event);
 }
index 39ea1a60e2b6734e20233b9067584aff442a1a58..c690e6720de23addd2e2ca5a2190129018612d04 100644 (file)
@@ -211,7 +211,7 @@ void TileDef::deSerialize(std::istream &is, const u8 contenfeatures_version, con
 {
        int version = readU8(is);
        name = deSerializeString(is);
-       animation.type = (TileAnimationType)readU8(is);
+       animation.type = (AnimationType)readU8(is);
        animation.aspect_w = readU16(is);
        animation.aspect_h = readU16(is);
        animation.length = readF1000(is);
@@ -531,7 +531,7 @@ void ContentFeatures::fillTileAttribs(ITextureSource *tsrc, TileSpec *tile,
        tile->material_flags = 0;
        if (backface_culling)
                tile->material_flags |= MATERIAL_FLAG_BACKFACE_CULLING;
-       if (tiledef->animation.type == TAT_VERTICAL_FRAMES)
+       if (tiledef->animation.type == AT_VERTICAL_FRAMES)
                tile->material_flags |= MATERIAL_FLAG_ANIMATION_VERTICAL_FRAMES;
        if (tiledef->tileable_horizontal)
                tile->material_flags |= MATERIAL_FLAG_TILEABLE_HORIZONTAL;
index 80396f992308db095f40871d6ec5a4723286692f..f47517c4a46c402dbef7b7e153d80003956e40a4 100644 (file)
@@ -161,9 +161,10 @@ enum NodeDrawType
 /*
        Stand-alone definition of a TileSpec (basically a server-side TileSpec)
 */
-enum TileAnimationType{
-       TAT_NONE=0,
-       TAT_VERTICAL_FRAMES=1,
+enum AnimationType{
+       AT_NONE = 0,
+       AT_VERTICAL_FRAMES = 1,
+       AT_2D_ANIMATION_SHEET = 2,
 };
 struct TileDef
 {
@@ -172,7 +173,7 @@ struct TileDef
        bool tileable_horizontal;
        bool tileable_vertical;
        struct{
-               enum TileAnimationType type;
+               enum AnimationType type;
                int aspect_w; // width for aspect ratio
                int aspect_h; // height for aspect ratio
                float length; // seconds
@@ -184,7 +185,7 @@ struct TileDef
                backface_culling = true;
                tileable_horizontal = true;
                tileable_vertical = true;
-               animation.type = TAT_NONE;
+               animation.type = AT_NONE;
                animation.aspect_w = 1;
                animation.aspect_h = 1;
                animation.length = 1.0;
index f20fb4083033631a48370ace89c6fc34a57be062..538487028e990de0367136b24bc52eea90d6e19b 100644 (file)
@@ -43,6 +43,22 @@ v3f random_v3f(v3f min, v3f max)
                        rand()/(float)RAND_MAX*(max.Z-min.Z)+min.Z);
 }
 
+u32 check_material_type_param(u32 material_type_param)
+{
+       u32 alphaSource = (material_type_param & 0x0000F000) >> 12;
+       u32 modulo  = (material_type_param & 0x00000F00) >> 8;
+       u32 srcFact = (material_type_param & 0x000000F0) >> 4;
+       u32 dstFact = material_type_param & 0x0000000F;
+       if (alphaSource <= 3 && modulo <= 4 && srcFact <= 10 && dstFact <= 10) {
+               return material_type_param;
+       } else {
+               errorstream << "Server send incorrect ";
+               errorstream << "material_type_param value for particle.";
+               errorstream << std::endl;
+               return 0;
+       }
+}
+
 Particle::Particle(
        IGameDef *gamedef,
        scene::ISceneManager* smgr,
@@ -58,7 +74,14 @@ Particle::Particle(
        bool vertical,
        video::ITexture *texture,
        v2f texpos,
-       v2f texsize
+       v2f texsize,
+       u32 material_type_param,
+       u16 vertical_frame_num,
+       u16 horizontal_frame_num,
+       u16 first_frame,
+       float frame_length,
+       bool loop_animation,
+       u8 glow
 ):
        scene::ISceneNode(smgr->getRootSceneNode(), smgr)
 {
@@ -71,11 +94,26 @@ Particle::Particle(
        m_material.setFlag(video::EMF_BACK_FACE_CULLING, false);
        m_material.setFlag(video::EMF_BILINEAR_FILTER, false);
        m_material.setFlag(video::EMF_FOG_ENABLE, true);
-       m_material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
+       if (material_type_param != 0) {
+               m_material.MaterialType = video::EMT_ONETEXTURE_BLEND;
+               m_material.MaterialTypeParam = irr::core::FR(material_type_param);
+               // We must disable z-buffer if we want to avoid transparent pixels
+               // to overlap pixels with lower z-value.
+               m_material.setFlag(video::EMF_ZWRITE_ENABLE, false); 
+       } else {
+               m_material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
+       }
        m_material.setTexture(0, texture);
+
        m_texpos = texpos;
        m_texsize = texsize;
-
+       m_vertical_frame_num = vertical_frame_num;
+       m_horizontal_frame_num = horizontal_frame_num;
+       m_first_frame = first_frame;
+       m_frame_length = frame_length;
+       m_loop_animation = loop_animation;
+       m_texsize.Y /= m_vertical_frame_num;
+       m_texsize.X /= m_horizontal_frame_num;
 
        // Particle related
        m_pos = pos;
@@ -88,6 +126,7 @@ Particle::Particle(
        m_collisiondetection = collisiondetection;
        m_collision_removal = collision_removal;
        m_vertical = vertical;
+       m_glow = glow;
 
        // Irrlicht stuff
        m_collisionbox = aabb3f
@@ -170,16 +209,29 @@ void Particle::updateLight()
        else
                light = blend_light(m_env->getDayNightRatio(), LIGHT_SUN, 0);
 
-       m_light = decode_light(light);
+       m_light = decode_light(light + m_glow);
 }
 
 void Particle::updateVertices()
 {
        video::SColor c(255, m_light, m_light, m_light);
-       f32 tx0 = m_texpos.X;
-       f32 tx1 = m_texpos.X + m_texsize.X;
-       f32 ty0 = m_texpos.Y;
-       f32 ty1 = m_texpos.Y + m_texsize.Y;
+       u16 frame = m_first_frame;
+       if (m_frame_length > 0) {
+               if (m_loop_animation)
+                       frame = m_first_frame + (u32)(m_time / m_frame_length)
+                                       % (m_vertical_frame_num * 
+                                       m_horizontal_frame_num - m_first_frame);
+               else if (m_time >= 
+                               (m_vertical_frame_num * m_horizontal_frame_num 
+                               - m_first_frame) * m_frame_length)
+                       frame = m_vertical_frame_num * m_horizontal_frame_num - 1;
+               else
+                       frame = m_first_frame + (u16)(m_time / m_frame_length);
+       }
+       f32 tx0 = m_texpos.X + m_texsize.X * (frame % m_horizontal_frame_num);
+       f32 tx1 = m_texpos.X + m_texsize.X * (frame % m_horizontal_frame_num + 1);
+       f32 ty0 = m_texpos.Y + m_texsize.Y * (frame / m_horizontal_frame_num);
+       f32 ty1 = m_texpos.Y + m_texsize.Y * (frame / m_horizontal_frame_num + 1);
 
        m_vertices[0] = video::S3DVertex(-m_size/2,-m_size/2,0, 0,0,0,
                        c, tx0, ty1);
@@ -214,7 +266,16 @@ ParticleSpawner::ParticleSpawner(IGameDef* gamedef, scene::ISceneManager *smgr,
        v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc,
        float minexptime, float maxexptime, float minsize, float maxsize,
        bool collisiondetection, bool collision_removal, u16 attached_id, bool vertical,
-       video::ITexture *texture, u32 id, ParticleManager *p_manager) :
+       video::ITexture *texture, u32 id, 
+       u32 material_type_param,
+       u16 vertical_frame_num,
+       u16 horizontal_frame_num,
+       u16 min_first_frame,
+       u16 max_first_frame,
+       float frame_length,
+       bool loop_animation,
+       u8 glow,
+       ParticleManager *p_manager) :
        m_particlemanager(p_manager)
 {
        m_gamedef = gamedef;
@@ -238,6 +299,14 @@ ParticleSpawner::ParticleSpawner(IGameDef* gamedef, scene::ISceneManager *smgr,
        m_vertical = vertical;
        m_texture = texture;
        m_time = 0;
+       m_vertical_frame_num = vertical_frame_num;
+       m_horizontal_frame_num = horizontal_frame_num;
+       m_min_first_frame = min_first_frame;
+       m_max_first_frame = max_first_frame;
+       m_frame_length = frame_length;
+       m_loop_animation = loop_animation;
+       m_material_type_param = material_type_param;
+       m_glow = glow;
 
        for (u16 i = 0; i<=m_amount; i++)
        {
@@ -251,7 +320,6 @@ ParticleSpawner::~ParticleSpawner() {}
 void ParticleSpawner::step(float dtime, ClientEnvironment* env)
 {
        m_time += dtime;
-
        bool unloaded = false;
        v3f attached_offset = v3f(0,0,0);
        if (m_attached_id != 0) {
@@ -285,7 +353,10 @@ void ParticleSpawner::step(float dtime, ClientEnvironment* env)
                                        float size = rand()/(float)RAND_MAX
                                                        *(m_maxsize-m_minsize)
                                                        +m_minsize;
-
+                                       u16 first_frame = m_min_first_frame + 
+                                                       rand() % 
+                                                       (m_max_first_frame - 
+                                                       m_min_first_frame + 1);
                                        Particle* toadd = new Particle(
                                                m_gamedef,
                                                m_smgr,
@@ -301,7 +372,14 @@ void ParticleSpawner::step(float dtime, ClientEnvironment* env)
                                                m_vertical,
                                                m_texture,
                                                v2f(0.0, 0.0),
-                                               v2f(1.0, 1.0));
+                                               v2f(1.0, 1.0),
+                                               m_material_type_param, 
+                                               m_vertical_frame_num,
+                                               m_horizontal_frame_num,
+                                               first_frame,
+                                               m_frame_length,
+                                               m_loop_animation,
+                                               m_glow);
                                        m_particlemanager->addParticle(toadd);
                                }
                                i = m_spawntimes.erase(i);
@@ -331,7 +409,10 @@ void ParticleSpawner::step(float dtime, ClientEnvironment* env)
                                float size = rand()/(float)RAND_MAX
                                                *(m_maxsize-m_minsize)
                                                +m_minsize;
-
+                               u16 first_frame = m_min_first_frame + 
+                                               rand() % 
+                                               (m_max_first_frame - 
+                                               m_min_first_frame + 1);
                                Particle* toadd = new Particle(
                                        m_gamedef,
                                        m_smgr,
@@ -347,7 +428,14 @@ void ParticleSpawner::step(float dtime, ClientEnvironment* env)
                                        m_vertical,
                                        m_texture,
                                        v2f(0.0, 0.0),
-                                       v2f(1.0, 1.0));
+                                       v2f(1.0, 1.0),
+                                       m_material_type_param, 
+                                       m_vertical_frame_num,
+                                       m_horizontal_frame_num,
+                                       first_frame,
+                                       m_frame_length,
+                                       m_loop_animation,
+                                       m_glow);
                                m_particlemanager->addParticle(toadd);
                        }
                }
@@ -459,6 +547,39 @@ void ParticleManager::handleParticleEvent(ClientEvent *event, IGameDef *gamedef,
                        video::ITexture *texture =
                                gamedef->tsrc()->getTextureForMesh(*(event->add_particlespawner.texture));
 
+                       float frame_length = -1;
+                       u16 vertical_frame_num = 1;
+                       u16 horizontal_frame_num = 1;
+                       u32 material_type_param =
+                               check_material_type_param(event->add_particlespawner.material_type_param);
+
+                       switch (event->add_particlespawner.animation_type) {
+                               case AT_NONE:
+                                       break;
+                               case AT_VERTICAL_FRAMES: {
+                                       v2u32 size = texture->getOriginalSize();
+                                       int frame_height = (float)size.X /
+                                               (float)event->add_particlespawner.vertical_frame_num *
+                                               (float)event->add_particlespawner.horizontal_frame_num;
+                                       vertical_frame_num = size.Y / frame_height;
+                                       frame_length = 
+                                               event->add_particlespawner.frame_length / 
+                                               vertical_frame_num;
+                                       break;
+                               }
+                               case AT_2D_ANIMATION_SHEET: {
+                                       vertical_frame_num =
+                                               event->add_particlespawner.vertical_frame_num;
+                                       horizontal_frame_num =
+                                               event->add_particlespawner.horizontal_frame_num;
+                                       frame_length = 
+                                               event->add_particlespawner.frame_length;
+                                       break;
+                               }
+                               default:
+                                       break;
+                       }
+
                        ParticleSpawner* toadd = new ParticleSpawner(gamedef, smgr, player,
                                        event->add_particlespawner.amount,
                                        event->add_particlespawner.spawntime,
@@ -478,6 +599,14 @@ void ParticleManager::handleParticleEvent(ClientEvent *event, IGameDef *gamedef,
                                        event->add_particlespawner.vertical,
                                        texture,
                                        event->add_particlespawner.id,
+                                       material_type_param,
+                                       vertical_frame_num,
+                                       horizontal_frame_num,
+                                       event->add_particlespawner.min_first_frame,
+                                       event->add_particlespawner.max_first_frame,
+                                       frame_length,
+                                       event->add_particlespawner.loop_animation,
+                                       event->add_particlespawner.glow,
                                        this);
 
                        /* delete allocated content of event */
@@ -502,6 +631,39 @@ void ParticleManager::handleParticleEvent(ClientEvent *event, IGameDef *gamedef,
                        video::ITexture *texture =
                                gamedef->tsrc()->getTextureForMesh(*(event->spawn_particle.texture));
 
+                       float frame_length = -1;
+                       u16 vertical_frame_num = 1;
+                       u16 horizontal_frame_num = 1;
+                       u32 material_type_param =
+                               check_material_type_param(event->spawn_particle.material_type_param);
+
+                       switch (event->spawn_particle.animation_type) {
+                               case AT_NONE:
+                                       break;
+                               case AT_VERTICAL_FRAMES: {
+                                       v2u32 size = texture->getOriginalSize();
+                                       int frame_height = (float)size.X /
+                                               (float)event->spawn_particle.vertical_frame_num *
+                                               (float)event->spawn_particle.horizontal_frame_num;
+                                       vertical_frame_num = size.Y / frame_height;
+                                       frame_length = 
+                                               event->spawn_particle.frame_length / 
+                                               vertical_frame_num;
+                                       break;
+                               }
+                               case AT_2D_ANIMATION_SHEET: {
+                                       vertical_frame_num =
+                                               event->spawn_particle.vertical_frame_num;
+                                       horizontal_frame_num =
+                                               event->spawn_particle.horizontal_frame_num;
+                                       frame_length = 
+                                               event->spawn_particle.frame_length;
+                                       break;
+                               }
+                               default:
+                                       break;
+                       }
+
                        Particle* toadd = new Particle(gamedef, smgr, player, m_env,
                                        *event->spawn_particle.pos,
                                        *event->spawn_particle.vel,
@@ -513,13 +675,21 @@ void ParticleManager::handleParticleEvent(ClientEvent *event, IGameDef *gamedef,
                                        event->spawn_particle.vertical,
                                        texture,
                                        v2f(0.0, 0.0),
-                                       v2f(1.0, 1.0));
+                                       v2f(1.0, 1.0),
+                                       material_type_param,
+                                       vertical_frame_num,
+                                       horizontal_frame_num,
+                                       event->spawn_particle.first_frame,
+                                       frame_length,
+                                       event->spawn_particle.loop_animation,
+                                       event->spawn_particle.glow);
 
                        addParticle(toadd);
 
                        delete event->spawn_particle.pos;
                        delete event->spawn_particle.vel;
                        delete event->spawn_particle.acc;
+                       delete event->spawn_particle.texture;
 
                        break;
                }
@@ -588,7 +758,8 @@ void ParticleManager::addNodeParticle(IGameDef* gamedef, scene::ISceneManager* s
                false,
                texture,
                texpos,
-               texsize);
+               texsize,
+               0, 1, 1, 0, -1, true, 0);
 
        addParticle(toadd);
 }
index eb8c6665d0e127200e9dd1ddc5655f13e6494a23..6d8c6139f2debc8ffb8707421039551a5061dc80 100644 (file)
@@ -50,7 +50,14 @@ class Particle : public scene::ISceneNode
                bool vertical,
                video::ITexture *texture,
                v2f texpos,
-               v2f texsize
+               v2f texsize,
+               u32 material_type_param,
+               u16 vertical_frame_num,
+               u16 horizontal_frame_num,
+               u16 first_frame,
+               float frame_length,
+               bool loop_animation,
+               u8 glow
        );
        ~Particle();
 
@@ -102,6 +109,12 @@ private:
        bool m_collision_removal;
        bool m_vertical;
        v3s16 m_camera_offset;
+       u16 m_vertical_frame_num;
+       u16 m_horizontal_frame_num;
+       u16 m_first_frame;
+       float m_frame_length;
+       bool m_loop_animation;
+       u8 m_glow;
 };
 
 class ParticleSpawner
@@ -123,8 +136,15 @@ class ParticleSpawner
                bool vertical,
                video::ITexture *texture,
                u32 id,
+               u32 material_type_param,
+               u16 vertical_frame_num,
+               u16 horizontal_frame_num,
+               u16 min_first_frame,
+               u16 max_first_frame,
+               float frame_length,
+               bool loop_animation,
+               u8 glow,
                ParticleManager* p_manager);
-
        ~ParticleSpawner();
 
        void step(float dtime, ClientEnvironment *env);
@@ -156,6 +176,14 @@ class ParticleSpawner
        bool m_collision_removal;
        bool m_vertical;
        u16 m_attached_id;
+       u32 m_material_type_param;
+       u16 m_vertical_frame_num;
+       u16 m_horizontal_frame_num;
+       u16 m_min_first_frame;
+       u16 m_max_first_frame;
+       float m_frame_length;
+       bool m_loop_animation;
+       u8 m_glow;
 };
 
 /**
index f20a65903c5015f1d40cd7a129ea773e1e02ef6f..d4a25b68b82e950682a741e0d9cd761fa9bcc62a 100644 (file)
@@ -35,10 +35,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "noise.h"
 #include <json/json.h>
 
-struct EnumString es_TileAnimationType[] =
+struct EnumString es_AnimationType[] =
 {
-       {TAT_NONE, "none"},
-       {TAT_VERTICAL_FRAMES, "vertical_frames"},
+       {AT_NONE, "none"},
+       {AT_VERTICAL_FRAMES, "vertical_frames"},
+       {AT_2D_ANIMATION_SHEET, "2d_animation_sheet"},
        {0, NULL},
 };
 
@@ -335,9 +336,9 @@ TileDef read_tiledef(lua_State *L, int index, u8 drawtype)
                lua_getfield(L, index, "animation");
                if(lua_istable(L, -1)){
                        // {type="vertical_frames", aspect_w=16, aspect_h=16, length=2.0}
-                       tiledef.animation.type = (TileAnimationType)
-                               getenumfield(L, -1, "type", es_TileAnimationType,
-                               TAT_NONE);
+                       tiledef.animation.type = (AnimationType)
+                               getenumfield(L, -1, "type", es_AnimationType,
+                               AT_NONE);
                        tiledef.animation.aspect_w =
                                getintfield_default(L, -1, "aspect_w", 16);
                        tiledef.animation.aspect_h =
index 2a2228b6dd2fb3922666768dab41b5aa6ab0c7f6..32fdb4f043ffac05667025d2b872cd589cc5d319 100644 (file)
@@ -159,6 +159,6 @@ bool               push_json_value           (lua_State *L,
 void               read_json_value           (lua_State *L, Json::Value &root,
                                               int index, u8 recursion = 0);
 
-extern struct EnumString es_TileAnimationType[];
+extern struct EnumString es_AnimationType[];
 
 #endif /* C_CONTENT_H_ */
index f36298915154b152975faca8416aa688533afccd..cfb5e26dbc7bf9731066e93e9359856fa6ab2beb 100644 (file)
@@ -513,6 +513,28 @@ int getintfield_default(lua_State *L, int table,
        return result;
 }
 
+int check_material_type_param(lua_State *L, int table,
+               const char *fieldname, int default_)
+{
+       int material_type_param =
+               getintfield_default(L, table, fieldname, default_);
+       u32 alphaSource = (material_type_param & 0x0000F000) >> 12;
+       u32 modulo  = (material_type_param & 0x00000F00) >> 8;
+       u32 srcFact = (material_type_param & 0x000000F0) >> 4;
+       u32 dstFact = material_type_param & 0x0000000F;
+       if (alphaSource <= 3 && modulo <= 4 && srcFact <= 10 && dstFact <= 10) {
+               return material_type_param;
+       } else {
+               std::ostringstream error_text;
+               error_text << "Incorrect material_type_param value ";
+               error_text << "for particle or particle spawner.";
+               error_text << std::endl;
+               throw LuaError(error_text.str());
+               return 0;
+       }
+}
+
+
 float getfloatfield_default(lua_State *L, int table,
                const char *fieldname, float default_)
 {
index a5fbee765ffd73d9d5163f8c6374e86e57e381c5..71ac735c15d9285d09a05dd44a1f80aafa62e3fb 100644 (file)
@@ -45,6 +45,8 @@ float              getfloatfield_default(lua_State *L, int table,
                              const char *fieldname, float default_);
 int                getintfield_default           (lua_State *L, int table,
                              const char *fieldname, int default_);
+int                check_material_type_param(lua_State *L, int table,
+                             const char *fieldname, int default_);
 
 bool               getstringfield(lua_State *L, int table,
                              const char *fieldname, std::string &result);
index 667ac727210b0d80fe36bb7dffd7e82031c5f5d5..b0a57ce6d3fe1778f543c44e27e9c80d26c6d57d 100644 (file)
@@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "lua_api/l_object.h"
 #include "lua_api/l_internal.h"
 #include "common/c_converter.h"
+#include "common/c_content.h"
 #include "server.h"
 #include "particles.h"
 
@@ -34,6 +35,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 // collision_removal = bool
 // vertical = bool
 // texture = e.g."default_wood.png"
+// material_type_param = num
+// animation = animation definition
+// glow = indexed color or color string
 int ModApiParticles::l_add_particle(lua_State *L)
 {
        MAP_LOCK_REQUIRED;
@@ -44,13 +48,24 @@ int ModApiParticles::l_add_particle(lua_State *L)
 
        float expirationtime, size;
        expirationtime = size = 1;
+       float frame_or_loop_length = -1;
+       
+       AnimationType animation_type = AT_NONE;
+
+       u16 vertical_frame_num_or_aspect = 1;
+       u16 horizontal_frame_num_or_aspect = 1;
+       u16 first_frame = 0;
 
        bool collisiondetection, vertical, collision_removal;
        collisiondetection = vertical = collision_removal = false;
+       bool loop_animation = true;
 
        std::string texture = "";
        std::string playername = "";
 
+       u32 material_type_param = 0;
+       u8 glow = 0;
+
        if (lua_gettop(L) > 1) // deprecated
        {
                log_deprecated(L, "Deprecated add_particle call with individual parameters instead of definition");
@@ -94,8 +109,61 @@ int ModApiParticles::l_add_particle(lua_State *L)
                acc = lua_istable(L, -1) ? check_v3f(L, -1) : acc;
                lua_pop(L, 1);
 
-               expirationtime = getfloatfield_default(L, 1, "expirationtime", 1);
+               expirationtime = getfloatfield_default(L, 1, "expirationtime", 1);      
                size = getfloatfield_default(L, 1, "size", 1);
+
+               lua_getfield(L, 1, "animation");
+               if (lua_istable(L, -1)) {
+                       animation_type = (AnimationType)
+                               getenumfield(L, -1, "type", es_AnimationType,
+                               AT_NONE);
+               }
+               switch (animation_type) {
+                       case AT_NONE:
+                               break;
+                       case AT_2D_ANIMATION_SHEET:
+                               frame_or_loop_length = 
+                                       getfloatfield_default(L, -1, "frame_length", -1);
+                               vertical_frame_num_or_aspect = 
+                                       getintfield_default(L, -1, "vertical_frame_num", 1);
+                               horizontal_frame_num_or_aspect = 
+                                       getintfield_default(L, -1, "horizontal_frame_num", 1);
+                               first_frame = 
+                                       getintfield_default(L, -1, "first_frame", 0);
+                               loop_animation = 
+                                       getboolfield_default(L, -1, "loop_animation", true);
+                               break;
+                       case AT_VERTICAL_FRAMES:
+                               frame_or_loop_length = 
+                                       getfloatfield_default(L, -1, "length", -1);
+                               vertical_frame_num_or_aspect = 
+                                       getintfield_default(L, -1, "aspect_w", 1);
+                               horizontal_frame_num_or_aspect = 
+                                       getintfield_default(L, -1, "aspect_h", 1);
+                               first_frame = 
+                                       getintfield_default(L, -1, "first_frame", 0);
+                               loop_animation = 
+                                       getboolfield_default(L, -1, "loop_animation", true);
+                               break;
+                       default:
+                               break;
+               }
+               lua_pop(L, 1);
+
+               if (animation_type == AT_2D_ANIMATION_SHEET && 
+                               first_frame >= vertical_frame_num_or_aspect * 
+                               horizontal_frame_num_or_aspect) {
+                       std::ostringstream error_text; 
+                       error_text << "first_frame should be lower, than "
+                               << "vertical_frame_num * horizontal_frame_num. "
+                               << "Got first_frame=" << first_frame
+                               << ", vertical_frame_num="
+                               << vertical_frame_num_or_aspect
+                               << " and horizontal_frame_num="
+                               << horizontal_frame_num_or_aspect << std::endl;
+                       throw LuaError(error_text.str());
+               }
+
                collisiondetection = getboolfield_default(L, 1,
                        "collisiondetection", collisiondetection);
                collision_removal = getboolfield_default(L, 1,
@@ -103,9 +171,16 @@ int ModApiParticles::l_add_particle(lua_State *L)
                vertical = getboolfield_default(L, 1, "vertical", vertical);
                texture = getstringfield_default(L, 1, "texture", "");
                playername = getstringfield_default(L, 1, "playername", "");
+               material_type_param = check_material_type_param(L, 1, "material_type_param", 0);
+               glow = getintfield_default (L, 1, "glow", 0);
        }
-       getServer(L)->spawnParticle(playername, pos, vel, acc, expirationtime, size,
-                       collisiondetection, collision_removal, vertical, texture);
+       getServer(L)->spawnParticle(playername, pos, vel, acc, expirationtime, 
+               size, collisiondetection, collision_removal, vertical, 
+               texture, material_type_param,
+               animation_type,
+               vertical_frame_num_or_aspect, 
+               horizontal_frame_num_or_aspect,
+               first_frame, frame_or_loop_length, loop_animation, glow);
        return 1;
 }
 
@@ -127,21 +202,33 @@ int ModApiParticles::l_add_particle(lua_State *L)
 // collision_removal = bool
 // vertical = bool
 // texture = e.g."default_wood.png"
+// material_type_param = num
+// animation = animation definition
+// glow = indexed color or color string
 int ModApiParticles::l_add_particlespawner(lua_State *L)
 {
        MAP_LOCK_REQUIRED;
 
        // Get parameters
        u16 amount = 1;
+       u16 vertical_frame_num_or_aspect = 1;
+       u16 horizontal_frame_num_or_aspect = 1;
+       u16 min_first_frame = 0;
+       u16 max_first_frame = 0;
        v3f minpos, maxpos, minvel, maxvel, minacc, maxacc;
            minpos= maxpos= minvel= maxvel= minacc= maxacc= v3f(0, 0, 0);
        float time, minexptime, maxexptime, minsize, maxsize;
              time= minexptime= maxexptime= minsize= maxsize= 1;
+       AnimationType animation_type = AT_NONE;
+       float frame_or_loop_length = -1;
        bool collisiondetection, vertical, collision_removal;
             collisiondetection = vertical = collision_removal = false;
+       bool loop_animation = true;
        ServerActiveObject *attached = NULL;
        std::string texture = "";
        std::string playername = "";
+       u32 material_type_param = 0;
+       u8 glow = 0;
 
        if (lua_gettop(L) > 1) //deprecated
        {
@@ -196,6 +283,65 @@ int ModApiParticles::l_add_particlespawner(lua_State *L)
                maxexptime = getfloatfield_default(L, 1, "maxexptime", maxexptime);
                minsize = getfloatfield_default(L, 1, "minsize", minsize);
                maxsize = getfloatfield_default(L, 1, "maxsize", maxsize);
+
+
+               lua_getfield(L, 1, "animation");
+               if (lua_istable(L, -1)) {
+                       animation_type = (AnimationType)
+                               getenumfield(L, -1, "type", es_AnimationType,
+                               AT_NONE);
+               }
+               switch (animation_type) {
+                       case AT_NONE:
+                               break;
+                       case AT_2D_ANIMATION_SHEET:
+                               frame_or_loop_length = 
+                                       getfloatfield_default(L, -1, "frame_length", -1);
+                               vertical_frame_num_or_aspect = 
+                                       getintfield_default(L, -1, "vertical_frame_num", 1);
+                               horizontal_frame_num_or_aspect = 
+                                       getintfield_default(L, -1, "horizontal_frame_num", 1);
+                               min_first_frame = 
+                                       getintfield_default(L, -1, "min_first_frame", 0);
+                               max_first_frame = 
+                                       getintfield_default(L, -1, "max_first_frame", 0);
+                               loop_animation = 
+                                       getboolfield_default(L, -1, "loop_animation", true);
+                               break;
+                       case AT_VERTICAL_FRAMES:
+                               frame_or_loop_length = 
+                                       getfloatfield_default(L, -1, "length", -1);
+                               vertical_frame_num_or_aspect = 
+                                       getintfield_default(L, -1, "aspect_w", 1);
+                               horizontal_frame_num_or_aspect = 
+                                       getintfield_default(L, -1, "aspect_h", 1);
+                               min_first_frame = 
+                                       getintfield_default(L, -1, "min_first_frame", 0);
+                               max_first_frame = 
+                                       getintfield_default(L, -1, "max_first_frame", 0);
+                               loop_animation = 
+                                       getboolfield_default(L, -1, "loop_animation", true);
+                               break;
+                       default:
+                               break;
+               }
+               lua_pop(L, 1);
+
+               if (animation_type == AT_2D_ANIMATION_SHEET && 
+                               max_first_frame >= vertical_frame_num_or_aspect * 
+                               horizontal_frame_num_or_aspect) {
+                       std::ostringstream error_text; 
+                       error_text << "max_first_frame should be lower, than "
+                               << "vertical_frame_num * horizontal_frame_num. " 
+                               << "Got max_first_frame="
+                               << max_first_frame
+                               << ", vertical_frame_num="
+                               << vertical_frame_num_or_aspect
+                               << " and horizontal_frame_num="
+                               << horizontal_frame_num_or_aspect << std::endl;
+                       throw LuaError(error_text.str());
+               }
+               
                collisiondetection = getboolfield_default(L, 1,
                        "collisiondetection", collisiondetection);
                collision_removal = getboolfield_default(L, 1,
@@ -211,6 +357,8 @@ int ModApiParticles::l_add_particlespawner(lua_State *L)
                vertical = getboolfield_default(L, 1, "vertical", vertical);
                texture = getstringfield_default(L, 1, "texture", "");
                playername = getstringfield_default(L, 1, "playername", "");
+               material_type_param = check_material_type_param(L, 1, "material_type_param", 0);
+               glow = getintfield_default(L, 1, "glow", 0);
        }
 
        u32 id = getServer(L)->addParticleSpawner(amount, time,
@@ -223,9 +371,17 @@ int ModApiParticles::l_add_particlespawner(lua_State *L)
                        collision_removal,
                        attached,
                        vertical,
-                       texture, playername);
+                       texture, 
+                       playername, 
+                       material_type_param, 
+                       animation_type,
+                       vertical_frame_num_or_aspect, 
+                       horizontal_frame_num_or_aspect,
+                       min_first_frame, max_first_frame, 
+                       frame_or_loop_length, 
+                       loop_animation,
+                       glow);
        lua_pushnumber(L, id);
-
        return 1;
 }
 
index 48331e4f84b2dad4eaf56c6815d6319468b224e9..cef57be888a5238debbacd2e727d01b95858aff0 100644 (file)
@@ -1658,7 +1658,11 @@ void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec,
 void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration,
                                float expirationtime, float size, bool collisiondetection,
                                bool collision_removal,
-                               bool vertical, const std::string &texture)
+                               bool vertical, const std::string &texture,
+                               u32 material_type_param,  AnimationType animation_type,
+                               u16 vertical_frame_num, u16 horizontal_frame_num, u16 first_frame,
+                               float frame_length, bool loop_animation, 
+                               u8 glow)
 {
        DSTACK(FUNCTION_NAME);
 
@@ -1670,6 +1674,12 @@ void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f accelerat
        pkt << vertical;
        pkt << collision_removal;
 
+       pkt << material_type_param 
+               << (u8)animation_type
+               << vertical_frame_num 
+               << horizontal_frame_num << first_frame 
+               << frame_length << loop_animation << glow;
+
        if (peer_id != PEER_ID_INEXISTENT) {
                Send(&pkt);
        }
@@ -1682,7 +1692,10 @@ void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f accelerat
 void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos,
        v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime,
        float minsize, float maxsize, bool collisiondetection, bool collision_removal,
-       u16 attached_id, bool vertical, const std::string &texture, u32 id)
+       u16 attached_id, bool vertical, const std::string &texture, u32 id,
+       u32 material_type_param,  AnimationType animation_type, u16 vertical_frame_num, u16 horizontal_frame_num, 
+       u16 min_first_frame, u16 max_first_frame, float frame_length, 
+       bool loop_animation, u8 glow)
 {
        DSTACK(FUNCTION_NAME);
 
@@ -1698,6 +1711,12 @@ void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3
        pkt << collision_removal;
        pkt << attached_id;
 
+       pkt << material_type_param 
+               << (u8)animation_type
+               << vertical_frame_num << horizontal_frame_num 
+               << min_first_frame << max_first_frame
+               << frame_length << loop_animation << glow;
+
        if (peer_id != PEER_ID_INEXISTENT) {
                Send(&pkt);
        }
@@ -3147,7 +3166,11 @@ void Server::spawnParticle(const std::string &playername, v3f pos,
        v3f velocity, v3f acceleration,
        float expirationtime, float size, bool
        collisiondetection, bool collision_removal,
-       bool vertical, const std::string &texture)
+       bool vertical, const std::string &texture,
+       u32 material_type_param,  AnimationType animation_type,
+       u16 vertical_frame_num, u16 horizontal_frame_num, u16 first_frame,
+       float frame_length, bool loop_animation,
+       u8 glow)
 {
        // m_env will be NULL if the server is initializing
        if (!m_env)
@@ -3163,7 +3186,11 @@ void Server::spawnParticle(const std::string &playername, v3f pos,
 
        SendSpawnParticle(peer_id, pos, velocity, acceleration,
                        expirationtime, size, collisiondetection,
-                       collision_removal, vertical, texture);
+                       collision_removal, vertical, texture,
+                       material_type_param, animation_type,
+                       vertical_frame_num, horizontal_frame_num, 
+                       first_frame, frame_length, loop_animation, 
+                       glow);
 }
 
 u32 Server::addParticleSpawner(u16 amount, float spawntime,
@@ -3171,7 +3198,9 @@ u32 Server::addParticleSpawner(u16 amount, float spawntime,
        float minexptime, float maxexptime, float minsize, float maxsize,
        bool collisiondetection, bool collision_removal,
        ServerActiveObject *attached, bool vertical, const std::string &texture,
-       const std::string &playername)
+       const std::string &playername,  u32 material_type_param,  AnimationType animation_type,
+       u16 vertical_frame_num, u16 horizontal_frame_num, u16 min_first_frame, u16 max_first_frame, 
+       float frame_length, bool loop_animation, u8 glow)
 {
        // m_env will be NULL if the server is initializing
        if (!m_env)
@@ -3197,7 +3226,10 @@ u32 Server::addParticleSpawner(u16 amount, float spawntime,
                minpos, maxpos, minvel, maxvel, minacc, maxacc,
                minexptime, maxexptime, minsize, maxsize,
                collisiondetection, collision_removal, attached_id, vertical,
-               texture, id);
+               texture, id, material_type_param, animation_type,
+               vertical_frame_num, horizontal_frame_num, 
+               min_first_frame, max_first_frame, frame_length, loop_animation,
+               glow);
 
        return id;
 }
index 9e844e36c3531ccf641dbefef209c3bfc0d76c7c..9a8d22b2eb4cc42e309e6be44ef52db436486ad2 100644 (file)
@@ -26,6 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "hud.h"
 #include "gamedef.h"
 #include "serialization.h" // For SER_FMT_VER_INVALID
+#include "nodedef.h" // AnimationType
 #include "mods.h"
 #include "inventorymanager.h"
 #include "subgame.h"
@@ -254,7 +255,11 @@ public:
                v3f pos, v3f velocity, v3f acceleration,
                float expirationtime, float size,
                bool collisiondetection, bool collision_removal,
-               bool vertical, const std::string &texture);
+               bool vertical, const std::string &texture,
+               u32 material_type_param,  AnimationType animation_type, 
+               u16 vertical_frame_num, u16 horizontal_frame_num, u16 first_frame,
+               float frame_length, bool loop_animation,
+               u8 glow);
 
        u32 addParticleSpawner(u16 amount, float spawntime,
                v3f minpos, v3f maxpos,
@@ -265,7 +270,12 @@ public:
                bool collisiondetection, bool collision_removal,
                ServerActiveObject *attached,
                bool vertical, const std::string &texture,
-               const std::string &playername);
+               const std::string &playername,
+               u32 material_type_param,  AnimationType animation_type, 
+               u16 vertical_frame_num, u16 horizontal_frame_num, 
+               u16 min_first_frame, u16 max_first_frame, 
+               float frame_length, bool loop_animation,
+               u8 glow);
 
        void deleteParticleSpawner(const std::string &playername, u32 id);
 
@@ -441,7 +451,12 @@ private:
                float minsize, float maxsize,
                bool collisiondetection, bool collision_removal,
                u16 attached_id,
-               bool vertical, const std::string &texture, u32 id);
+               bool vertical, const std::string &texture, u32 id,
+               u32 material_type_param,  AnimationType animation_type, 
+               u16 vertical_frame_num, u16 horizontal_frame_num, 
+               u16 min_first_frame, u16 max_first_frame, 
+               float frame_length, bool loop_animation,
+               u8 glow);
 
        void SendDeleteParticleSpawner(u16 peer_id, u32 id);
 
@@ -450,7 +465,11 @@ private:
                v3f pos, v3f velocity, v3f acceleration,
                float expirationtime, float size,
                bool collisiondetection, bool collision_removal,
-               bool vertical, const std::string &texture);
+               bool vertical, const std::string &texture,
+               u32 material_type_param,  AnimationType animation_type, 
+               u16 vertical_frame_num, u16 horizontal_frame_num, u16 first_frame,
+               float frame_length, bool loop_animation,
+               u8 glow);
 
        u32 SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas);
        void SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable = true);