Shader (CMS)
From The Official Visionaire Studio: Adventure Game Engine Wiki
Name | Version | Type | By |
---|---|---|---|
Shader Toolkit | 0.96 | Definition | Simon Scheckel, with edits by AFRLme |
This script offers some easy functions to use shader power. It ranges from blur, noise, saturation, contrast, lightness, colorize to some simple camera controls. Visionaire Studio 5.x is required to run this script.
Quick note: The script on here may be outdated, please download the latest version for 5.x from the resources section at the bottom of the page. |
Instructions
1. Add the main script to the Visionaire Studio Script Editor & set the script as a definition script.
2. Call the functions you need.
Shader Toolkit Functions
Function Name | Description |
---|---|
shaderAddEffect() | Add various dynamic pre-made warp effects to the screen. |
shaderBlur() | Blur/Focus the screen over x amount of milliseconds. |
shaderColorize() | Tint all the graphics on the screen a specific color over x amount of milliseconds. |
shaderContrast() | Set the global contrast level of the screen over x amount of milliseconds. |
shaderFollowCharacter() | Softly follow the linked character around the screen. |
shaderGlow() | Create a glow effect on light/saturated scene objects (automatically selected) over x amount of milliseconds. |
shaderHue() | Adjust the hue level of the screen over x amount of milliseconds. |
shaderLightness() | Adjust the lightness of the screen over x amount of milliseconds. |
shaderNoise() | Apply noise effect to the screen over x amount of milliseconds. |
shaderPan() | Pan the camera on the x or y axis over x amount of milliseconds. |
shaderRotate() | Rotate the screen over x amount of milliseconds. |
shaderSaturation() | Adjust saturation value of the screen over x amount of milliseconds. |
shaderViewport() | Pan, zoom & rotate the camera over x amount of milliseconds. |
shaderZoom() | Zoom the camera over x amount of milliseconds. |
shaderZoomCharacter() | Zoom camera into or out of linked characters position over x amount of milliseconds. |
shaderZoomObject() | Zoom camera into or out of linked objects location over x amount of milliseconds. |
Examples
shaderZoomCharacter("", 1.2, 3000, easeBackOut) -- Zoom 1.2x on current character in 3s with one bounce
shaderZoomObject(getObject("Objects[pole]"), 1.4, 3000, easeBounceOut)
shaderFollowCharacter("Heinz", 2, 3000, easeQuintOut) -- Follow character Heinz with a slow camera
shaderViewport(2, 300, 200, 1.41, 3000, easeBounceInOut) -- advanced zooming with rotating
shaderNoise(1, -0.1, 3000) -- activate noise in 3s with a soft black grain
shaderBlur(1, 3000) -- activate blur in 3s
shaderSaturation(0, 3000) -- desaturate image in 3s
shaderLightness(-0.5, 3000) -- darken image in 3s
shaderContrast(2, 3000) -- double contrast
shaderHue(0.5, 2000) -- turn hue wheel, red->green
shaderColorize(0, 1, 3000) -- colorize with red
Reset Values
shaderViewport(1, 0, 0, 0, 1000, easeQuintOut)
shaderStopFollow(easeQuintOut) -- Stop following character & reset viewport
shaderNoise(0, 0, 3000)
shaderBlur(0, 3000)
shaderSaturation(1, 3000)
shaderLightness(0, 3000)
shaderContrast(1, 3000)
shaderHue(0, 3000)
shaderColorize(0, 0, 3000)
Main Script
--[VISMODULE,id,version,chksum]
--
-- Shader Toolkit Hue, Saturation, Luminance, Blur, Noise, Camera Control, Bloom, Random Effects
-- (c) 2015 Simon Scheckel, Visionaire Studio Engine - with edits by AFRLme
-- Version 0.96
-- updated 29/09/2014 for 4.1
-- added some save functionality 9/10
-- bugfix version 16/10
-- update 10/6/15 radial glow, use per object matrices
-- update 3/2/16 cross platform shaders requires 4.3
-- update 28/9/18 lua 5.3
--
-- Matrix functions from https://github.com/davidm/lua-matrix/blob/master/lua/matrix.lua
-- Developers: Michael Lutz (chillcode) - original author David Manura http://lua-users.org/wiki/DavidManura
--
-- Usage:
--
-- all factors like zoom, scale are normally 1 to have no change
-- delay in ms
-- hue in 0-1 (0 = red, 0.5 = cyan, 1 = red again)
--
-- easing functions: Back, Bounce, Circ, Cubic, Elastic, Linear, None, Quad, Quint, Sine, all In/Out/InOut
-- examples: easeBackOut, easeLinearIn, easeElasticInOut etc
-- More information about that: http://easings.net
--
-- shaderZoomCharacter(name, c_scale, delay, easing)
-- shaderZoomObject(object, c_scale, delay, easing)
-- shaderFollowCharacter(name, c_scale, delay)
-- shaderStopFollow()
-- shaderViewportInterpolationPoint(x,y)
-- shaderViewport(zoom, x, y, rotation, delay, easing) rotation in 0-2Pi (full turn)
-- shaderPan(offset, delay, easing, axis)
-- shaderRotate(degree, delay, easing) -- degree values 0 to 359 (automatically converts value to Pi)
-- shaderZoom(zoom, delay, easing)
-- on: 1 = on, 0 = off
--
-- shaderNoise(on, strength, delay) -- strength * noise + color, so strength < 0 creates black noise and > 0 white
-- shaderBlur(radius, delay)
-- shaderSaturation(factor, delay)
-- shaderLightness(offset, delay)
-- shaderContrast(contrast, delay)
-- shaderHue(target, delay)
-- shaderColorize(hue, strength, delay)
--
-- shaderActivate()
-- shaderDeactivate()
--
-- shaderGlow(on, radius, exposure)
-- shaderAddEffect(name)
-- shaderRemoveEffect(name)
-- shaderEffectParam(shader, name, value)
-- shaderLamp(index, type, position, targetpos, falloff, ambient, diffuse, diffusefactor, exponent, cutoff)
--
-- Effects at the time:
--[[
warp1
tv1
ripple1
ripple2
ascii
edgeglow
chroma
ripple3
warp2
ripple4
pearls
highlight
fourbit
tv2
tv3
tv4
--
-- Read no further if the word matrix multiplication frightens you
--]]
local matrix = {_TYPE='module', _NAME='matrix', _VERSION='0.2.11.20120416'}
local matrix_meta = { }
function matrix:new( rows, columns, value )
if type( rows ) == "table" then
if type(rows[1]) ~= "table" then
return setmetatable( {{rows[1]},{rows[2]},{rows[3]}},matrix_meta )
end
return setmetatable( rows,matrix_meta )
end
local mtx = {}
local value = value or 0
if columns == "I" then
for i = 1,rows do
mtx[i] = {}
for j = 1,rows do
if i == j then
mtx[i][j] = 1
else
mtx[i][j] = 0
end
end
end
else
for i = 1,rows do
mtx[i] = {}
for j = 1,columns do
mtx[i][j] = value
end
end
end
return setmetatable( mtx,matrix_meta )
end
function matrix.mul( m1, m2 )
local mtx = {}
for i = 1,#m1 do
mtx[i] = {}
for j = 1,#m2[1] do
local num = m1[i][1] * m2[1][j]
for n = 2,#m1[1] do
num = num + m1[i][n] * m2[n][j]
end
mtx[i][j] = num
end
end
return setmetatable( mtx, matrix_meta )
end
function matrix.type( mtx )
local e = mtx[1][1]
if type(e) == "table" then
if e.type then
return e:type()
end
return "tensor"
end
return "number"
end
local num_copy = function( num )
return num
end
local t_copy = function( t )
local newt = setmetatable( {}, getmetatable( t ) )
for i,v in ipairs( t ) do
newt[i] = v
end
return newt
end
function matrix.transpose( m1 )
local docopy = matrix.type( m1 ) == "number" and num_copy or t_copy
local mtx = {}
for i = 1,#m1[1] do
mtx[i] = {}
for j = 1,#m1 do
mtx[i][j] = docopy( m1[j][i] )
end
end
return setmetatable( mtx, matrix_meta )
end
function matrix.tofloat( m1 )
local mtx = {}
local pos = 1
for i = 1,#m1 do
for j = 1,#m1[1] do
mtx[pos] = m1[i][j]
pos=pos+1
end
end
return mtx
end
matrix_meta.__mul = matrix.mul
matrix_meta.__index = {tofloat = matrix.tofloat, transpose = matrix.transpose}
setmetatable( matrix, { __call = function( ... ) return matrix.new( ... ) end } )
-- End of matrix functions
function string.fromhex(str)
return (str:gsub('..', function (cc)
return string.char(tonumber(cc, 16))
end))
end
function string.tohex(str)
return (str:gsub('.', function (c)
return string.format('%02X', string.byte(c))
end))
end
--
-- Source: http://lua-users.org/wiki/DataDumper
--[[ DataDumper.lua
Copyright (c) 2007 Olivetti-Engineering SA
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
]]
local dumplua_closure = [[
local closures = {}
local function closure(t)
closures[#closures+1] = t
t[1] = assert(load(t[1]))
return t[1]
end
for _,t in pairs(closures) do
for i = 2,#t do
debug.setupvalue(t[1], i-1, t[i])
end
end
]]
local lua_reserved_keywords = {
'and', 'break', 'do', 'else', 'elseif', 'end', 'false', 'for',
'function', 'if', 'in', 'local', 'nil', 'not', 'or', 'repeat',
'return', 'then', 'true', 'until', 'while' }
local function keys(t)
local res = {}
local oktypes = { stringstring = true, numbernumber = true }
local function cmpfct(a,b)
if oktypes[type(a)..type(b)] then
return a < b
else
return type(a) < type(b)
end
end
for k in pairs(t) do
res[#res+1] = k
end
table.sort(res, cmpfct)
return res
end
local c_functions = {}
for _,lib in pairs{'_G', 'string', 'table', 'math',
'io', 'os', 'coroutine', 'package', 'debug'} do
local t = _G[lib] or {}
lib = lib .. "."
if lib == "_G." then lib = "" end
for k,v in pairs(t) do
if type(v) == 'function' and not pcall(string.dump, v) then
c_functions[v] = lib..k
end
end
end
function DataDumper(value, varname, fastmode, ident)
local defined, dumplua = {}
-- Local variables for speed optimization
local string_format, type, string_dump, string_rep =
string.format, type, string.dump, string.rep
-- local tostring, pairs, table_concat =
-- tostring, pairs, table.concat
local pairs, table_concat =
pairs, table.concat
local keycache, strvalcache, out, closure_cnt = {}, {}, {}, 0
setmetatable(strvalcache, {__index = function(t,value)
local res = string_format('%q', value)
t[value] = res
return res
end})
local fcts = {
string = function(value) return strvalcache[value] end,
number = function(value) return value end,
boolean = function(value) return tostring(value) end,
['nil'] = function(value) return 'nil' end,
['function'] = function(value)
return string_format("load(%q)", string_dump(value))
end,
userdata = function(value)
--if value.getId ~= nil then
-- return value:getId().id .. " " .. value:getName()
--else
-- return "userdata"
--end
end,
thread = function() error("Cannot dump threads") end,
}
local function test_defined(value, path)
if defined[value] then
if path:match("^getmetatable.*%)$") then
out[#out+1] = string_format("s%s, %s)\n", path:sub(2,-2), defined[value])
else
out[#out+1] = path .. " = " .. defined[value] .. "\n"
end
return true
end
defined[value] = path
end
local function make_key(t, key)
local s
if type(key) == 'string' and key:match('^[_%a][_%w]*$') then
s = key .. "="
else
s = "[" .. dumplua(key, 0) .. "]="
end
t[key] = s
return s
end
for _,k in ipairs(lua_reserved_keywords) do
keycache[k] = '["'..k..'"] = '
end
if fastmode then
fcts.table = function (value)
-- Table value
local numidx = 1
out[#out+1] = "{"
for key,val in pairs(value) do
if key == numidx then
numidx = numidx + 1
else
out[#out+1] = keycache[key]
end
local str = dumplua(val)
out[#out+1] = str..","
end
if string.sub(out[#out], -1) == "," then
out[#out] = string.sub(out[#out], 1, -2);
end
out[#out+1] = "}"
return ""
end
else
fcts.table = function (value, ident, path)
if test_defined(value, path) then return "nil" end
-- Table value
local sep, str, numidx, totallen = " ", {}, 1, 0
local meta, metastr = (debug or getfenv()).getmetatable(value)
if meta then
ident = ident + 1
metastr = dumplua(meta, ident, "getmetatable("..path..")")
totallen = totallen + #metastr + 16
end
for _,key in pairs(keys(value)) do
local val = value[key]
local s = ""
local subpath = path
if key == numidx then
subpath = subpath .. "[" .. numidx .. "]"
numidx = numidx + 1
else
s = keycache[key]
if not s:match "^%[" then subpath = subpath .. "." end
subpath = subpath .. s:gsub("%s*=%s*$","")
end
local res = dumplua(val, ident+1, subpath)
if res ~= nil then
s = s .. res
end
str[#str+1] = s
totallen = totallen + #s + 2
end
if totallen > 80 then
sep = "\n" .. string_rep(" ", ident+1)
end
str = "{"..sep..table_concat(str, ","..sep).." "..sep:sub(1,-3).."}"
if meta then
sep = sep:sub(1,-3)
return "setmetatable("..sep..str..","..sep..metastr..sep:sub(1,-3)..")"
end
return str
end
fcts['function'] = function (value, ident, path)
if test_defined(value, path) then return "nil" end
if c_functions[value] then
return c_functions[value]
elseif debug == nil or debug.getupvalue(value, 1) == nil then
return string_format("load(%q)", string_dump(value))
end
closure_cnt = closure_cnt + 1
local res = {string.dump(value)}
for i = 1,math.huge do
local name, v = debug.getupvalue(value,i)
if name == nil then break end
res[i+1] = v
end
print(res)
return "closure " .. dumplua(res, ident, "closures["..closure_cnt.."]")
end
end
function dumplua(value, ident, path)
return fcts[type(value)](value, ident, path)
end
if varname == nil then
varname = "return "
elseif varname:match("^[%a_][%w_]*$") then
varname = varname .. " = "
end
if fastmode then
setmetatable(keycache, {__index = make_key })
out[1] = varname
table.insert(out,dumplua(value, 0))
return table.concat(out)
else
setmetatable(keycache, {__index = make_key })
local items = {}
for i=1,10 do items[i] = '' end
items[3] = dumplua(value, ident or 0, "t")
if closure_cnt > 0 then
items[1], items[6] = dumplua_closure:match("(.*\n)\n(.*)")
out[#out+1] = ""
end
if #out > 0 then
items[2], items[4] = "local t = ", "\n"
items[5] = table.concat(out)
items[7] = varname .. "t"
else
items[2] = varname
end
return table.concat(items)
end
end
-- End of DataDumper
--
-- Shader Metatable
shaders_compiled = {}
local shader_meta = {}
local shader = {}
function shader:new (this, id, file)
local shader = {}
shader.num = shaderCompile(file)
shader.id = id
if shaders_compiled[id] == nil then
shaders_compiled[id] = {}
end
return setmetatable( shader, shader_meta )
end
shader_meta.__call = function(this)
return this.num
end
shader_meta.__newindex = function(this, field, value)
shaders_compiled[this.id][field] = value
graphics.shaderUniform(this.num, field, value)
end
setmetatable( shader, { __call = function( ... ) return shader:new( ... ) end } )
function tween(val,newval,delay,ease)
startTween(val, _G[val], newval, delay,ease)
end
shaders = {
_temporary_=0, c_scene = game.CurrentScene,
glownum = shader("glow","sht_glow.bin"),
rglownum = shader("rglow","sht_glowradial.bin"),
bnum = shader("blur","sht_blur.bin"),
num = shader("num","sht_color.bin")
}
shader_coeff0=0
shader_coeff1=1
shader_coeff2=1
shader_coeff3=0
shader_blur=0
shader_downsize=1
shader_colorize=0
shader_color=0
shader_iTime = 0
shader_noise=0
shader_noiseStrength=0.0
shader_passes=2
shader_active = true
shader_glow = 0
shader_glowradius = 0
shader_glowexp = 1
shader_rotate=0.0
shader_scale = 1.0
shader_offsetx = 0.0
shader_offsety = 0.0
shader_follow = {on=0, name="", c_scale=1, easing = easeQuintOut, delay = 0}
c_res=game.WindowResolution
shaders.num.weights = {shader_colorize,shader_color}
shaders.num.shader_coeff = {shader_coeff0,shader_coeff1,shader_coeff2,shader_coeff3}
shaders.glownum.resolution = {c_res.x,c_res.y}
if graphics.isUpsideDown() then
shaders.bnum.upsideDown = 1.0
shaders.rglownum.upsideDown = 1.0
shaders.glownum.upsideDown = 1.0
else
shaders.glownum.upsideDown = 0.0
shaders.bnum.upsideDown = 0.0
shaders.rglownum.upsideDown = 0.0
end
shaders.bnum.resolution = {c_res.x,c_res.y}
-- * function that stops following specified character & resets camera back to default * --
function shaderStopFollow(easing)
shader_follow.on = 0
shaderViewport(1, 0, 0, 0, shader_follow.delay, easing)
unregisterEventHandler("mainLoop", "followCharacter")
end
-- * function that smoothly follows specified character * --
function shaderFollowCharacter(name, c_scale, delay, easing)
if name == "" then name = game.CurrentCharacter:getName() end
if shader_follow.on == 0 then registerEventHandler("mainLoop", "followCharacter") end
shader_follow.on = 1
shader_follow.name = name
shader_follow.c_scale = c_scale
shader_follow.delay = delay
shader_follow.easing = easing or easeQuintOut
end
function shaderZoomCharacter(name, c_scale, delay, easing)
local c_position={}
if(name=="")then
c_position=game.CurrentCharacter.Position
else
c_position=Characters[name].Position
end
local c_scroll=game.ScrollPosition
c_position.x=c_position.x-c_scroll.x
c_position.y=c_position.y-c_scroll.y
c_position.x=c_position.x-(c_res.x/c_scale/2)
c_position.y=c_position.y-(c_res.y/c_scale/1.2)
c_position.x = math.min(math.max(0,c_position.x), game.CurrentScene.Sprite:getSize().x - c_res.x/c_scale)
c_position.y = math.min(math.max(0,c_position.y), game.CurrentScene.Sprite:getSize().y - c_res.y/c_scale)
shaderViewport(c_scale, c_position.x, c_position.y, 0, delay, easing)
end
function shaderZoomObject(object, c_scale, delay, easing)
local c_position=object.Position
local c_scroll=game.ScrollPosition
c_position.x=c_position.x-c_scroll.x
c_position.y=c_position.y-c_scroll.y
c_position.x=c_position.x-(c_res.x/c_scale/2)
c_position.y=c_position.y-(c_res.y/c_scale/1.2)
c_position.x = math.min(math.max(0,c_position.x), game.CurrentScene.Sprite:getSize().x - c_res.x/c_scale)
c_position.y = math.min(math.max(0,c_position.y), game.CurrentScene.Sprite:getSize().y - c_res.y/c_scale)
shaderViewport(c_scale, c_position.x, c_position.y, 0, delay, easing)
end
function shaderNoise(on, strength,delay)
shaders.num.noise = on
startTween("shader_noiseStrength", shader_noiseStrength, strength, delay,easeLinearInOut)
shader_noise=on
end
function shaderSaturation(factor, delay)
startTween("shader_coeff1",shader_coeff1,factor,delay,easeLinearInOut)
end
function shaderLightness(offset, delay)
startTween("shader_coeff3",shader_coeff3,offset,delay,easeLinearInOut)
end
function shaderContrast(contrast, delay)
startTween("shader_coeff2",shader_coeff2,contrast,delay,easeLinearInOut)
end
function shaderHue(target, delay)
startTween("shader_coeff0",shader_coeff0,target,delay,easeLinearInOut)
end
function shaderColorize(hue, strength, delay)
startTween("shader_colorize",shader_colorize,strength,delay,easeLinearIn)
shader_color=hue
end
shader_viewportTransition = 1.0
shader_oldViewport = { x = 0.0, y=0.0, scale = 1.0, rotate = 0.0}
shader_newViewport = { x = 0.0, y=0.0, scale = 1.0, rotate = 0.0}
shader_interpolationPoint = {x=0.0, y=0.0}
function shaderViewportInterpolationPoint(x,y)
shader_interpolationPoint = {x=x, y=y}
end
function shaderViewport(zoom, x, y, rotation, delay, easing)
shader_viewportTransition = 0.0
shader_oldViewport.x = shader_offsetx
shader_oldViewport.y = shader_offsety
shader_oldViewport.scale = shader_scale
shader_oldViewport.rotate = shader_rotate
shader_newViewport.x = x
shader_newViewport.y = y
shader_newViewport.scale = zoom
shader_newViewport.rotate = rotation
startTween("shader_viewportTransition", 0.0, 1.0, delay,easing)
currentlyZoomedParameters = { zoomFactor = zoom, x = x, y = y, rotationFactor = rotation }
if delay == 0 then return end
end
-- * allows you to pan the camera left or right * --
function shaderPan(offset, delay, easing, axis)
if axis then
startTween("shader_offsety", shader_offsety, offset, delay, easing)
else
startTween("shader_offsetx", shader_offsetx, offset, delay, easing)
end
end
-- * allows you to zoom the camera in or out * --
function shaderZoom(zoom, delay, easing)
startTween("shader_scale", shader_scale, zoom, delay, easing)
end
-- * allows you to rotate the screen (w/ degree instead of pi) * --
function shaderRotate(degree, delay, easing)
degree = (degree / 360 * 2 * 3.14) -- convert degree to pi
startTween("shader_rotate", shader_rotate, degree, delay, easing)
end
-- * function that follows character; only active when loop enabled * --
function followCharacter()
shaderZoomCharacter(shader_follow.name, shader_follow.c_scale, shader_follow.delay, shader_follow.easing)
end
shader_effects = {_temporary_=0,
transition={shader= "sht_transition.bin"} ,
warp1={shader= "sht_warp1.bin"} ,
light1={shader="sht_light.bin"},
tv1 = {shader = "sht_tv1.bin"},
ripple1 = {shader = "sht_ripple1.bin", vars={speed=0.2, speed_x=0.3, speed_y=0.3, intensity=0.0, frequency=6.0}},
ripple2 = {shader = "sht_ripple2.bin"},
ascii = {shader = "sht_ascii.bin"},
edgeglow = {shader = "sht_edgeglow.bin"},
chroma = {shader = "sht_chroma.bin"},
ripple3 = {shader = "sht_ripple3.bin"},
warp2 = {shader = "sht_warp2.bin"},
ripple4 = {shader = "sht_ripple4.bin"},
pearls={shader="sht_pearls.bin"},
highlight={shader="sht_hightlight.bin"},
fourbit={shader="sht_fourbit.bin"},
tv2={shader="sht_tv2.bin"},
tv3={shader="sht_tv3.bin"},
tv4={shader="sht_tv4.bin"}
}
function clamp(a,b,c)
return math.min(math.max(a,b),c)
end
function modf(a)
local a,b = math.modf(a)
return b
end
--[[vector =
{
add = function(a,b) return {a[1]+b[1],a[2]+b[2],a[3]+b[3]} end,
sub = function(a,b) return {a[1]-b[1],a[2]-b[2],a[3]-b[3]} end,
mult = function(a,b) return {a*b[1],a*b[2],a*b[3]} end,
abs = function(a) return {math.abs(a[1]),math.abs(a[2]),math.abs(a[3])} end,
modf = function(a) return {modf(a[1]),modf(a[2]),modf(a[3])} end,
mix = function(a,b,c) return {a[1]*(1-c)+b[1]*c,a[2]*(1-c)+b[2]*c,a[3]*(1-c)+b[3]*c} end,
clamp = function(a,b,c) return {clamp(a[1],b,c),clamp(a[2],b,c),clamp(a[3],b,c)} end
}
function fromHSV(h, s, v)
local K = {1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0}
local p = vector.abs(vector.sub(vector.mult(6.0,vector.modf(vector.add({h,h,h},{K[1],K[2],K[3]}))), {K[4],K[4],K[4]}))
return vector.mult(v, vector.mix({K[1],K[1],K[1]}, vector.clamp(vector.sub(p,{K[1],K[1],K[1]}), 0.0, 1.0), s))
end]]
function standardparam(param, standard)
if param==nil then
return standard
else
return param
end
end
function shaderGlow(on, blurradius, alpha)
if on == 0 then
passesRemove(5,"glow")
shader_glow = on
shader_glowradius = blurradius
shader_glowexp = alpha
else
passesAdd(5,"glow",{{ shader = shaders.glownum(), source=1, target = 2, clear = 0, variable = "shaders.glownum._i_firstpass" },
{ shader = shaders.glownum(), source=2, target = 1, clear = 0 },
{ shader = shaders.glownum(), source=1, target = 2, clear = 0 },
{ shader = shaders.glownum(), source=2, target = 1, clear = 0 },
{ shader = shaders.glownum(), source=1, target = 2, clear = 0 },
{ shader = shaders.glownum(), source=2, target = 1, clear = 0 },
{ shader = shaders.glownum(), source=1, target = 0, clear = 0, comp_dst=1, comp_src=1, variable = "shaders.glownum._i_lastpass" }}) -- 5 4 for cutout
shader_glow = on
shader_glowradius = blurradius
shader_glowexp = alpha
end
end
function shaderRadialGlow(on, blurradius, alpha)
if on == 0 then
passesRemove(6,"rglow")
shader_rglow = on
shader_rglowradius = blurradius
shader_rglowexp = alpha
else
passesAdd(6,"rglow",{{ shader = shaders.rglownum(), source=1, target = 2, clear = 0, variable = "shaders.rglownum._i_firstpass" },
{ shader = shaders.rglownum(), source=2, target = 1, clear = 0 },
{ shader = shaders.rglownum(), source=1, target = 2, clear = 0 },
{ shader = shaders.rglownum(), source=2, target = 0, clear = 0, comp_dst=1, comp_src=1, variable = "shaders.rglownum._i_lastpass" }})
shader_rglow = on
shader_rglowradius = blurradius
shader_rglowexp = alpha
end
end
function shaderActivateLighting(lights)
if(shader_effects.light1.num==nil)then
shader_effects.light1.num = shader("light1", shader_effects.light1.shader)
end
shader_effects.light1.num.resolution = {game.WindowResolution.x, game.WindowResolution.y}
passesAdd(2,"light1",{ { shader = shader_effects.light1.num(), source=1, target = 2, clear = 0 } })
local sh = shader_effects.light1.num
sh.lights_count = lights
end
function shaderDeactivateLighting()
passesRemove(2,"light1")
end
function table.join(t1, t2)
local t3 = {}
local offset = #t1
for k,v in pairs(t1) do
t3[k] = v
end
for k,v in pairs(t2) do
if(type(k)=="string")then
t3[k] = v
else
t3[offset + k] = v
end
end
return t3
end
function shaderLamp(index, type, position, targetpos, falloff, ambient, diffuse, diffusefactor, exponent, cutoff)
local l = "lights["..index.."]."
position[3]=standardparam(position[3],1.0)
targetpos[3]=standardparam(targetpos[3],10.0)
local sh = shader_effects["light1"].num
sh[l.."position"] = position
sh[l.."targetpos"] = targetpos
sh["_i_"..l.."type"] = type
sh[l.."lightfalloff"] = standardparam(falloff,{0.01,0.0001,0.0})
sh[l.."ambient"] = standardparam(ambient,{0,0,0})
sh[l.."diffuse"] = standardparam(diffuse,{1,1,1})
sh[l.."diffusefactor"] = standardparam(diffusefactor,1)
if type==0 then --point light
sh[l.."exponent"] = standardparam(exponent,90)
sh[l.."cutoff"] = standardparam(cutoff,0)
end
end
-- * function that blurs the screen * --
function shaderBlur(strength, delay)
passesAdd(2, "blur", {
{ shader = shaders.bnum(), source=1, target = 2, clear = 0, variable = "shaders.bnum._i_firstpass" },
{ shader = shaders.bnum(), source=2, target = 1, clear = 0},
{ shader = shaders.bnum(), source=1, target = 2, clear = 0 },
{ shader = shaders.bnum(), source=2, target = 1, clear = 0 },
{ shader = shaders.bnum(), source=1, target = 2, clear = 0 },
{ shader = shaders.bnum(), source=2, target = 0, clear = 0, comp_dst=0, variable = "shaders.bnum._i_lastpass" }})
startTween("shader_blur",shader_blur,strength, delay,easeBackInOut)
end
function shaderActivate()
shader_active = true
passesUpdate()
end
function shaderDeactivate()
shader_active = false
passesUpdate()
end
-- Passes
shader_passes = {
{"basic",{renderbuffers = 2, { shader = shaders.num(), source=0, target = 1 }}}, -- basic slot, hue, sat, lightness
{}, -- slot 2 takes many effects
{}, -- slot 3 takes blur
{"composite", {{source = 1, target = 0 }}}, -- slot 4 takes compositing everything
{}, -- slot 5 is for glow
{} -- slot 6 is for radial glow
}
shader_slots = {
{shader = 0, comp_src = 5, comp_dst = 4}
}
function passesRemove(position, id)
if position==2 then -- effects slot
for k,v in pairs(shader_passes[2]) do
if(v[1]==id)then
table.remove(shader_passes[2], k)
break
end
end
else
if shader_passes[position][1]==id then
shader_passes[position]={}
end
end
passesUpdate()
end
function passesAdd(position, id, passes)
if position==2 then -- effects slot
local found = false
for k,v in pairs(shader_passes[2]) do
if(v[1]==id)then
found = true
end
end
if not found then
table.insert(shader_passes[2], {id, passes})
end
else
if(shader_passes[position][1]==nil)then
shader_passes[position]={id, passes}
end
end
passesUpdate()
end
function passesUpdate()
for k,v in pairs(shaders_compiled) do
if(k~="glow" and k~="num" and k~="blur" and k~="rglow" and shader_effects[k].num==nil)then
shader_effects[k].num = shader(k, "", shader_effects[k].shader)
end
end
if shader_active == false then
shaderSetOptions({ { shader = shaders.num(), source=0, target = 0, clear = 0 } })
else
-- composite passes
local worktable = {}
local lastpass = 0
for k,v in pairs(shader_passes) do
if(k==2)then
for k,v in pairs(shader_passes[2]) do
for i,v in pairs(shader_passes[2][k][2]) do
v.source = lastpass + 1
lastpass = (lastpass + 1) % 2
v.target = lastpass + 1
end
worktable = table.join(worktable,v[2])
end
elseif v[2] ~= nil then
if k~=1 then
if k==5 or k==6 then
lastpass = (lastpass + 1) % 2
end
for i,v in pairs(shader_passes[k][2]) do
if type(v)=="table" then
v.source = lastpass + 1
lastpass = (lastpass + 1) % 2
v.target = lastpass + 1
if (k==4 or k==5 or k==6) and i==#shader_passes[k][2] then
v.target = 0
end
end
end
end
worktable = table.join(worktable,v[2])
end
end
for k,v in pairs(worktable) do
if type(v) == "table" and v.variable ~= nil then
load(v.variable.."="..(k-1))()
end
end
shaderSetOptions(worktable)
end
end
function shaderAddEffect(name, _table)
if(shader_effects[name].num==nil)then
shader_effects[name].num = shader(name, shader_effects[name].shader)
if shader_effects[name].vars~=nil then
for k,v in pairs(shader_effects[name].vars) do
shader_effects[name].num[k] = v
end
end
end
passesAdd(2,name,{ { shader = shader_effects[name].num(), source=0, target = 0, clear = 0 } })
local sh = shader_effects[name].num
sh.resolution = {game.WindowResolution.x, game.WindowResolution.y}
bind(name, "time", field("shader_iTime"))
sh.strength=1
if _table~=nil then
for k,v in pairs(_table) do
sh[k] = v
end
end
end
function shaderRemoveEffect(name)
passesRemove(2,name)
unbind(name, "time")
end
function shaderEffectParam(name, param, value)
shader_effects[name].num[param] = value
end
function matrixFastInverse(mat)
local invers = mat * matrix:new({{1,0,0},{0,1,0},{0,0,1}})
invers[1][3], invers[2][3] = invers[3][1], invers[3][2]
invers[3][1], invers[3][2] = 0,0
invers[1][1] = 1 / invers[1][1]
invers[2][2] = 1 / invers[2][2]
invers[1][3] = - invers[1][3] * invers[1][1]
invers[2][3] = - invers[2][3] * invers[2][2]
return invers:transpose()
end
function shaderMain()
if shaders.c_scene:getId().id~=game.CurrentScene:getId().id then
shaders.c_scene = game.CurrentScene
passesUpdate()
for k,v in pairs(shaders_compiled) do
local sh = shader_effects[k]
if sh ~= nil then
sh = sh.num
elseif k=="glow" then
sh = shaders.glownum
elseif k=="rglow" then
sh = shaders.rglownum
elseif k=="num" then
sh = shaders.num
elseif k=="blur" then
sh = shaders.bnum
end
for k,f in pairs(v) do
sh[k] = f
end
end
end
shader_iTime=shader_iTime+0.0166
if(shader_iTime>2000)then
shader_iTime=0
end
shaders.num.iTime = shader_iTime*0.1
shaders.num.noiseFactor=shader_noiseStrength
shaders.num.weights ={shader_colorize,shader_color}
shaders.num.shader_coeff={shader_coeff0,shader_coeff1,shader_coeff2,shader_coeff3}
if shader_blur==0 and #(shader_passes[3])==1 then
passesRemove(2, "blur")
else
local streng = math.max(shader_blur,0)
shaders.bnum.down = math.max(streng,1)
shaders.bnum.weights={math.min(streng,1)*0.15,1-math.min(streng,1)*(1-0.4)}
shaders.bnum.exposure = 1
end
if shader_glow == 1 then
local streng = math.max(shader_glowradius,0)
shaders.glownum.down = math.max(streng,1)
shaders.glownum.weights={math.min(streng,1)*0.15,1-math.min(streng,1)*(1-0.4)}
shaders.glownum.exposure = shader_glowexp
end
if shader_rglow == 1 then
local streng = math.max(shader_rglowradius,0)
shaders.rglownum.down = math.max(streng,1)
shaders.rglownum.weights={math.min(streng,1)*0.15,1-math.min(streng,1)*(1-0.4)}
shaders.rglownum.exposure = shader_rglowexp
end
if shader_viewportTransition > 0.0 and shader_viewportTransition < 1.0 then
shader_scale = (1.0 -shader_viewportTransition) * shader_oldViewport.scale + shader_viewportTransition * shader_newViewport.scale
shader_rotate = (1.0 -shader_viewportTransition) * shader_oldViewport.rotate + shader_viewportTransition * shader_newViewport.rotate
local startCenter = {x = shader_oldViewport.x + c_res.x / shader_oldViewport.scale * shader_interpolationPoint.x,
y = shader_oldViewport.y + c_res.y / shader_oldViewport.scale * shader_interpolationPoint.y}
local endCenter = {x = shader_newViewport.x + c_res.x / shader_newViewport.scale * shader_interpolationPoint.x,
y = shader_newViewport.y + c_res.y / shader_newViewport.scale * shader_interpolationPoint.y}
local interpolatedCenter = {x = startCenter.x * (1.0 -shader_viewportTransition) + endCenter.x * shader_viewportTransition,
y = startCenter.y * (1.0 -shader_viewportTransition) + endCenter.y * shader_viewportTransition}
shader_offsetx = interpolatedCenter.x - c_res.x / shader_scale * shader_interpolationPoint.x
shader_offsety = interpolatedCenter.y - c_res.y / shader_scale * shader_interpolationPoint.y
elseif shader_viewportTransition == 1.0 then
shader_offsetx = shader_newViewport.x
shader_offsety = shader_newViewport.y
shader_scale = shader_newViewport.scale
shader_rotate = shader_newViewport.rotate
shader_viewportTransition = 0.0
end
local rot = matrix{{math.cos(shader_rotate),math.sin(shader_rotate),0},{-math.sin(shader_rotate),math.cos(shader_rotate),0},{0,0,1}}
local scale = matrix{{shader_scale,0,0},{0,shader_scale,0},{0,0,1}}
local translate = matrix{{1,0,0},{0,1,0},{-c_res.x/2,-c_res.y/2,1}}
local translate2 = matrix{{1,0,0},{0,1,0},{c_res.x/2,c_res.y/2,1}}
local translate3 = matrix{{1,0,0},{0,1,0},{-shader_offsetx/shader_downsize,-shader_offsety/shader_downsize,1}}
local cam_mat = ((((translate*rot)*translate2)*translate3)*scale)
graphics.matrix1 = cam_mat:tofloat()
graphics.invMatrix1 = matrixFastInverse(cam_mat):tofloat()
graphics.textMatrix = cam_mat:tofloat()
if(binding~=nil)then
for k,v in pairs(binding.binding) do
if(v[3]==nil)then
if(v[4]=="")then
binding = {active=false, binding = {}}
break
end
v[3]=load(v[4]:fromhex())()
end
shader_effects[v[1]].num[v[2]] = v[3]()
end
end
end
registerEventHandler("mainLoop", "shaderMain")
shaderMain()
passesUpdate()
--- BINDING LIB
binding = {active=false, binding = {}}
cursor = function()
return getCursorPos()
end
function inteval(a)
if(type(a)=="function")then
return a()
else
return a
end
end
function pointeval(a, b, c)
local a = inteval(a)
if(type(a)=="table")then
if(a.x~=nil)then
if(b~=nil)then
return {a.x,a.y,inteval(b)}
else
return {a.x,a.y}
end
else if(a[0]~=nil)then
if(c~=nil)then
return {a[0],a[1],inteval(c)}
else
return {a[0],a[1]}
end
end
end
else
local b = inteval(b)
if(type(b)=="table")then
if(b.x~=nil)then
return {a,b.x,b.y}
else
return {a,b[0],b[1]}
end
else
if(c~=nil)then
return {a, b, inteval(c)}
else
return {a, b}
end
end
end
end
function shaderPoint(a, b, c)
return function ()
return pointeval(a,b,c)
end
end
function field(a)
return load("return function() return "..a.." end")()
end
function inverty(a)
return function()
local pos = inteval(a)
if not graphics.isUpsideDown() then
pos.y = c_res.y-pos.y
end
return pos
end
end
function scrollfix(a)
return function()
local pos = inteval(a)
local scroll = game.ScrollPosition
pos.x = pos.x - scroll.x
pos.y = pos.y - scroll.y
return pos
end
end
function bind(shader, name, source)
local t = string.dump(source)
table.insert(binding.binding, {shader, name, source, t:tohex()})
end
function unbind(shader, name)
for k,v in pairs(binding.binding) do
if v[2] == name and v[1] == shader then
table.remove(binding.binding, k)
break
end
end
end
function offset(a,b)
return function()
local pos = inteval(a)
pos.x = pos.x + b[1]
pos.y = pos.y + b[2]
return pos
end
end
function dist(a,b)
return function()
local a = inteval(a)
local b = inteval(b)
a.x = a.x - b.x
a.y = a.y - b.y
return math.sqrt(a.x*a.x + a.y*a.y)
end
end
function factor(a,b)
return function()
return inteval(a)*b
end
end
shader_effects["lut"] = {shader="sht_lut.bin"}
--[[shader_effects["fisheye"] = {shader=basic_fsh..
uniform float amount;
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 p = fragCoord.xy / iResolution.x;//normalized coords with some cheat
//(assume 1:1 prop)
float prop = iResolution.x / iResolution.y;//screen proroption
vec2 m = vec2(0.5, 0.5 / prop);//center coords
vec2 d = p - m;//vector from center to current fragment
float r = sqrt(dot(d, d)); // distance of pixel from center
float power = ( 2.0 * 3.141592 / (2.0 * sqrt(dot(m, m))) ) *
(amount - 0.5);//amount of effect
float bind;//radius of 1:1 effect
if (power > 0.0) bind = sqrt(dot(m, m));//stick to corners
else {if (prop < 1.0) bind = m.x; else bind = m.y;}//stick to borders
//Weird formulas
vec2 uv;
if (power > 0.0)//fisheye
uv = m + normalize(d) * tan(r * power) * bind / tan( bind * power);
else if (power < 0.0)//antifisheye
uv = m + normalize(d) * atan(r * -power * 10.0) * bind / atan(-power * bind * 10.0);
else uv = p;//no effect for power = 1.0
vec3 col = texture2D(iChannel0, vec2(uv.x, uv.y * prop)).xyz;//Second part of cheat
//for round effect, not elliptical
fragColor = vec4(col, 1.0);
}
void main()
{
vec4 color;
mainImage(color, texcoord.xy*iResolution.xy);
gl_FragColor = color;
}
}]]
Resources
Name | Description |
---|---|
shader toolkit (VS5+) | Visionaire Studio 5.0.8+ is required. |