From f58fa99cf345f6543937e3326128322a4d3f5c90 Mon Sep 17 00:00:00 2001 From: dg <dg@51575b47-30f0-44d4-a5cc-537603b46e54> Date: Sun, 29 Jul 2012 17:47:57 +0000 Subject: [PATCH] Particles can have shaders attached New shader-enabled damage shield effect git-svn-id: http://svn.net-core.org/repos/t-engine4@5387 51575b47-30f0-44d4-a5cc-537603b46e54 --- game/engines/default/engine/Particles.lua | 16 +++++- game/engines/default/engine/Shader.lua | 2 + game/modules/tome/class/Actor.lua | 7 +++ game/modules/tome/class/Game.lua | 9 +++- .../tome/data/gfx/particles/shader_shield.lua | 48 +++++++++++++++++ .../data/gfx/particles_images/shield2.png | Bin 0 -> 16944 bytes .../modules/tome/data/gfx/shaders/shield.frag | 49 ++++++++++++++++++ game/modules/tome/data/gfx/shaders/shield.lua | 32 ++++++++++++ .../tome/data/timed_effects/magical.lua | 14 ++++- src/particles.c | 7 +++ src/particles.h | 2 + 11 files changed, 182 insertions(+), 4 deletions(-) create mode 100644 game/modules/tome/data/gfx/particles/shader_shield.lua create mode 100644 game/modules/tome/data/gfx/particles_images/shield2.png create mode 100644 game/modules/tome/data/gfx/shaders/shield.frag create mode 100644 game/modules/tome/data/gfx/shaders/shield.lua diff --git a/game/engines/default/engine/Particles.lua b/game/engines/default/engine/Particles.lua index 47fd3cca34..d1aa83ab0e 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 d25c249230..fa62ad9499 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 2b60589ca5..504099b9fb 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 21ff7ce9cf..b0417e50b5 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 0000000000..211fbb36a5 --- /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 GIT binary patch literal 16944 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 A0RR91 literal 0 HcmV?d00001 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 0000000000..1e255718ba --- /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 0000000000..f510bd0b3c --- /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 3a2656a7b5..103258d9f7 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 58823eea9d..d008615ae3 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 ef4a85afcf..46dc615773 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; -- GitLab