Shader (CMS)

From The Official Visionaire Studio: Adventure Game Engine Wiki
Name Version Type By
Shader Toolkit 0.9.5 Definition SimonS

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. The script on here is likely 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.

Examples

Please see here for a list of working 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.95 
-- 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 
-- 
-- 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 
--]] 
 
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(loadstring(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 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("loadstring(%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 "loadstring()" 
        return string_format("loadstring(%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 
      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 
 
 
basic_vsh=[[#ifdef GL_ES 
precision lowp float;  
precision lowp int;  
#endif 
varying vec2 texcoord;  
uniform mat4 mvp_mat; 
attribute vec2 position;  
attribute vec2 uv; 
uniform int pass; 
void main ()  
{  
  gl_Position = mvp_mat * vec4(position.x,position.y,0.0,1.0);  
  texcoord = uv;  
}]] 
 
---------------------------- 
basic_fsh=[[#ifdef GL_ES 
precision highp float;  
precision lowp  int;  
#endif 
#define iChannel0 composite 
#define iResolution resolution 
#define iGlobalTime time 
#define iMouse mouse 
uniform float time; 
uniform sampler2D composite; 
uniform int pass; 
uniform vec2 mouse; 
uniform vec2 resolution; 
varying vec2 texcoord;]] 
 
---------------------------- 
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 
	if easing == nil then 
		easing = easeQuadInOut 
	end 
    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 
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.6) 
	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) 
    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) 
  if delay == 0 then return end 
--[[  if Scenes["sys_tpote"] ~= nil then 
    currentZoom = { zoomFactor = zoom, x = x, y = y, rotationFactor = rotation } 
    Scenes["sys_tpote"].SceneConditions["sys_checkIfZoomIsRunning"].ConditionValue = true 
    startAction( Scenes["sys_tpote"].SceneActions["checkIfZoomIsRunning"] ) 
  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) 
    if(shader_effects.light1.num==nil)then 
        shader_effects.light1.num = shader("light1", basic_vsh, shader_effects.light1.shader) 
    end 
    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, basic_vsh, 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 
                loadstring(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 table.getn(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 identity = matrix{{1,0,0},{0,1,0},{0,0,1}} 
    --shaders.num.cam_mat = 
    local cam_mat = ((((translate*rot)*translate2)*translate3)*scale)  
    graphics.matrix1 = cam_mat:tofloat() 
    graphics.invMatrix1 = matrixFastInverse(cam_mat):tofloat() 
 
    local cam_mat = (translate3*scale)  
    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]=loadstring(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 point(a, b, c) 
    return function () 
        return pointeval(a,b,c) 
    end 
end 
function field(a) 
    return loadstring("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 = DataDumper(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"}

Resources

Name Description
shader toolkit (VS5+) Visionaire Studio 5.0.8+ is required.