working on shaders

This commit is contained in:
Ryan Ward 2026-05-17 22:50:49 -07:00
parent 3f1d83f790
commit 1886b909d4
4 changed files with 309 additions and 1 deletions

View File

@ -937,6 +937,22 @@ function gui:newBase(typ, x, y, w, h, sx, sy, sw, sh, virtual)
function c:setShader(shader)
if type(shader) == "string" then
self.shader = love.graphics.newShader(shader)
elseif type(shader) == "table" then
self.shader = shader.source
for i,v in pairs(shader or {}) do
if i ~= "source" and i ~= "usage" then
if self[i] then
if type(v) == "function" then
local data = v(self)
self.shader:send(i, data)
else
self.shader:send(i, self[i])
end
else
error(i .. " is a required argument!\n\n".. shader.usage())
end
end
end
else
self.shader = shader -- already a compiled love Shader object
end

274
gui/shaders/shaders.lua Normal file
View File

@ -0,0 +1,274 @@
local shaders = {}
function NewShader(name, shader, opt_args)
local uniforms = {}
local opt_args = opt_args or {}
for typ, uname in shader:gmatch("extern%s+(%w+)%s+(%w+)%s*;") do
if uname ~= "time" and uname ~= "size" then
table.insert(uniforms, "Argument \"" .. uname .. "\" is expected to be: \"" .. typ .. "\"")
opt_args[uname] = true
end
end
if #opt_args > 0 or #uniforms > 0 then
opt_args.source = love.graphics.newShader(shader)
shaders[name] = opt_args
if opt_args.usage == nil then
opt_args.usage = function() return table.concat(uniforms,"\n").."\n" end
end
else
shaders[name] = love.graphics.newShader(shader)
end
end
function GetShaderUniforms(name)
local source = shaders[name] -- we need the source not the compiled shader
local uniforms = {}
for type, uname in source:gmatch("extern%s+(%w+)%s+(%w+)%s*;") do
uniforms[uname] = type
end
return uniforms
end
-- ─────────────────────────────────────────────
-- GLOW (original kept for reference)
-- Uniforms: vec2 size, float time
-- ─────────────────────────────────────────────
NewShader("glow", [[
extern float time;
vec4 effect(vec4 color, Image tex, vec2 tc, vec2 sc) {
vec4 pixel = Texel(tex, tc);
float pulse = 0.15 * sin(time * 3.0) + 0.85;
return vec4(pixel.rgb * pulse, pixel.a) * color;
}
]])
-- ─────────────────────────────────────────────
-- GRAYSCALE
-- Converts the sprite to grayscale (good for disabled/inactive state).
-- Uniforms: float grayScale (0.0 = full color, 1.0 = full gray)
-- ─────────────────────────────────────────────
NewShader("grayscale", [[
extern float amount;
vec4 effect(vec4 col, Image tex, vec2 tc, vec2 sc) {
vec4 pixel = Texel(tex, tc) * col;
float gray = dot(pixel.rgb, vec3(0.299, 0.587, 0.114));
float a = clamp(amount, 0.0, 1.0);
vec3 mixed = pixel.rgb * (1.0 - a) + vec3(gray) * a;
return vec4(mixed, pixel.a);
}
]])
-- ─────────────────────────────────────────────
-- CHROMATIC ABERRATION
-- Uniforms: float amount (try 0.003 0.012)
-- ─────────────────────────────────────────────
NewShader("chromatic_aberration", [[
extern float amount;
vec4 effect(vec4 color, Image tex, vec2 tc, vec2 sc) {
vec4 r = Texel(tex, tc + vec2(amount, 0.0));
vec4 g = Texel(tex, tc);
vec4 b = Texel(tex, tc + vec2(-amount, 0.0));
vec4 pixel = vec4(r.r, g.g, b.b, g.a) * color;
return pixel;
}
]])
-- ─────────────────────────────────────────────
-- GAUSSIAN BLUR (single-pass, 9-tap)
-- Run twice with {1,0} then {0,1} for full 2D blur.
-- Uniforms: vec2 direction ({1,0} or {0,1}), vec2 size
-- ─────────────────────────────────────────────
NewShader("blur", [[
extern vec2 direction;
extern vec2 size;
vec4 effect(vec4 color, Image tex, vec2 tc, vec2 sc) {
vec2 px = direction / size;
vec4 result = vec4(0.0);
result += Texel(tex, tc - px * 4.0) * 0.0162;
result += Texel(tex, tc - px * 3.0) * 0.0540;
result += Texel(tex, tc - px * 2.0) * 0.1216;
result += Texel(tex, tc - px * 1.0) * 0.1945;
result += Texel(tex, tc ) * 0.2270;
result += Texel(tex, tc + px * 1.0) * 0.1945;
result += Texel(tex, tc + px * 2.0) * 0.1216;
result += Texel(tex, tc + px * 3.0) * 0.0540;
result += Texel(tex, tc + px * 4.0) * 0.0162;
return result * color;
}
]])
-- ─────────────────────────────────────────────
-- SCANLINES
-- Uniforms: float strength (0.0-1.0), float count (e.g. 200)
-- ─────────────────────────────────────────────
NewShader("scanlines", [[
extern float strength;
extern float count;
vec4 effect(vec4 color, Image tex, vec2 tc, vec2 sc) {
vec4 pixel = Texel(tex, tc) * color;
float line = sin(tc.y * count * 3.14159) * 0.5 + 0.5;
float dim = 1.0 - strength * (1.0 - line);
return vec4(pixel.rgb * dim, pixel.a);
}
]])
-- ─────────────────────────────────────────────
-- PIXELATE
-- Uniforms: float pixels (grid cell size, e.g. 8.0), vec2 size
-- ─────────────────────────────────────────────
NewShader("pixelate", [[
extern float pixels;
extern vec2 size;
vec4 effect(vec4 color, Image tex, vec2 tc, vec2 sc) {
vec2 grid = floor(tc * size / pixels) * pixels / size;
return Texel(tex, grid) * color;
}
]])
-- ─────────────────────────────────────────────
-- VIGNETTE
-- Uniforms: float intensity (0.0-1.0), float smoothness (0.0-1.0)
-- ─────────────────────────────────────────────
NewShader("vignette", [[
extern float intensity;
extern float smoothness;
vec4 effect(vec4 color, Image tex, vec2 tc, vec2 sc) {
vec4 pixel = Texel(tex, tc) * color;
vec2 uv = tc - 0.5;
float dist = length(uv);
float vig = smoothstep(0.8, 0.8 - smoothness, dist * intensity);
return vec4(pixel.rgb * vig, pixel.a);
}
]])
-- ─────────────────────────────────────────────
-- HUE SHIFT
-- Uniforms: float hue (radians, 0 = no change)
-- ─────────────────────────────────────────────
NewShader("hue_shift", [[
extern float hue;
vec3 rgb2hsv(vec3 c) {
vec4 K = vec4(0.0, -1.0/3.0, 2.0/3.0, -1.0);
vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
float d = q.x - min(q.w, q.y);
float e = 1.0e-10;
return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
}
vec3 hsv2rgb(vec3 c) {
vec4 K = vec4(1.0, 2.0/3.0, 1.0/3.0, 3.0);
vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
}
vec4 effect(vec4 color, Image tex, vec2 tc, vec2 sc) {
vec4 pixel = Texel(tex, tc) * color;
vec3 hsv = rgb2hsv(pixel.rgb);
hsv.x = fract(hsv.x + hue / 6.28318);
return vec4(hsv2rgb(hsv), pixel.a);
}
]])
--[[
NEEDS TESTING :P
]]
-- ─────────────────────────────────────────────
-- DISSOLVE
-- Uniforms: float threshold (0.0=visible, 1.0=gone)
-- float edge_width (e.g. 0.05)
-- vec4 edge_color
-- ─────────────────────────────────────────────
NewShader("dissolve", [[
extern float threshold;
extern float edge_width;
extern vec4 edge_color;
float hash(vec2 p) {
return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453);
}
float noise(vec2 p) {
vec2 i = floor(p);
vec2 f = fract(p);
vec2 u = f * f * (3.0 - 2.0 * f);
return mix(mix(hash(i), hash(i + vec2(1,0)), u.x),
mix(hash(i + vec2(0,1)), hash(i + vec2(1,1)), u.x), u.y);
}
vec4 effect(vec4 color, Image tex, vec2 tc, vec2 sc) {
vec4 pixel = Texel(tex, tc) * color;
float n = noise(tc * 8.0);
if (n < threshold) discard;
if (n < threshold + edge_width) return edge_color;
return pixel;
}
]])
-- ─────────────────────────────────────────────
-- WAVE
-- Uniforms: float time, float amplitude (e.g. 0.01), float frequency (e.g. 10.0)
-- ─────────────────────────────────────────────
NewShader("wave", [[
extern float time;
extern float amplitude;
extern float frequency;
vec4 effect(vec4 color, Image tex, vec2 tc, vec2 sc) {
vec2 uv = tc;
uv.x += sin(uv.y * frequency + time * 3.0) * amplitude;
uv.y += sin(uv.x * frequency + time * 2.5) * amplitude * 0.6;
return Texel(tex, uv) * color;
}
]])
-- ─────────────────────────────────────────────
-- RAINBOW / IRIDESCENCE
-- Uniforms: float time, float speed (e.g. 1.0), float spread (e.g. 2.0)
-- ─────────────────────────────────────────────
NewShader("rainbow", [[
extern float time;
extern float speed;
extern float spread;
vec3 hsv2rgb(vec3 c) {
vec4 K = vec4(1.0, 2.0/3.0, 1.0/3.0, 3.0);
vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
}
vec4 effect(vec4 color, Image tex, vec2 tc, vec2 sc) {
vec4 pixel = Texel(tex, tc) * color;
float h = fract(tc.x * spread + time * speed * 0.1);
vec3 rainbow = hsv2rgb(vec3(h, 0.8, 1.0));
return vec4(pixel.rgb * rainbow, pixel.a);
}
]])
-- ─────────────────────────────────────────────
-- FLASH / HIT-FLASH
-- Uniforms: float flash (0.0=normal, 1.0=full flash)
-- vec4 flash_color (e.g. {1,1,1,1})
-- ─────────────────────────────────────────────
NewShader("flash", [[
extern float flash;
extern vec4 flash_color;
vec4 effect(vec4 color, Image tex, vec2 tc, vec2 sc) {
vec4 pixel = Texel(tex, tc) * color;
vec3 mixed = pixel.rgb * (1.0 - flash) + flash_color.rgb * flash;
return vec4(mixed, pixel.a);
}
]])
-- ─────────────────────────────────────────────
-- INVERT
-- Uniforms: float amount (0.0 = normal, 1.0 = fully inverted)
-- ─────────────────────────────────────────────
NewShader("invert", [[
extern float amount;
vec4 effect(vec4 color, Image tex, vec2 tc, vec2 sc) {
vec4 pixel = Texel(tex, tc) * color;
vec3 inverted = 1.0 - pixel.rgb;
vec3 mixed = pixel.rgb * (1.0 - amount) + inverted * amount;
return vec4(mixed, pixel.a);
}
]])
-- Auto hooks new shaders to SHADERS namespace, also adds the NewShader function
return {init = function(gui) gui.SHADERS=shaders gui.NewShader = NewShader end}

View File

@ -38,6 +38,24 @@ function love.load()
bg:fullFrame()
bg.color = color.new("#242f9b")
local btn = bg:newImageButton("rainbow.jpg", 100, 100, 600, 450)
btn.color = color.light_blue
btn.align = gui.ALIGN_CENTER
btn.direction = {1,0}
btn:enableShaderTime()
btn.OnEnter(function()
btn:setShader(gui.SHADERS.blur)
end)
btn.OnExit(function()
btn:setShader()
end)
-- btn:fitFont()
-- btn:centerFont()
-- bg:setBlur(10)
bg:OnUpdate(function(self, dt)
if self.__blur then
@ -47,7 +65,7 @@ function love.load()
end
end)
StartGame(bg)
-- StartGame(bg)
end
function GetActivePlayer()

BIN
rainbow.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB