Skip to content

Instantly share code, notes, and snippets.

@ggcrunchy
Last active November 19, 2015 21:18
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ggcrunchy/0232e2fd003e13d88077 to your computer and use it in GitHub Desktop.
Save ggcrunchy/0232e2fd003e13d88077 to your computer and use it in GitHub Desktop.
Heat haze example
--- Heat haze shader.
--
-- 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.
--
-- [ MIT license: http://www.opensource.org/licenses/mit-license.php ]
--
local kernel = {}
kernel.language = "glsl"
kernel.category = "filter"
-- By default, the group is "custom"
-- kernel.group = "custom"
kernel.name = "heat"
kernel.isTimeDependent = true
-- Expose effect parameters using vertex data
kernel.vertexData =
{
{
name = "extend", -- The property name exposed to Lua
default = 5,
min = .25,
max = 250,
index = 0, -- This corresponds to CoronaVertexUserData.x
},
{
name = "frequency", -- The property name exposed to Lua
default = 1.3,
min = .2,
max = 8,
index = 1, -- This corresponds to CoronaVertexUserData.y
},
{
name = "center", -- The property name exposed to Lua
default = display.contentCenterX,
min = 0,
max = display.contentWidth,
index = 2, -- This corresponds to CoronaVertexUserData.2
}
}
kernel.vertex = [[
varying P_UV vec2 extension_frac; // Custom varying variable (x = extension, y = fraction)
P_POSITION vec2 VertexKernel( P_POSITION vec2 position )
{
P_DEFAULT float offset = position.x - CoronaVertexUserData.z;
P_DEFAULT float extend = sign(offset) * CoronaVertexUserData.x;
extension_frac.x = .5 * extend / (offset + extend);
extension_frac.y = (offset + 2. * extend) / (offset + extend);
position.x += extend;
return position;
}
]]
kernel.fragment = [[
#ifdef GL_ES
precision mediump float;
#endif
varying P_UV vec2 extension_frac; // Custom varying variable (x = extension, y = fraction)
P_COLOR vec4 FragmentKernel( P_UV vec2 texCoord )
{
texCoord.x *= extension_frac.y;
texCoord.x -= extension_frac.x;
P_UV float amp = sin(2. * 3.14159 * (texCoord.y + CoronaTotalTime) * CoronaVertexUserData.y);
texCoord.x += amp * extension_frac.x;
if (abs(texCoord.x - .5) > .5) discard;
// P_UV float scale = ceil(.5 - abs(texCoord.x - .5)); // ... failed experiment to use alpha in lieu of discard
P_COLOR vec4 tcolor = texture2D( CoronaSampler0, texCoord );
// tcolor.a *= scale;
return CoronaColorScale(tcolor);
}
]]
return kernel
--- Non-discarding heat haze shader.
--
-- 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.
--
-- [ MIT license: http://www.opensource.org/licenses/mit-license.php ]
--
local kernel = {}
kernel.language = "glsl"
kernel.category = "filter"
-- By default, the group is "custom"
-- kernel.group = "custom"
kernel.name = "heat_no_discard"
kernel.isTimeDependent = true
-- Expose effect parameters using vertex data
kernel.vertexData =
{
{
name = "extend", -- The property name exposed to Lua
default = 5,
min = .25,
max = 250,
index = 0, -- This corresponds to CoronaVertexUserData.x
},
{
name = "frequency", -- The property name exposed to Lua
default = 1.3,
min = .2,
max = 8,
index = 1, -- This corresponds to CoronaVertexUserData.y
},
{
name = "center", -- The property name exposed to Lua
default = display.contentCenterX,
min = 0,
max = display.contentWidth,
index = 2, -- This corresponds to CoronaVertexUserData.2
}
}
kernel.vertex = [[
varying P_UV vec2 extension_frac; // Custom varying variable (x = extension, y = fraction)
P_POSITION vec2 VertexKernel( P_POSITION vec2 position )
{
P_DEFAULT float offset = position.x - CoronaVertexUserData.z;
P_DEFAULT float extend = sign(offset) * CoronaVertexUserData.x;
extension_frac.x = .5 * extend / (offset + extend);
extension_frac.y = (offset + 2. * extend) / (offset + extend);
position.x += extend;
return position;
}
]]
kernel.fragment = [[
#ifdef GL_ES
precision mediump float;
#endif
varying P_UV vec2 extension_frac; // Custom varying variable (x = extension, y = fraction)
P_COLOR vec4 FragmentKernel( P_UV vec2 texCoord )
{
texCoord.x *= extension_frac.y;
texCoord.x -= extension_frac.x;
P_UV float amp = sin(2. * 3.14159 * (texCoord.y + CoronaTotalTime) * CoronaVertexUserData.y);
texCoord.x += amp * extension_frac.x;
P_COLOR vec4 tcolor = texture2D( CoronaSampler0, texCoord );
return CoronaColorScale(tcolor);
}
]]
return kernel
--- Driver for shader demo.
--
-- 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.
--
-- [ MIT license: http://www.opensource.org/licenses/mit-license.php ]
--
-- Modules --
local utils = require("utils")
-- Setup
display.setStatusBar( display.HiddenStatusBar )
-- Log compiler errors found in shader code to console
display.setDefault( 'isShaderCompilerVerbose', true )
local cx, cy, CurrentGroup = display.contentCenterX, display.contentCenterY
-- Effect 1 --
local Normal = utils.LoadKernel("filter.custom.heat", function(group, name)
local image = display.newImageRect(group, "Image1.jpg", 256, 256)
image.x, image.y = cx, cy
image.fill.effect = name
-- Add some controls.
utils.SliderAndText(image, 10, "extend", .25, 250)
utils.SliderAndText(image, 40, "frequency", .2, 8)
end)
-- Effect 2 --
local Snapshot = utils.LoadKernel("filter.custom.heat", function(group, name)
local snap = display.newSnapshot(300, 300)
group:insert(snap)
snap.x, snap.y = cx, cy
-- Put some stuff in the snapshot.
local red = display.newRect(snap.group, 80 - cx, 90 - cy, 100, 200)
red:setFillColor(1, 0, 0)
local BlueY = 250 - cy
local blue = display.newRect(snap.group, 160 - cx, BlueY, 100, 200)
blue:setFillColor(0, 0, 1)
local green = display.newRect(snap.group, 140 - cx, 210 - cy, 200, 100)
green:setFillColor(0, 1, 0)
-- Add some controls.
snap.fill.effect = name
utils.SliderAndText(snap, 10, "extend", .25, 250)
utils.SliderAndText(snap, 40, "frequency", .2, 8)
-- Update the snapshot.
Runtime:addEventListener("enterFrame", function(event)
if group == CurrentGroup then
blue.y = BlueY + math.sin(event.time / 1050) * 25
snap:invalidate()
end
end)
end)
-- Effect 3 --
local NoDiscard = utils.LoadKernel("filter.custom.heat_no_discard", function(group, name)
local image = display.newImageRect(group, "Image1.jpg", 256, 256)
image.x, image.y = cx, cy
image.fill.effect = name
-- Add some controls.
utils.SliderAndText(image, 10, "extend", .25, 250)
utils.SliderAndText(image, 40, "frequency", .2, 8)
end)
-- Effect selection.
utils.TabBar{
{
name = "Normal",
func = function()
if CurrentGroup then -- handle first time
CurrentGroup.isVisible = false
end
CurrentGroup, Normal.isVisible = Normal, true
end
},
{
name = "Snapshot",
func = function()
CurrentGroup.isVisible = false
CurrentGroup, Snapshot.isVisible = Snapshot, true
end
},
{
name = "No Discard",
func = function()
CurrentGroup.isVisible = false
CurrentGroup, NoDiscard.isVisible = NoDiscard, true
end
}
}
--- Just some helper utilities for Corona shaders.
--
-- 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.
--
-- [ MIT license: http://www.opensource.org/licenses/mit-license.php ]
--
-- Corona modules --
local widget = require("widget")
-- Exports --
local M = {}
--- Helper to load kernels
function M.LoadKernel (effect_name, func)
local resolved = "kernel_" .. effect_name:gsub("%.", "_")
if not package.loaded[resolved] then
local kernel = require(resolved)
graphics.defineEffect(kernel)
end
local group = display.newGroup()
func(group, effect_name)
group.isVisible = false
return group
end
--
local function GetProp (effect, prefix, prop)
if prefix then
return effect[prefix][prop]
else
return effect[prop]
end
end
--
local function SetProp (effect, prefix, prop, v)
if prefix then
effect[prefix][prop] = v
else
effect[prop] = v
end
end
-- Make a slider with some text to its right
function M.SliderAndText (target, top, prop, min_value, max_value)
local group, dot, prefix = target.parent, prop:find("%.")
if dot then
prefix, prop = prop:sub(1, dot - 1), prop:sub(dot + 1)
end
local range = max_value - min_value -- see the shader file for these values
local slider = widget.newSlider{
top = top, left = 10,
orientation = "horizontal",
value = 100 * (GetProp(target.fill.effect, prefix, prop) - min_value) / range,
listener = function(event)
SetProp(target.fill.effect, prefix, prop, min_value + (event.value / 100) * range)
end
}
group:insert(slider)
local text = display.newText(group, prop, 0, slider.y, native.systemFont, 20)
text.anchorX, text.x = 0, slider.contentBounds.xMax + 10
end
--- Make a very basic tab bar
function M.TabBar (funcs)
local buttons = {}
for i, func in ipairs(funcs) do
buttons[#buttons + 1] = {
label = func.name,
selected = i == 1,
onPress = func.func
}
end
local tb = widget.newTabBar{
top = display.contentHeight - 26,
width = display.contentWidth,
buttons = buttons
}
funcs[1].func()
return tb
end
-- Install some theme.
widget.setTheme("widget_theme_ios")
-- Export the module.
return M
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment