diff --git a/game/engines/default/engine/Particles.lua b/game/engines/default/engine/Particles.lua index 47fd3cca345e7f9c9d88c691e3069c11caea147c..d1aa83ab0e5a09d351de021426e86cee4b5477f3 100644 --- a/game/engines/default/engine/Particles.lua +++ b/game/engines/default/engine/Particles.lua @@ -26,10 +26,11 @@ module(..., package.seeall, class.make) local __particles_gl = {} --- Make a particle emitter -function _M:init(def, radius, args) +function _M:init(def, radius, args, shader) self.args = args self.def = def self.radius = radius or 1 + self.shader = shader self:loaded() end @@ -72,7 +73,18 @@ function _M:loaded() args = args.."tile_w="..engine.Map.tile_w.."\ntile_h="..engine.Map.tile_h self.update = fct - self.ps = core.particles.newEmitter("/data/gfx/particles/"..self.def..".lua", args, self.zoom, config.settings.particles_density or 100, gl) + + local sha = nil + if self.shader then + if not self._shader then + local Shader = require 'engine.Shader' + self._shader = Shader.new(self.shader.type, self.shader) + end + + sha = self._shader.shad + end + + self.ps = core.particles.newEmitter("/data/gfx/particles/"..self.def..".lua", args, self.zoom, config.settings.particles_density or 100, gl, sha) end function _M:updateZoom() diff --git a/game/engines/default/engine/Shader.lua b/game/engines/default/engine/Shader.lua index d25c24923047d75e041139e2629058b9ef7ff02d..fa62ad9499cccf2365b5fcf63d6231d7059d835b 100644 --- a/game/engines/default/engine/Shader.lua +++ b/game/engines/default/engine/Shader.lua @@ -27,6 +27,8 @@ _M.verts = {} _M.frags = {} _M.progs = {} +loadNoDelay = true + --- Make a shader function _M:init(name, args) self.args = args or {} diff --git a/game/modules/tome/class/Actor.lua b/game/modules/tome/class/Actor.lua index 2b60589ca5b80a5595facdd5f9022c12d52ba1b2..504099b9fb6be79e3b0c233fc5844f761dcd43ec 100644 --- a/game/modules/tome/class/Actor.lua +++ b/game/modules/tome/class/Actor.lua @@ -1974,6 +1974,13 @@ function _M:onTakeHit(value, src) end function _M:takeHit(value, src, death_note) + for eid, p in pairs(self.tmp) do + local e = self.tempeffect_def[eid] + if e.damage_feedback then + e.damage_feedback(self, p, src, value) + end + end + local dead, val = engine.interface.ActorLife.takeHit(self, value, src, death_note) if dead and src and src.attr and src:attr("overkill") and src.project and not src.turn_procs.overkill then diff --git a/game/modules/tome/class/Game.lua b/game/modules/tome/class/Game.lua index 21ff7ce9cfe417a70d4585c0c1053fa965672f41..b0417e50b5010bfb31fce1ee32893c6c27fe8c9f 100644 --- a/game/modules/tome/class/Game.lua +++ b/game/modules/tome/class/Game.lua @@ -1213,8 +1213,15 @@ function _M:setupCommands() end end end end, [{"_g","ctrl"}] = function() if config.settings.cheat then - self:registerDialog(require("mod.dialogs.DownloadCharball").new()) + local ps = next(game.player.__particles) + + local a = math.rad(rng.float(0, 360)) + local r = rng.float(0.2, 0.4) + ps._shader:setUniform("impact", {math.cos(a) * r, math.sin(a) * r}) + ps._shader:setUniform("impact_tick", core.game.getTime()) + do return end + self:registerDialog(require("mod.dialogs.DownloadCharball").new()) local f, err = loadfile("/data/general/events/snowstorm.lua") print(f, err) setfenv(f, setmetatable({level=self.level, zone=self.zone}, {__index=_G})) diff --git a/game/modules/tome/data/gfx/particles/shader_shield.lua b/game/modules/tome/data/gfx/particles/shader_shield.lua new file mode 100644 index 0000000000000000000000000000000000000000..211fbb36a5693d10c40c9540f681562fb9cc6e68 --- /dev/null +++ b/game/modules/tome/data/gfx/particles/shader_shield.lua @@ -0,0 +1,48 @@ +-- ToME - Tales of Maj'Eyal +-- Copyright (C) 2009, 2010, 2011, 2012 Nicolas Casalini +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see <http://www.gnu.org/licenses/>. +-- +-- Nicolas Casalini "DarkGod" +-- darkgod@te4.org + +base_size = 32 + +local r = 1 +local g = 1 +local b = 1 +local a = 1 + +return { generator = function() + return { + trail = 0, + life = 10, + size = 38, sizev = 0, sizea = 0, + + x = 0, xv = 0, xa = 0, + y = 0, yv = 0, ya = 0, + dir = 0, dirv = dirv, dira = 0, + vel = 0, velv = 0, vela = 0, + + r = r, rv = 0, ra = 0, + g = g, gv = 0, ga = 0, + b = b, bv = 0, ba = 0, + a = a, av = -0.02, aa = 0.005, + } +end, }, +function(self) + self.ps:emit(1) +end, +1, +"particles_images/shield2" diff --git a/game/modules/tome/data/gfx/particles_images/shield2.png b/game/modules/tome/data/gfx/particles_images/shield2.png new file mode 100644 index 0000000000000000000000000000000000000000..aa9a097833754ab205c1a9e60a749686cd40354a Binary files /dev/null and b/game/modules/tome/data/gfx/particles_images/shield2.png differ diff --git a/game/modules/tome/data/gfx/shaders/shield.frag b/game/modules/tome/data/gfx/shaders/shield.frag new file mode 100644 index 0000000000000000000000000000000000000000..1e255718ba7c618b1f7d2f325eedd8d3c523661c --- /dev/null +++ b/game/modules/tome/data/gfx/shaders/shield.frag @@ -0,0 +1,49 @@ +uniform sampler2D tex; +uniform float tick; +uniform float aadjust; +uniform vec3 color; +uniform float time_factor; + +vec3 impact_color = vec3(1.0, 0.3, 1.0); +uniform vec2 impact; +uniform float impact_tick; + +void main(void) +{ + vec2 uv = vec2(0.5, 0.5) - gl_TexCoord[0].xy; + float l = length(uv) * 2.0; + float ll = l * l; + + vec4 c1 = texture2D(tex, (uv * ll / 1.3 + vec2(tick / time_factor, 0.0))); + vec4 c2 = texture2D(tex, (uv * ll / 1.3 + vec2(0.0, tick / time_factor))); + vec4 c = c1 * c2; + + float dist = max(min(1.0, 1.0 - l), 0.0) * 3.0; + c.a *= c.a * dist; + + float z = l; + c.a *= z; + + if (l > 1.0) c.a = 0.0; + if (l < 0.5) { + c.a *= ll * 4.0; + } + + // Impact + float it = tick - impact_tick; + if (it < 400.0) { + float v = (400.0 - it) / 400.0; + float il = distance(impact / ll, (vec2(0.5) - gl_TexCoord[0].xy) / ll); + if (il < 0.5 * (1.0 - v)) { + v *= v * v; + float ic = (1.0 - length(uv - impact)) * v * 3.0; + c.rgb = mix(c.rgb, impact_color, ic); + aadjust *= 1.0 + v * 3.0; + } + } + + c.a *= aadjust; + + c.rgb *= color; + gl_FragColor = c; +} diff --git a/game/modules/tome/data/gfx/shaders/shield.lua b/game/modules/tome/data/gfx/shaders/shield.lua new file mode 100644 index 0000000000000000000000000000000000000000..f510bd0b3c9b1947299f1fb43666efe54213efae --- /dev/null +++ b/game/modules/tome/data/gfx/shaders/shield.lua @@ -0,0 +1,32 @@ +-- ToME - Tales of Maj'Eyal +-- Copyright (C) 2009, 2010, 2011, 2012 Nicolas Casalini +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see <http://www.gnu.org/licenses/>. +-- +-- Nicolas Casalini "DarkGod" +-- darkgod@te4.org + +return { + frag = "shield", + vert = nil, + args = { + tex = { texture = 0 }, + color = color or {0.4, 0.7, 1.0}, + time_factor = time_factor or 4000, + aadjust = aadjust or 10, + impact = {0, 0}, + impact_tick = -1000, + }, + clone = false, +} diff --git a/game/modules/tome/data/timed_effects/magical.lua b/game/modules/tome/data/timed_effects/magical.lua index 3a2656a7b5dd850b64f8ef12f4810ff78a9aedb5..103258d9f7da2e5168fbc42c4d1b900f77b7c858 100644 --- a/game/modules/tome/data/timed_effects/magical.lua +++ b/game/modules/tome/data/timed_effects/magical.lua @@ -435,6 +435,14 @@ newEffect{ on_aegis = function(self, eff, aegis) self.damage_shield_absorb = self.damage_shield_absorb + eff.power * aegis / 100 end, + damage_feedback = function(self, eff, src, value) + if eff.particle and eff.particle._shader and eff.particle._shader.shad and src and src.x and src.y then + local r = -rng.float(0.2, 0.4) + local a = math.atan2(src.y - self.y, src.x - self.x) + eff.particle._shader:setUniform("impact", {math.cos(a) * r, math.sin(a) * r}) + eff.particle._shader:setUniform("impact_tick", core.game.getTime()) + end + end, activate = function(self, eff) if self:attr("shield_factor") then eff.power = eff.power * (100 + self:attr("shield_factor")) / 100 end if self:attr("shield_dur") then eff.dur = eff.dur + self:attr("shield_dur") end @@ -443,7 +451,11 @@ newEffect{ --- Warning there can be only one time shield active at once for an actor self.damage_shield_absorb = eff.power self.damage_shield_absorb_max = eff.power - eff.particle = self:addParticles(Particles.new("damage_shield", 1)) + if core.shader.active() then + eff.particle = self:addParticles(Particles.new("shader_shield", 1, nil, {type="shield", color={0.4, 0.7, 1.0}})) + else + eff.particle = self:addParticles(Particles.new("damage_shield", 1)) + end end, deactivate = function(self, eff) self:removeParticles(eff.particle) diff --git a/src/particles.c b/src/particles.c index 58823eea9d8bc4d8fd7692008d49ceb8b839a857..d008615ae387ec2d87c9887348c01615ca2923b9 100644 --- a/src/particles.c +++ b/src/particles.c @@ -83,6 +83,8 @@ static int particles_new(lua_State *L) // float zoom = luaL_checknumber(L, 3); int density = luaL_checknumber(L, 4); GLuint *texture = (GLuint*)auxiliar_checkclass(L, "gl{texture}", 5); + shader_type *s = NULL; + if (lua_isuserdata(L, 6)) s = (shader_type*)auxiliar_checkclass(L, "gl{program}", 6); particles_type *ps = (particles_type*)lua_newuserdata(L, sizeof(particles_type)); auxiliar_setclass(L, "core{particles}", -1); @@ -100,6 +102,7 @@ static int particles_new(lua_State *L) ps->particles = NULL; ps->init = FALSE; ps->texture = *texture; + ps->shader = s; thread_add(ps); return 1; @@ -182,6 +185,8 @@ static int particles_to_screen(lua_State *L) glScalef(ps->zoom * zoom, ps->zoom * zoom, ps->zoom * zoom); glRotatef(ps->rotate, 0, 0, 1); + if (ps->shader) useShader(ps->shader, 1, 1, 1, 1, 1, 1, 1, 1); + int remaining = ps->batch_nb; while (remaining >= PARTICLES_PER_ARRAY) { @@ -190,6 +195,8 @@ static int particles_to_screen(lua_State *L) } if (remaining) glDrawArrays(GL_QUADS, 0, remaining); + if (ps->shader) glUseProgramObjectARB(0); + glRotatef(-ps->rotate, 0, 0, 1); glPopMatrix(); glTranslatef(-x, -y, 0); diff --git a/src/particles.h b/src/particles.h index ef4a85afcfc813f88910a37342cfd123e77063ba..46dc615773abe2f6d40ccd5ddc3a8c9c74aad6d7 100644 --- a/src/particles.h +++ b/src/particles.h @@ -22,6 +22,7 @@ #define _PARTICLES_H_ #include "tgl.h" +#include "useshader.h" typedef struct { float size, sizev, sizea; @@ -40,6 +41,7 @@ typedef struct { // Read only by main GLuint texture; + shader_type *shader; // W by main, R by thread const char *name_def;