Skip to content

Instantly share code, notes, and snippets.

@geekhunger
Last active August 29, 2015 14:06
Show Gist options
  • Save geekhunger/d19e20c53c20e63c8412 to your computer and use it in GitHub Desktop.
Save geekhunger/d19e20c53c20e63c8412 to your computer and use it in GitHub Desktop.
Simplified Painting App, made with Codea.
--# Color
-- modified version from https://github.com/EmmanuelOga/columns/blob/master/utils/color.lua
--[[
* Converts an RGB color value to HSL. Conversion formula
* adapted from http://en.wikipedia.org/wiki/HSL_color_space.
* Assumes r, g, and b are contained in the set [0, 255] and
* returns h, s, and l in the set [0, 1].
*
* @param Number r The red color value
* @param Number g The green color value
* @param Number b The blue color value
* @return Array The HSL representation
]]
function rgb2hsl(r, g, b)
r,g,b = r/255, g/255, b/255
local max, min = math.max(r,g,b), math.min(r,g,b)
local h, s, l = 0, 0, (max + min)/2 -- achromatic
if max ~= min then
local d = max - min
if l > .5 then s = d/(2 - max - min) else s = d/(max + min) end
if max == r then
h = (g - b)/d
if g < b then h = h + 6 end
elseif max == g then h = (b - r)/d + 2
elseif max == b then h = (r - g)/d + 4
end
h = h/6
end
return h,s,l
end
--[[
* Converts an HSL color value to RGB. Conversion formula
* adapted from http://en.wikipedia.org/wiki/HSL_color_space.
* Assumes h, s, and l are contained in the set [0, 1] and
* returns r, g, and b in the set [0, 255].
*
* @param Number h The hue
* @param Number s The saturation
* @param Number l The lightness
* @return Array The RGB representation
]]
function hsl2rgb(h, s, l)
local r,g,b = l,l,l -- achromatic
if s ~= 0 then
local function hue2rgb(p, q, t)
if t < 0 then t = t + 1 end
if t > 1 then t = t - 1 end
if t < 1/6 then return p + (q - p) * 6 * t end
if t < 1/2 then return q end
if t < 2/3 then return p + (q - p) * (2/3 - t) * 6 end
return p
end
local q = l < .5 and l*(1 + s) or l + s - l*s
local p = 2 * l - q
r = hue2rgb(p, q, h + 1/3)
g = hue2rgb(p, q, h)
b = hue2rgb(p, q, h - 1/3)
end
return r*255, g*255, b*255
end
--[[
* Converts an RGB color value to HSV. Conversion formula
* adapted from http://en.wikipedia.org/wiki/HSV_color_space.
* Assumes r, g, and b are contained in the set [0, 255] and
* returns h, s, and v in the set [0, 1].
*
* @param Number r The red color value
* @param Number g The green color value
* @param Number b The blue color value
* @return Array The HSV representation
]]
function rgb2hsv(r, g, b)
r, g, b = r / 255, g / 255, b / 255
local max, min = math.max(r, g, b), math.min(r, g, b)
local h, s, v = nil, nil, max
local d = max - min
if max == 0 then s = 0 else s = d / max end
if max == min then h = 0
else
if max == r then h = g < b and h + 6 or (g - b) / d
elseif max == g then h = (b - r) / d + 2
elseif max == b then h = (r - g) / d + 4 end
h = h / 6
end
return h, s, v
end
--[[
* Converts an HSV color value to RGB. Conversion formula
* adapted from http://en.wikipedia.org/wiki/HSV_color_space.
* Assumes h, s, and v are contained in the set [0, 1] and
* returns r, g, and b in the set [0, 255].
*
* @param Number h The hue
* @param Number s The saturation
* @param Number v The value
* @return Array The RGB representation
]]
function hsv2rgb(h, s, v)
local r, g, b
local i = math.floor(h * 6);
local f = h * 6 - i;
local p = v * (1 - s);
local q = v * (1 - f * s);
local t = v * (1 - (1 - f) * s);
i = i % 6
if i == 0 then r, g, b = v, t, p
elseif i == 1 then r, g, b = q, v, p
elseif i == 2 then r, g, b = p, v, t
elseif i == 3 then r, g, b = p, q, v
elseif i == 4 then r, g, b = t, p, v
elseif i == 5 then r, g, b = v, p, q
end
return r * 255, g * 255, b * 255
end
--# Main
Scale = .25 -- image quality settings (may affect speed also)
Canvas = readImage("Documents:Canvas")
if not Canvas then
supportedOrientations(CurrentOrientation, (CurrentOrientation~=3 and CurrentOrientation~=1) and CurrentOrientation+1 or CurrentOrientation-1)
Canvas = image(WIDTH * Scale, HEIGHT * Scale)
else
if Canvas.width < Canvas.height then
supportedOrientations(PORTRAIT_ANY)
else
supportedOrientations(LANDSCAPE_ANY)
end
end
function setup()
noSmooth()
displayMode(OVERLAY)
parameter.boolean("Mirror", false)
parameter.color("BG", loadstring(readLocalData("BG", "return color(221,219,199,255)"))(), function()
if BG.a < 255 then BG.a = 255 end
saveLocalData("BG", "return color"..tostring(BG))
end)
parameter.color("Color", loadstring(readLocalData("Color", "return color(41,151,176,255)"))(), function()
if Colorpicker then Colorpicker = false end
if Color.a > 0 then Color.a = 255 end
Schade = select(3, rgb2hsl(Color.r, Color.g, Color.b))
saveLocalData("Color", "return color"..tostring(Color))
end)
parameter.boolean("Colorpicker", false)
parameter.number("Schade", .001, .999, Schade, function()
if Colorpicker then Colorpicker = false end
local h, s, l = rgb2hsl(Color.r, Color.g, Color.b)
Color = color(hsl2rgb(h, s, Schade))
saveLocalData("Color", "return color"..tostring(Color)) -- fix because Color = color() doesn't trigger its prameter callback
end)
parameter.integer("Size", 1, 50, loadstring(readLocalData("Size", "return 2"))(), function()
saveLocalData("Size", "return "..tostring(Size))
end)
end
function orientationChanged()
if _allowFlipping then
local flipped = image(Canvas.width, Canvas.height)
setContext(flipped)
sprite(Canvas, WIDTH/2 * Scale, HEIGHT/2 * Scale, -Canvas.width, Canvas.height)
setContext()
Canvas = flipped
else
_allowFlipping = true
end
end
local function deviceShaking()
local acceleration = UserAcceleration
local intensity = 2 -- adjust min. shaking intensity to trigger this event!
if UserAcceleration.x > intensity or acceleration.y > intensity or acceleration.z > intensity then
_deviceShakingUpdatedAt = ElapsedTime
_deviceShakingBegunAt = _deviceShakingBegunAt or ElapsedTime
-- first shake triggers listening process
-- listen if shaking continues for [x] seconds then device is considered shaking on purpose
if (ElapsedTime - _deviceShakingBegunAt) >= .5 then return true end
end
if _deviceShakingUpdatedAt and (ElapsedTime > (_deviceShakingUpdatedAt + .5)) then
_deviceShakingUpdatedAt = nil
_deviceShakingBegunAt = nil
end
return false
end
function draw()
background(BG)
sprite(Canvas, WIDTH/2, HEIGHT/2, WIDTH, HEIGHT)
if Mirror then
stroke(127)
strokeWidth(1)
line(WIDTH/2, 0, WIDTH/2, HEIGHT)
end
if Touch then
local size = not Colorpicker and Size*2 or 50
local pos = not Colorpicker and vec2(Touch.x, Touch.y) or vec2(Touch.x, Touch.y + size)
fill(Color)
strokeWidth(1)
stroke(0)
ellipse(pos.x, pos.y, size + strokeWidth())
stroke(255)
ellipse(pos.x, pos.y, size)
end
if deviceShaking() then
saveLocalData("BG", "return color(221,219,199,255)")
saveLocalData("Color", "return color(41,151,176,255)")
saveLocalData("Size", "return 2")
saveImage("Documents:Canvas", nil)
restart()
end
end
function touched(touch)
if not Touch or Touch.id == touch.id then Touch = touch end
if Touch.state == BEGAN then tween.resetAll() end
if Touch.state == ENDED then
if Touch.id == touch.id then
Touch = nil
if Colorpicker then Colorpicker = false end
if _SaveCanvas then
tween.delay(.375, function() saveImage("Documents:Canvas", Canvas) end)
_SaveCanvas = nil
end
end
else
if not Colorpicker then
setContext(Canvas)
noFill()
strokeWidth(Size/2)
stroke(Color)
if Color.a == 0 then
stroke(0,0,0,255)
blendMode(ZERO, ONE_MINUS_SRC_ALPHA)
end
line(Touch.prevX * Scale, Touch.prevY * Scale, Touch.x * Scale, Touch.y * Scale, ROUND)
if Mirror then line((WIDTH - Touch.prevX) * Scale, Touch.prevY * Scale, (WIDTH - Touch.x) * Scale, Touch.y * Scale, ROUND) end
setContext()
blendMode(NORMAL)
_SaveCanvas = true
else
local col = color(Canvas:get(Touch.x * Scale, Touch.y * Scale))
if col == color(0,0,0,0) then col = BG end
if col.a < 255 then col = Color end
Color = col
Schade = select(3, rgb2hsl(Color.r, Color.g, Color.b))
saveLocalData("Color", "return color"..tostring(Color)) -- fix because Color = color() doesn't trigger its prameter callback
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment