Skip to content

Instantly share code, notes, and snippets.

Created September 22, 2015 21:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anonymous/42e8b083a70bd36a1f2a to your computer and use it in GitHub Desktop.
Save anonymous/42e8b083a70bd36a1f2a to your computer and use it in GitHub Desktop.
Gists Codea Upload
--# 1_Intro_one_parameter
-- 1_Intro_one_parameter
function setup()
title = "blendMode tutorial"
code = "-------- \n(optimized for LANDSCAPE) \n---------"
info =
[[
blendMode(...) function can change the way colors are blended on the screen.
This project shows some examples of use of this function.
Each example is coded in an individual tab.
You can browse through the examples by:
- swiping left or right to go to next example
- sliding your finger up/down for faster browsing
You can copy the current example by pressing <copy code> button.
blendMode has several syntaxes.
The simplest takes 1 parameter, with 3 possible values:
blendMode(NORMAL)
blendMode(ADDITIVE)
blendMode(MULTIPLY)
Let's start with this syntax.
]]
textColor = color(255)
xt,yt = WIDTH/2, HEIGHT*9/10
xc,yc = WIDTH/2, HEIGHT*8/10
xi,yi = WIDTH/2, HEIGHT*4/10
end
function draw()
noStroke()
background(178, 178, 178, 255) textMode()
textWrapWidth(WIDTH*0.9)-- controls the wraping of long texts
fill(57, 57, 57, 255) -- set color for text
fontSize(35) -- set font size
text(title,xt,yt) -- draw text on screen
fontSize(25) -- set font size
textAlign(CENTER)
text(code,xc,yc)
textAlign(LEFT)
text(info,xi,yi)
end
--# D2_BlendMode_NORMAL
-- 2_BlendMode_NORMAL
function setup()
-- text
title = "2: Normal color blending"
code = "blendMode(NORMAL)"
info = "This is the default behavior. New colors mask previous ones. Each color is composed of 3 independent channels : red, green, blue (or: r,g,b) with values from 0 to 255. The default opacity is a=255 (fully opaque)."
textColor = color(255)
xt,yt = WIDTH/2, HEIGHT*9.5/10 -- position, computed from codea WIDTH and HEIGHT variables
xc,yc = WIDTH/2, HEIGHT*8.5/10
xi,yi = WIDTH/2, HEIGHT*1/10
-- cicles
d = WIDTH/3 -- diameter of cicles
-- circle 0
c0 = color(0,0,255) -- color
x0,y0 = WIDTH/2, HEIGHT*6/10 -- position
-- circle 1
c1 = color(255,0,0)
x1,y1 = WIDTH*4/10, HEIGHT*4/10
-- circle 2
c2 = color(0,255,0)
x2,y2 = WIDTH*6/10, HEIGHT*4/10
end
function draw()
background(30) -- erase last screen with white
-- ############ here is the blendmode setting #################################
blendMode(NORMAL) -- colors components mask colors below
-- ############ and now let's see the effect when drawing circles ############
noStroke() -- draw with no border
ellipseMode(CENTER) -- ellipse are defined by center and diameter
fill(c0) -- set circle 0 color...
ellipse(x0, y0, d) -- ... and draw it
fill(c1) -- set circle 1 color, etc...
ellipse(x1, y1, d)
fill(c2)
ellipse(x2, y2, d)
blendMode(NORMAL) -- let's go back to normal mode to draw the text
-- draw text
textWrapWidth(WIDTH*0.9)-- controls the wraping of long texts
fill(textColor) -- set color for text
fontSize(25) -- set font size
text(title,xt,yt) -- draw text on screen
text(code,xc,yc)
text(info,xi,yi)
end
--# D3_NORMAL_and_alpha
-- 3_NORMAL_and_alpha
function setup()
-- define some data
-- text
title = "3: normal color blending, with semi-opaque colors"
code = "blendMode(NORMAL)"
info = "Here the green circle is partly opaque (a=128). The resulting color is a/255*new + (1-a/255)*old for each color channel (red, green blue)"
textColor = color(255)
xt,yt = WIDTH/2, HEIGHT*9.5/10 -- position, computed from codea WIDTH and HEIGHT variables
xc,yc = WIDTH/2, HEIGHT*8.5/10
xi,yi = WIDTH/2, HEIGHT*1/10
-- cicles
d = WIDTH/3 -- diameter of cicles
-- circle 0
c0 = color(0,0,255) -- color
x0,y0 = WIDTH/2, HEIGHT*6/10 -- position
-- circle 1
c1 = color(255,0,0)
x1,y1 = WIDTH*4/10, HEIGHT*4/10
-- circle 2
a2 = 128
c2 = color(0,255,0,a2)
x2,y2 = WIDTH*6/10, HEIGHT*4/10
end
function draw()
background(30) -- erase last screen with white
-- ############ here is the blendmode setting #################################
blendMode(NORMAL) -- colors components mask colors below
-- ############ and now let's see the effect when drawing circles ############
noStroke() -- draw with no border
ellipseMode(CENTER) -- ellipse are defined by center and diameter
fill(c0) -- set circle 0 color...
ellipse(x0, y0, d) -- ... and draw it
fill(c1) -- set circle 1 color, etc...
ellipse(x1, y1, d)
fill(c2)
ellipse(x2, y2, d)
blendMode(NORMAL) -- let's go back to normal mode to draw the text
-- draw text
textWrapWidth(WIDTH*0.9)-- controls the wraping of long texts
fill(textColor) -- set color for text
fontSize(25) -- set font size
text(title,xt,yt) -- draw text on screen
text(code,xc,yc)
text(info,xi,yi)
end
--# D4_BlendMode_ADDITIVE
-- 4_BlendMode_ADDITIVE
function setup()
-- define some data
-- text
title = "4: additive color blending"
code = "blendMode(ADDITIVE)"
info = "Additive mode simulates light projected on a screen: colors add together, until saturation (white). Start with a black background to get better results."
textColor = color(255)
xt,yt = WIDTH/2, HEIGHT*9.5/10 -- position, computed from codea WIDTH and HEIGHT variables
xc,yc = WIDTH/2, HEIGHT*8.5/10
xi,yi = WIDTH/2, HEIGHT*1/10
-- cicles
d = WIDTH/3 -- diameter of cicles
-- circle 0
c0 = color(0,0,255) -- color
x0,y0 = WIDTH/2, HEIGHT*6/10 -- position
-- circle 1
c1 = color(255,0,0)
x1,y1 = WIDTH*4/10, HEIGHT*4/10
-- circle 2
c2 = color(0,255,0)
x2,y2 = WIDTH*6/10, HEIGHT*4/10
end
function draw()
background(0) -- erase last screen with white
-- ############ here is the blendmode setting #################################
blendMode(ADDITIVE) -- colors components will be added
-- ############ and now let's see the effect when drawing circles ############
noStroke() -- draw with no border
ellipseMode(CENTER) -- ellipse are defined by center and diameter
fill(c0) -- set circle 0 color...
ellipse(x0, y0, d) -- ... and draw it
fill(c1) -- set circle 1 color, etc...
ellipse(x1, y1, d)
fill(c2)
ellipse(x2, y2, d)
blendMode(NORMAL) -- let's go back to normal mode to draw the text
-- draw text
fill(textColor) -- set color for text
fontSize(25) -- set font size
text(title,xt,yt) -- draw text on screen
text(code,xc,yc)
text(info,xi,yi)
end
--# D5_ADDITIVE_and_alpha
-- 5_ADDITIVE_and_alpha
function setup()
-- define some data
-- text
title = "5: additive color blending"
code = "blendMode(ADDITIVE)"
info = "Here the green circle is partly opaque (a=128). Colors are mutiplied by a/255 before being added, so the overlapping parts are less saturated now."
textColor = color(255)
xt,yt = WIDTH/2, HEIGHT*9.5/10 -- position, computed from codea WIDTH and HEIGHT variables
xc,yc = WIDTH/2, HEIGHT*8.5/10
xi,yi = WIDTH/2, HEIGHT*1/10
-- cicles
d = WIDTH/3 -- diameter of cicles
-- circle 0
c0 = color(0,0,255) -- color
x0,y0 = WIDTH/2, HEIGHT*6/10 -- position
-- circle 1
c1 = color(255,0,0)
x1,y1 = WIDTH*4/10, HEIGHT*4/10
-- circle 2
a2 = 128
c2 = color(0,255,0,a2)
x2,y2 = WIDTH*6/10, HEIGHT*4/10
end
function draw()
background(0) -- erase last screen with white
-- ############ here is the blendmode setting #################################
blendMode(ADDITIVE) -- colors components will be added
-- ############ and now let's see the effect when drawing circles ############
noStroke() -- draw with no border
ellipseMode(CENTER) -- ellipse are defined by center and diameter
fill(c0) -- set circle 0 color...
ellipse(x0, y0, d) -- ... and draw it
fill(c1) -- set circle 1 color, etc...
ellipse(x1, y1, d)
fill(c2)
ellipse(x2, y2, d)
blendMode(NORMAL) -- let's go back to normal mode to draw the text
-- draw text
fill(textColor) -- set color for text
fontSize(25) -- set font size
text(title,xt,yt) -- draw text on screen
text(code,xc,yc)
text(info,xi,yi)
end
--# D6_BlendMode_MULTIPLY
-- 6_BlendMode_MULTIPLY
function setup()
-- define some data
-- text
title = "6: mutiplicative color blending"
code = "blendMode(MULTIPLY)"
info = "Multiplicative mode simulates subtractive color blending, like when you paint on paper with water colors. Start with a white background. The blend result is: new * old / 255 (for r,g,b), so red, green blue primaries blend to black."
textColor = color(0)
xt,yt = WIDTH/2, HEIGHT*9.5/10 -- position, computed from codea WIDTH and HEIGHT variables
xc,yc = WIDTH/2, HEIGHT*8.5/10
xi,yi = WIDTH/2, HEIGHT*1/10
-- cicles
d = WIDTH/3 -- diameter of cicles
-- circle 0
c0 = color(0,0,255) -- color
x0,y0 = WIDTH/2, HEIGHT*6/10 -- position
-- circle 1
c1 = color(255,0,0)
x1,y1 = WIDTH*4/10, HEIGHT*4/10
-- circle 2
a2 = 255
c2 = color(0,255,0,a2)
x2,y2 = WIDTH*6/10, HEIGHT*4/10
end
function draw()
background(255) -- erase last screen with white
-- ############ here is the blendmode setting #################################
blendMode(MULTIPLY) -- colors components will be mutiplied
-- ############ and now let's see the effect when drawing circles ############
noStroke() -- draw with no border
ellipseMode(CENTER) -- ellipse are defined by center and diameter
fill(c0) -- set circle 0 color...
ellipse(x0, y0, d) -- ... and draw it
fill(c1) -- set circle 1 color, etc...
ellipse(x1, y1, d)
fill(c2)
ellipse(x2, y2, d)
blendMode(NORMAL) -- let's go back to normal mode to draw the text
-- draw text
fill(textColor) -- set color for text
fontSize(25) -- set font size
text(title,xt,yt) -- draw text on screen
text(code,xc,yc)
text(info,xi,yi)
end
--# D7_MULTIPLY_primaries
-- 7_MULTIPLY_primaries
function setup()
-- define some data
-- text
title = "7: primary colors for MULTIPLY"
code = "blendMode(MULTIPLY)"
info = "You must use composed primary colors (yellow, cyan, magenta) to get interesting result from the mix. Mixing many colors will result in darker images, eventually black."
textColor = color(0)
xt,yt = WIDTH/2, HEIGHT*9.5/10 -- position, computed from codea WIDTH and HEIGHT variables
xc,yc = WIDTH/2, HEIGHT*8.5/10
xi,yi = WIDTH/2, HEIGHT*1/10
-- cicles
d = WIDTH/3 -- diameter of cicles
-- circle 0
c0 = color(0,255,255) -- color
x0,y0 = WIDTH/2, HEIGHT*6/10 -- position
-- circle 1
c1 = color(255,0,255)
x1,y1 = WIDTH*4/10, HEIGHT*4/10
-- circle 2
a2 = 255
c2 = color(255,255,0,a2)
x2,y2 = WIDTH*6/10, HEIGHT*4/10
end
function draw()
background(255) -- erase last screen with white
-- ############ here is the blendmode setting #################################
blendMode(MULTIPLY) -- colors components will be mutiplied
-- ############ and now let's see the effect when drawing circles ############
noStroke() -- draw with no border
ellipseMode(CENTER) -- ellipse are defined by center and diameter
fill(c0) -- set circle 0 color...
ellipse(x0, y0, d) -- ... and draw it
fill(c1) -- set circle 1 color, etc...
ellipse(x1, y1, d)
fill(c2)
ellipse(x2, y2, d)
blendMode(NORMAL) -- let's go back to normal mode to draw the text
-- draw text
fill(textColor) -- set color for text
fontSize(25) -- set font size
text(title,xt,yt) -- draw text on screen
text(code,xc,yc)
text(info,xi,yi)
end
--# D8_MULTIPLY_and_alpha
-- 8_MULTIPLY_and_alpha
function setup()
-- define some data
-- text
title = "8: mutiplicative color blending"
code = "blendMode(MULTIPLY)"
info = "Here the yellow circle is partly opaque (a=128). Colors are mutiplied by (1-a/255) before being multiplied to the on-screen color, so the overlapping parts are less attenuated now."
textColor = color(0)
xt,yt = WIDTH/2, HEIGHT*9.5/10 -- position, computed from codea WIDTH and HEIGHT variables
xc,yc = WIDTH/2, HEIGHT*8.5/10
xi,yi = WIDTH/2, HEIGHT*1/10
-- cicles
d = WIDTH/3 -- diameter of cicles
-- circle 0
c0 = color(0,255,255) -- color
x0,y0 = WIDTH/2, HEIGHT*6/10 -- position
-- circle 1
c1 = color(255,0,255)
x1,y1 = WIDTH*4/10, HEIGHT*4/10
-- circle 2
a2 = 128
c2 = color(255,255,0,a2)
x2,y2 = WIDTH*6/10, HEIGHT*4/10
end
function draw()
background(255) -- erase last screen with white
-- ############ here is the blendmode setting #################################
blendMode(MULTIPLY) -- colors components will be mutiplied
-- ############ and now let's see the effect when drawing circles ############
noStroke() -- draw with no border
ellipseMode(CENTER) -- ellipse are defined by center and diameter
fill(c0) -- set circle 0 color...
ellipse(x0, y0, d) -- ... and draw it
fill(c1) -- set circle 1 color, etc...
ellipse(x1, y1, d)
fill(c2)
ellipse(x2, y2, d)
blendMode(NORMAL) -- let's go back to normal mode to draw the text
-- draw text
fill(textColor) -- set color for text
fontSize(25) -- set font size
text(title,xt,yt) -- draw text on screen
text(code,xc,yc)
text(info,xi,yi)
end
--# 10_two_parameters
-- 10_two_parameters
function setup()
title = "10: blendMode( sf , df )"
code = "--------"
info =
[[
Now, let's see the 2 parameters syntax.
First some definitions:
SRC : source, the image to be added on the screen
DST : destination, the image already on the screen
OUT : output, final image
each color is defined by (r,g,b,a), hence the definitions:
SRC will mean indifferently r, g or b channels, and a_SRC if for alpha
same for DST, a_DST, OUT, a_OUT
Also note that r,g,b,a are represented by a number from 0 to 255 in codea,
but internally the value is divided by 255, so between 0.0 and 1.0
From now on i will use indifferently 255 or 1.0 to name the max value.
The blend formula are:
OUT = SRC * sf + DST * df
a_OUT = a_SRS * sf + a_DST * df
the result is clipped to [0.0, 1.0]
The possible values for sf and df are predefined codes:
ZERO | ONE | DST_COLOR | ONE_MINUS_DST_COLOR
SRC_ALPHA | ONE_MINUS_SRC_ALPHA | SRC_ALPHA_SATURATE
DST_ALPHA | ONE_MINUS_DST_ALPHA
Let's see some interesting choice for these parameters...
]]
textColor = color(255)
xt,yt = WIDTH/2, HEIGHT*9.5/10
xc,yc = WIDTH/2, HEIGHT*9/10
xi,yi = WIDTH/2, HEIGHT*4.5/10
end
function draw()
background(178, 178, 178, 255) textMode()
textWrapWidth(WIDTH*0.9)-- controls the wraping of long texts
fill(57, 57, 57, 255) -- set color for text
fontSize(35) -- set font size
text(title,xt,yt) -- draw text on screen
fontSize(20) -- set font size
text(code,xc,yc)
text(info,xi,yi)
end
--# D11_Punching_holes
-- 11_Punching_holes
function setup()
-- define some data
-- text
title = "11: punching holes in an image"
code = "blendMode( ZERO, ONE_MINUS_SRC_ALPHA ) \n\n OUT = SRC x 0 + DST x (1 - a_SRC)"
info = "With this mode you can punch a hole of any shape in an image. The opaque parts you draw will make the image transparent. Here i drew a white circle into the green circle, an 2 small ones in the red circle. Note the process is a bit more complex: you must prepare your images in advance with setContext()."
textColor = color(0)
xt,yt = WIDTH/2, HEIGHT*9.5/10 -- position, computed from codea WIDTH and HEIGHT variables
xc,yc = WIDTH/2, HEIGHT*8.5/10
xi,yi = WIDTH/2, HEIGHT*1/10
-- cicles
d = WIDTH/3 -- diameter of cicles
-- circle 0
c0 = color(0,0,255) -- color
x0,y0 = WIDTH/2, HEIGHT*6/10 -- position
-- circle 1
c1 = color(255,0,0)
x1,y1 = WIDTH*4/10, HEIGHT*4/10
-- circle 2
a2 = 255
c2 = color(0,255,0,a2)
x2,y2 = WIDTH*6/10, HEIGHT*4/10
-- to demonstrate punching holes, we need to make an image of circle2 and punch it in advance
-- it is not possible to punch just one image after it is drawn, so you must do it before.
circle2 = image(d,d) -- image of proper size
noStroke() -- draw with no border
setContext(circle2) -- let's draw into it
fill(c2)
ellipseMode(CENTER)
ellipse(d/2, d/2, d)
-- ############ here is the blendmode setting #################################
blendMode(ZERO, ONE_MINUS_SRC_ALPHA) --
-- ############ and now let's see the effect ############
fill(255)
ellipse(d/2, d/2, d/1.2)
blendMode(NORMAL)
setContext()
-- similar with circle1
circle1 = image(d,d) -- image of proper size
setContext(circle1) -- let's draw into it
fill(c1)
ellipse(d/2, d/2, d)
blendMode(ZERO, ONE_MINUS_SRC_ALPHA)
ellipseMode(CENTER)
fill(255)
ellipse(d*5/8, d*5/8, d/4)
ellipse(d/2, d*3/4, d/4)
blendMode(NORMAL)
setContext()
end
function draw()
background(255) -- erase last screen with white
blendMode(NORMAL)
noStroke() -- draw with no border
ellipseMode(CENTER) -- ellipse are defined by center and diameter
fill(c0) -- set circle 0 color...
ellipse(x0, y0, d) -- ... and draw it
spriteMode(CENTER)
sprite(circle1,x1, y1) -- circle 1 is in a previously made sprite now
sprite(circle2,x2, y2) -- circle 2 also
-- draw text
fill(textColor) -- set color for text
fontSize(25) -- set font size
text(title,xt,yt) -- draw text on screen
fontSize(20) -- set font size
textAlign(CENTER)
text(code,xc,yc)
textAlign(LEFT)
text(info,xi,yi)
end
--# D12_Inverting_colors
-- 12_Inverting_colors
function setup()
-- define some data
-- text
title = "12: inverting the colors"
code = "blendMode( ZERO, ONE_MINUS_SRC_COLOR )\n\n OUT = SRC x 0 + DST x (1-SRC)"
info = "The original colors were blue,red,green. Colors are inverted where the background is white, but elsewhere the blend in like MULTIPLY mode (subtractive blending). Not sure there is any use for that?"
textColor = color(0)
xt,yt = WIDTH/2, HEIGHT*9.5/10 -- position, computed from codea WIDTH and HEIGHT variables
xc,yc = WIDTH/2, HEIGHT*8.5/10
xi,yi = WIDTH/2, HEIGHT*1/10
-- cicles
d = WIDTH/3 -- diameter of cicles
-- circle 0
c0 = color(0,0,255) -- color
x0,y0 = WIDTH/2, HEIGHT*6/10 -- position
-- circle 1
c1 = color(255,0,0)
x1,y1 = WIDTH*4/10, HEIGHT*4/10
-- circle 2
a2 = 255
c2 = color(0,255,0,a2)
x2,y2 = WIDTH*6/10, HEIGHT*4/10
end
function draw()
background(255) -- erase last screen with white
blendMode(ZERO, ONE_MINUS_SRC_COLOR)
noStroke() -- draw with no border
ellipseMode(CENTER) -- ellipse are defined by center and diameter
fill(c0) -- set circle 0 color...
ellipse(x0, y0, d) -- ... and draw it
fill(c1) -- set circle 1 color, etc...
ellipse(x1, y1, d)
fill(c2)
ellipse(x2, y2, d)
blendMode(NORMAL)
-- draw text
fill(textColor) -- set color for text
fontSize(25) -- set font size
text(title,xt,yt) -- draw text on screen
fontSize(20) -- set font size
textAlign(CENTER)
text(code,xc,yc)
textAlign(LEFT)
text(info,xi,yi)
end
--# 15_Four_parameters
-- 15_Four_parameters
function setup()
title = "15: blendMode( sf , df , asf, adf)"
code = "--------"
info =
[[
Now, let's see the 4 parameters syntax.
This similar to the 2 parameters mode, except now you can control directly the alpha channel
The blend formula are:
OUT = SRC * sf + DST * df
a_OUT = a_SRS * asf + a_DST * adf
the result is clipped to [0.0, 1.0]
The possible values for sf and df are predefined codes (check CODEA documentation for a comprehensive list)
Let's see some interesting choices for these parameters...
]]
textColor = color(255)
xt,yt = WIDTH/2, HEIGHT*9/10
xc,yc = WIDTH/2, HEIGHT*8/10
xi,yi = WIDTH/2, HEIGHT*4.5/10
end
function draw()
background(178, 178, 178, 255) textMode()
textWrapWidth(WIDTH*0.9)-- controls the wraping of long texts
fill(57, 57, 57, 255) -- set color for text
fontSize(35) -- set font size
text(title,xt,yt) -- draw text on screen
fontSize(25) -- set font size
text(code,xc,yc)
text(info,xi,yi)
end
--# D16_Coying_transparency
-- 16_Coying_transparency
function setup()
-- define some data
-- text
title = "16: replacing the opacity of an image "
code =
[[blendMode( ZERO, ONE, ONE, ZERO )
OUT = SRC x 0 + DST x 1
a_OUT = a_SRC x 1 + a_DST x 0]]
info = "With this mode you can fully replace the alpha channel of destination image by the alpha channel of the source image. Here the green ring alpha has been copied to the red circle. Note that the result is not what we'd expect: the outside of the red ring is fully transparent, but the inside not. This is because the 3 images have been drawn in NORMAL mode, and the inside of the red circle is still red, it should be black to get perfect transparency"
textColor = color(0)
xt,yt = WIDTH/2, HEIGHT*9.5/10 -- position, computed from codea WIDTH and HEIGHT variables
xc,yc = WIDTH/2, HEIGHT*8.5/10
xi,yi = WIDTH/2, HEIGHT*1/10
-- cicles
d = WIDTH/3 -- diameter of cicles
-- circle 0
c0 = color(0,0,255) -- color
x0,y0 = WIDTH/2, HEIGHT*6/10 -- position
-- circle 1
c1 = color(255,0,0)
x1,y1 = WIDTH*4/10, HEIGHT*4/10
-- circle 2
a2 = 255
c2 = color(0,255,0,a2)
x2,y2 = WIDTH*6/10, HEIGHT*4/10
circle2 = image(d,d) -- image of proper size
noStroke() -- draw with no border
setContext(circle2) -- let's draw into it
ellipseMode(CENTER)
fill(c2)
ellipse(d/2, d/2, d)
blendMode(ZERO, ONE_MINUS_SRC_ALPHA)
fill(255)
ellipse(d/2, d/2, d/1.2)
blendMode(NORMAL)
setContext()
circle1 = image(d,d) -- image of proper size
setContext(circle1) -- let's draw into it
fill(c1)
ellipse(d/2, d/2, d)
-- ############ here is the blendmode setting #############
blendMode(ZERO, ONE, ONE, ZERO)
spriteMode(CORNER)
sprite(circle2,0,0) -- paste alpha channel
blendMode(NORMAL)
-- ############ and now let's see the effect ############
setContext()
end
function draw()
background(255) -- erase last screen with white
blendMode(NORMAL)
noStroke() -- draw with no border
ellipseMode(CENTER) -- ellipse are defined by center and diameter
fill(c0) -- set circle 0 color...
ellipse(x0, y0, d) -- ... and draw it
spriteMode(CENTER)
sprite(circle1,x1, y1) -- circle 1 is in a previously made sprite now
sprite(circle2,x2, y2) -- circle 2 also
-- draw text
fill(textColor) -- set color for text
fontSize(25) -- set font size
text(title,xt,yt) -- draw text on screen
fontSize(20) -- set font size
textAlign(CENTER)
text(code,xc,yc)
textAlign(LEFT)
text(info,xi,yi)
end
--# 17_Intro_workbench
-- 17_Intro_workbench
function setup()
title = "17: intro WORKBENCH"
code = "--------"
info =
[[
These examples are only a very few
of the possible combinations.
The next slide is not really a code tutorial
(the code is too complex), but it is a tool
that will let you try yourself any combination
of colors and modes, by sliding the boxes up/down.
You can copy the currently displayed blendmode
to paste it into your code by pressing the copy
button in the parameters panel.
Enjoy!
]]
textColor = color(255)
xt,yt = WIDTH/2, HEIGHT*9/10
xc,yc = WIDTH/2, HEIGHT*8/10
xi,yi = WIDTH/2, HEIGHT*4.5/10
end
function draw()
background(178, 178, 178, 255) textMode()
textWrapWidth(WIDTH*0.9)-- controls the wraping of long texts
fill(57, 57, 57, 255) -- set color for text
fontSize(35) -- set font size
text(title,xt,yt) -- draw text on screen
fontSize(25) -- set font size
text(code,xc,yc)
textAlign(CENTER)
text(info,xi,yi)
textAlign( LEFT)
end
--# Workbench
-- Workbench
function setup()
-- a background image
x0,y0 = WIDTH/2, HEIGHT/1.7-30
w0,h0 = WIDTH/2,WIDTH/2
sprite0 = grid()
-- blending
setBlender("blendMode 1 parameter")
-- cicles
x1,y1 = x0,y0
w1,h1 = math.floor(WIDTH/1.5),math.floor(WIDTH/1.5)
sprite1 = image(w1,h1)
r0,g0,b0,a0 = 255,0,0,255
r1,g1,b1,a1 = 0,255,0,255
-- a container for selectors
selectors = {}
-- boxes to view/set the colors
-- DST color
local w,h = WIDTH/8,HEIGHT/4.2-30
table.insert(selectors, colorSelector( "r0", 255, w*2, h) )
table.insert(selectors, colorSelector( "g0", 000, w*3, h) )
table.insert(selectors, colorSelector( "b0", 000, w*4, h) )
table.insert(selectors, colorSelector( "a0", 255, w*5, h) )
selectors[1].title = "DST = "
selectors[1].tdx = -100
-- SRC color
local w,h = w, h-35
table.insert(selectors, colorSelector( "r1", 000, w*2, h) )
table.insert(selectors, colorSelector( "g1", 255, w*3, h) )
table.insert(selectors, colorSelector( "b1", 000, w*4, h) )
table.insert(selectors, colorSelector( "a1", 255, w*5, h) )
selectors[5].title = "SRC = "
selectors[5].tdx = -100
-- resulting color
local w,y,y1 = WIDTH/16,HEIGHT/4.2-55-30,HEIGHT/4.2+50-30
outputValue = {
{x=w*5, y=y, txt="0"},
{x=w*7, y=y, txt="0"},
{x=w*9, y=y, txt="0"},
{x=w*11, y=y, txt="0"},
{x=w*3-17, y=y, txt="OUT ="},
{x=w*5, y=y1, txt="R"},
{x=w*7, y=y1, txt="G"},
{x=w*9, y=y1, txt="B"},
{x=w*11, y=y1, txt="A"},
}
-- the mode syntax selector
local s = Selector({
list = {"blendMode 1 parameter","blendMode 2 parameters","blendMode 4 parameters"},
x=WIDTH/4, y=HEIGHT-70, w=math.floor(WIDTH/2), h=30, strokeWidth=1, cur=1,
callback = function(i,v)
setBlender(v)
updateSprite1()
end
})
s:setValue(value)
table.insert(selectors, s )
-- update the blending from all these data
updateSprite1()
end
function touched(t)
for i,s in ipairs(selectors) do if s:touched(t) then return true end end
for i,s in ipairs(blend.selectors) do if s:touched(t) then return true end end
end
function draw()
background(240) -- erase last screen with white
blendMode(NORMAL)
spriteMode(CENTER)
noSmooth()
sprite(sprite0, x0,y0,w0,h0)
sprite(sprite1, x1,y1,w1,h1)
for i,s in ipairs(selectors) do s:draw() end
blend:draw()
textMode(CENTER)
fill(0)
fontSize(25)
for i,s in ipairs(outputValue) do text(s.txt,s.x,s.y) end
end
function ColorBar(str,value,x,y)
local bar = {}
return bar
end
function colorSelector(str,value,x,y)
local s = Selector({
list = {0,32,64,92,128,160,192,224,255},
x=x, y=y, w=90, h=30, strokeWidth=1,
callback = function(i,v)
_G[str] = v
updateSprite1()
end
})
s:setValue(value)
return s
end
function setBlender(str)
if str == "blendMode 1 parameter" then blend = Blend1() end
if str == "blendMode 2 parameters" then blend = Blend2() end
if str == "blendMode 4 parameters" then blend = Blend4() end
end
function Blend1()
local b = {}
local choices = {NORMAL, ADDITIVE, MULTIPLY}
local list = {[NORMAL]="NORMAL", [ADDITIVE]="ADDITIVE", [MULTIPLY]="MULTIPLY"}
b.mode = NORMAL
b.selectors = {}
local x,y,w,h = WIDTH/2-75, HEIGHT-110, 150, 30
local s = Selector({
list = {"NORMAL","ADDITIVE","MULTIPLY"},
x=x, y=y, w=w, h=h, strokeWidth=1,
callback = function(i,v)
b.mode = choices[i]
updateSprite1()
end
})
s:setCur(1)
b.selectors[1] = s
b.tostring = function(self)
local txt = "blendmode( "..list[self.mode].." )"
return txt
end
b.draw = function(self)
fontSize(35)
fill(0)
for i,s in ipairs(self.selectors) do s:draw() end
end
b.setMode = function()
blendMode(b.mode)
end
return b
end
local choices1 = {
"ONE","ZERO",
"DST_COLOR","ONE_MINUS_DST_COLOR",
"SRC_ALPHA","ONE_MINUS_SRC_ALPHA",
"DST_ALPHA","ONE_MINUS_DST_ALPHA",
"SRC_ALPHA_SATURATE",
["ZERO"]=ZERO, ["ONE"]=ONE,
["DST_COLOR"]=DST_COLOR, ["ONE_MINUS_DST_COLOR"]=ONE_MINUS_DST_COLOR,
["SRC_ALPHA"]=SRC_ALPHA, ["ONE_MINUS_SRC_ALPHA"]=ONE_MINUS_SRC_ALPHA,
["DST_ALPHA"]=DST_ALPHA, ["ONE_MINUS_DST_ALPHA"]=ONE_MINUS_DST_ALPHA,
["SRC_ALPHA_SATURATE"]=SRC_ALPHA_SATURATE,
}
local choices2 = {
"ONE","ZERO",
"SRC_COLOR","ONE_MINUS_SRC_COLOR",
"SRC_ALPHA","ONE_MINUS_SRC_ALPHA",
"DST_ALPHA","ONE_MINUS_DST_ALPHA",
["ZERO"]=ZERO, ["ONE"]=ONE,
["SRC_COLOR"]=SRC_COLOR, ["ONE_MINUS_SRC_COLOR"]=ONE_MINUS_SRC_COLOR,
["SRC_ALPHA"]=SRC_ALPHA, ["ONE_MINUS_SRC_ALPHA"]=ONE_MINUS_SRC_ALPHA,
["DST_ALPHA"]=DST_ALPHA, ["ONE_MINUS_DST_ALPHA"]=ONE_MINUS_DST_ALPHA,
}
local mNames = {
[ONE]="ONE",[ZERO]="ZERO",
[DST_COLOR]="DST_COLOR",[ONE_MINUS_DST_COLOR]="ONE_MINUS_DST_COLOR",
[SRC_COLOR]="SRC_COLOR", [ONE_MINUS_SRC_COLOR]="ONE_MINUS_SRC_COLOR",
[SRC_ALPHA]="SRC_ALPHA",[ONE_MINUS_SRC_ALPHA]="ONE_MINUS_SRC_ALPHA",
[DST_ALPHA]="DST_ALPHA",[ONE_MINUS_DST_ALPHA]="ONE_MINUS_DST_ALPHA",
[SRC_ALPHA_SATURATE]="SRC_ALPHA_SATURATE",
}
function Blend2()
local b = {}
b.c1 = ONE
b.c2 = ONE
b.selectors = {}
local x,y,w,h,fs = WIDTH/2, HEIGHT-130, math.floor(WIDTH/4-10), 25,13
b.selectors[1] = Selector({ list = choices1, x=x-w-5, y=y, w=w, h=h, strokeWidth=1, fontSize=fs,
title = "SRC color x", tdy = 30, tdx=50, titleFontSize=15,
callback = function(i,v)
b.c1 = choices1[v]
updateSprite1()
end
})
b.selectors[2] = Selector({ list = choices2, x=x+5, y=y, w=w, h=h, strokeWidth=1, fontSize=fs,
title = "+ DST color x", tdy = 30, tdx=-10, titleFontSize=15,
callback = function(i,v)
b.c2 = choices2[v]
updateSprite1()
end
})
b.tostring = function(self)
local txt = "blendmode( "..mNames[self.c1].." , "..mNames[self.c2].." )"
return txt
end
b.draw = function(self)
fontSize(35)
fill(0)
for i,s in ipairs(self.selectors) do s:draw() end
end
b.setMode = function()
blendMode( b.c1, b.c2 )
end
return b
end
function Blend4()
local b = {}
b.c1 = ONE
b.c2 = ONE
b.c3 = ONE
b.c4 = ONE
b.selectors = {}
local x,y,w,h,fs = WIDTH/2, HEIGHT-130, math.floor(WIDTH/4-10), 25,13
b.selectors[1] = Selector({ list = choices1, x=x-2*w-15, y=y, w=w, h=h, strokeWidth=1, fontSize=fs,
title = "SRC color x", tdy = 30, tdx=50, titleFontSize=15,
callback = function(i,v)
b.c1 = choices1[v]
updateSprite1()
end
})
b.selectors[2] = Selector({ list = choices2, x=x-w-5, y=y, w=w, h=h, strokeWidth=1, fontSize=fs,
title = "+ DST color x", tdy = 30, tdx=-10, titleFontSize=15,
callback = function(i,v)
b.c2 = choices2[v]
updateSprite1()
end
})
b.selectors[3] = Selector({ list = choices1, x=x+5, y=y, w=w, h=h, strokeWidth=1, fontSize=fs,
title = "SRC alpha x", tdy = 30, tdx=50, titleFontSize=15,
callback = function(i,v)
b.c3 = choices1[v]
updateSprite1()
end
})
b.selectors[4] = Selector({ list = choices2, x=x+5+w, y=y, w=w, h=h, strokeWidth=1, fontSize=fs,
title = "+ DST alpha x", tdy = 30, tdx=-10, titleFontSize=15,
callback = function(i,v)
b.c4 = choices2[v]
updateSprite1()
end
})
b.tostring = function(self)
local txt = "blendmode( "..mNames[self.c1].." , "..mNames[self.c2].." , "..
mNames[self.c3].." , "..mNames[self.c4].." )"
return txt
end
b.draw = function(self)
fontSize(35)
fill(0)
for i,s in ipairs(self.selectors) do s:draw() end
end
b.setMode = function()
blendMode( b.c1, b.c2, b.c3, b.c4 )
end
return b
end
function octet(v)
return string.format( " %3.3d", tostring(v))
end
function updateSprite1()
local w,h = sprite1.width, sprite1.height
local d = w *2/3 -- diameter of cicles
-- circle 0
local x0,y0 = w/3, h/2 -- position
-- circle 1
local x1,y1 = w*2/3, h/2
setContext(sprite1)
blendMode(NORMAL)
background(0,0)
stroke(0)
strokeWidth(10)
fill( r0,g0,b0,a0 )
ellipseMode(CENTER)
ellipse(x0,y0,d)
blend.setMode()
fill( r1,g1,b1,a1 )
ellipse(x1,y1,d)
setContext()
local r2,g2,b2,a2 = sprite1:get(math.floor(w/2),math.floor(h/2))
outputValue[1].txt = tostring(r2)
outputValue[2].txt = tostring(g2)
outputValue[3].txt = tostring(b2)
outputValue[4].txt = tostring(a2)
end
-- this is a diagonal grid to visualize transparency
function grid()
local w = 20
local img = image(w,w)
setContext(img)
noSmooth()
background(0)
strokeWidth(0.5)
stroke(128)
for i=1,w/2 do
line(0,i*2,i*2,0)
line(i*2, w, w, i*2)
end
setContext()
return img
end
--# Credits
function setup()
title = "THE END"
code = "--------"
info =
[[
Well that's all for now.
--------
CREDITS:
this tuto was cooked up by: JMV38
Overhauling Manager: Ignatz
]]
textColor = color(255)
xt,yt = WIDTH/2, HEIGHT*9/10
xc,yc = WIDTH/2, HEIGHT*8/10
xi,yi = WIDTH/2, HEIGHT*4.5/10
end
function draw()
background(178, 178, 178, 255) textMode()
textWrapWidth(WIDTH*0.9)-- controls the wraping of long texts
fill(57, 57, 57, 255) -- set color for text
fontSize(35) -- set font size
text(title,xt,yt) -- draw text on screen
fontSize(25) -- set font size
text(code,xc,yc)
textAlign(CENTER)
text(info,xi,yi)
textAlign( LEFT)
end
--# Main
-- Main
-- This part is not part of the tutorial, it is managing the transitions
-- => the code is not commented
function setup()
supportedOrientations(LANDSCAPE_LEFT)
-- the demo tabs
demo = listProjectTabs()
-- remove the last tabs starting at Main tab
local thisIsNoDemoTab = false
for i = 1,#demo do
if demo[i] == "Main" then thisIsNoDemoTab = true end
if thisIsNoDemoTab then demo[#demo] = nil end
end
print("Swipe left/right to go to next demo tab")
print("Or use the top right selector to jump quickly to a demo tab")
-- I use 2 images to make the transition between demos smoother, and for the workbench
img1 = image(WIDTH,HEIGHT)
img2 = image(WIDTH,HEIGHT)
position = {dx1=0,dx2=WIDTH} -- a table to keep the image position
message = "" -- some text to display
touchable = true -- flag to disable touch during transitions
-- a quick browsing slider
slider = Slider({list=demo, x=WIDTH-160, y=HEIGHT-200, w=300, h=40, fontSize=20,
callback = function(i,tab) setTab(i) end})
-- let's start by running the first tab of the list
setTab(1)
-- a screen swipe sensor
screen = {x=0,y=0,w=WIDTH,h=HEIGHT}
screen.sensor = Sensor {parent=screen}
screen.sensor:onSwipe(function(event)
if event.dx < 0 and current<#demo then setTab(current + 1) end
if event.dx > 0 and current>1 then setTab(current - 1) end
end)
end
function setTab(i)
if not current then current = i currentTab = demo[i] end
runTab(i)()
current = i
currentTab = demo[i]
slider:setCur(i)
copyButtonMenu()
end
function copyButtonMenu()
-- clear
parameter.clear()
-- if this is not a demo tab, no copy button
if currentTab:sub(1,1) == "D" then
-- a <copy> button so you can quickly get the tab code
parameter.action("copy code",function()
pasteboard.text = readProjectTab(currentTab)
print(currentTab .. " has been copied. You can now paste it into another project.")
end )
end
if currentTab == "Workbench" then
-- a <copy> button so you can quickly get the blendmode
parameter.action("copy blendmode",function()
pasteboard.text = blend:tostring()
print(pasteboard.text)
end )
end
end
function mainDraw()
background(0)
drawDemo()
drawMessage()
slider:draw()
end
function runTab(i)
local callback = function()
-- get tab content
local name = demo[i]
local tab = readProjectTab(name)
-- execute it (calling setup is necessary to setup new values)
draw = function() end
touched = function() end
loadstring(tab)()
drawDemo = draw
touchedDemo = touched
setup()
-- draw once into an image, and then re-activate the main draw function
img2 = draw_into_image()
-- this is to make a nice transition between demo tabs
animateTransition(i)
end
return callback
end
function animateTransition(new)
local direction = compare(current,new)
position.dx1= 0
position.dx2= WIDTH * direction
touchable = false
draw = transitionDraw
tween(1, position, {dx1= -WIDTH * direction ,dx2=0}, tween.easing.cubicInOut)
tween.delay(1,function()
position.dx1=0
position.dx2=WIDTH
img1 = img2
collectgarbage()
touchable = true
draw = mainDraw
touched = mainTouched
end)
currentTab = name
end
function transitionDraw()
-- during transition, 2 fixed images are moved on the screen (no live update)
background(0)
spriteMode(CORNER)
sprite(img1, position.dx1, 0) -- this image is the main one
sprite(img2, position.dx2, 0) -- this one is used for transition effects
end
function compare(v1,v2)
if v1 < v2 then return 1.0 end
if v1 == v2 then return 0.0 end
if v1 > v2 then return -1.0 end
end
function mainTouched(t)
if slider:touched(t) then return true end
if touchedDemo(t) then return true end
if screen.sensor:touched(t) then return true end
end
function drawMessage()
if message == "" then return end
fill(128)
rectMode(CENTER)
local x,y = CurrentTouch.x-150,CurrentTouch.y
rect(x,y,200,50)
fill(255)
fontSize(25)
text(message,x,y)
end
function draw_into_image()
local img = image(WIDTH,HEIGHT)
setContext(img)
draw()
setContext()
return img
end
--# Sensor
-- Sensor
-- a class to interpret touch events
-- usage:
--[[
-- in setup():
screen = {x=0,y=0,w=WIDTH,h=HEIGHT}
sensor = Sensor {parent=screen} -- tell the object you want to be listening to touches, here the screen
sensor:onTap( function(event) print("tap") end )
-- in touched(t):
if sensor:touched(t) then return true end
-- available:
sensor:onDrag(callback)
sensor:onTap(callback)
sensor:onLongPress(callback)
sensor:onSwipe(callback)
--]]
Sensor = class()
function Sensor:init(t)
self.enabled = true -- listen to touches
self.extra = t.extra or self.extra or 0 -- for fat fingers
self.touches = {}
self:setParent(t)
self.events = {}
end
function Sensor:setParent(t)
-- a parent must have x,y,w,h coordinates (CORNER) to use the sensor
local p = t.parent or self.parent
if p.x and p.y and p.w and p.h then
self.parent = p
else
error("Sensor parent must have x,y,w,h coordinates")
end
-- the coordinates may be in different modes, use the appropriate function
self.xywhMode = t.xywhMode or self.xywhMode or CORNER
if self.xywhMode == CENTER then self.xywh = self.xywhCENTER
elseif self.xywhMode == CORNER then self.xywh = self.xywhCORNER
elseif self.xywhMode == RADIUS then self.xywh = self.xywhRADIUS
end
end
local abs = math.abs
-- all gestures register themselves with this function
function Sensor:register(eventName, update, callback)
table.insert(self.events, {name=eventName, callback=callback, update=update})
end
-- gestures defined below. Note the that, because gestures are managed individually, the
-- code is much more clear than when everything is mixed up
-- drag gesture
function Sensor:onDrag(callback)
self:register("onDrag", self.dragUpdate, callback)
end
function Sensor.dragUpdate(event,self,t)
if self.touches[t.id] then -- the touch must have started on me
-- manage MOVING and ENDED states in the callback
event.touch = t
event:callback()
end
end
-- tap gesture
function Sensor:onTap(callback)
self:register("onTap", self.tapUpdate, callback)
end
function Sensor.tapUpdate(event,self,t)
if self.touches[t.id] then -- the touch must have started on me
if t.state == BEGAN then
event.totalMove = 0
event.t0 = ElapsedTime
elseif t.state == MOVING then
-- integrate finger movement
event.totalMove = event.totalMove + abs(t.deltaX) + abs(t.deltaY)
elseif t.state == ENDED
and event.totalMove < 10 -- the finger should not have moved too much ...
and (ElapsedTime-event.t0) < 0.5 then -- and delay should not be too long
event:callback()
end
end
end
-- long press gesture
function Sensor:onLongPress(callback)
self:register("onLongPress", self.longPressUpdate, callback)
end
function Sensor.longPressUpdate(event,self,t)
local tmin = 1
if self.touches[t.id] then -- the touch must have started on me
if t.state == BEGAN then
event.totalMove = 0
event.cancel = false
event.id = t.id
event.tween = tween.delay(tmin,function()
event.tween = nil
if event.totalMove > 10 or event.id ~= t.id then event.cancel = true end
if event.cancel then return end
event:callback()
end)
elseif t.state == MOVING and event.id == t.id then
-- integrate finger movement
event.totalMove = event.totalMove + abs(t.deltaX) + abs(t.deltaY)
elseif (t.state == ENDED or t.state == CANCELLED) and event.id == t.id then
event.cancel = true
if event.tween then tween.stop(event.tween) end
end
end
end
-- swipe gesture
function Sensor:onSwipe(callback)
self:register("onSwipe", self.swipeUpdate, callback)
end
function Sensor.swipeUpdate(event,self,t)
if self.touches[t.id] then -- the touch must have started on me
if t.state == BEGAN then
event.dx = 0
event.dy = 0
event.t0 = ElapsedTime
elseif t.state == MOVING then
-- track net finger movement
event.dx = event.dx + t.deltaX
event.dy = event.dy + t.deltaY
elseif t.state == ENDED
and (ElapsedTime-event.t0) < 1 then -- delay should not be too long
-- and the finger should have moved enough:
local minMove = 70
if abs(event.dx) < minMove then event.dx = 0 end
if abs(event.dy) < minMove then event.dy = 0 end
if event.dx ~= 0 or event.dy ~= 0 then
event:callback() -- use event.dx and .dy to know the swipe direction
end
end
end
end
function Sensor:touched(t)
if not self.enabled then return end
if t.state == BEGAN and self:inbox(t) then
self.touches[t.id] = true
end
for i,event in ipairs(self.events) do
event:update(self,t) -- only registered events are computed
end
local intercepted = self.touches[t.id]
if t.state == ENDED or t.state == CANCELLED then
self.touches[t.id] = nil
end
-- return true when touched (or concerned)
return intercepted
end
-- functions to get x, y, w, h in different coordinates systems
function Sensor:xywhCORNER()
local p = self.parent
local wr, hr = p.w/2.0, p.h/2.0
local xr, yr = p.x + wr, p.y + hr
return xr,yr,wr,hr
end
function Sensor:xywhCENTER()
local p = self.parent
return p.x, p.y, p.w/2, p.h/2
end
function Sensor:xywhRADIUS()
local p = self.parent
return p.x, p.y, p.w, p.h
end
-- check if the box is touched
function Sensor:inbox(t)
local x,y,w,h = self:xywh()
return abs(t.x-x)<(w+self.extra) and abs(t.y-y)<(h+self.extra)
end
--# Selector
-- A class to make a selection from a list of values
Selector = class()
function Selector:init(data)
data = data or {}
self.list = data.list or self.list or {"a","b","c"}
self.cur = data.cur or self.cur or 1 -- currently selected index
self.title = data.title or self.title
self.tdx = data.tdx or self.tdx or -30
self.tdy = data.tdy or self.tdy or 0
self.h = data.h or self.h or 50
self.w = data.w or self.w or 200
self.x = data.x or self.x or 300
self.y = data.y or self.y or 300
self.fontSize = data.fontSize or self.fontSize or self.h * 0.8
self.titleFontSize = data.titleFontSize or self.titleFontSize or self.fontSize
self.bkg = data.bkg or self.bkg or color(230)
self.frg = data.frg or self.frg or color(0)
self.stroke = data.stroke or self.stroke or color(100)
self.strokeWidth = data.strokeWidth or self.strokeWidth or 5
-- callback is called with 2 arguments: callback( current index , current list value )
self.callback = data.callback or self.callback or function(v) print(v) end
-- prepare the image for drawing
self.img = self:makeImage()
self.dy = self:update_dy()
self.visible = true
-- for touch management
self.wr = self.w / 2
self.hr = self.h / 2
self.xr = self.x + self.wr
self.yr = self.y + self.hr
self.sensor = Sensor{parent=self}
self.sensor:onDrag( function(event) self:drag(event.touch) end )
self.sensor.enabled = (#self.list~=1) -- if 1 option only, this is just a text box
end
function Selector:update_dy()
-- update the image shift from current index value
self.dy = (self.cur-1) * self.h
return self.dy
end
function Selector:update_cur()
-- update current index from dy value
self.cur = math.floor(self.dy/self.h+1.5)
if self.cur < 1 then self.cur =1 end
if self.cur > #self.list then self.cur =#self.list end
end
function Selector:setCur(v)
self.cur = v
if self.cur < 1 then self.cur =1 end
if self.cur > #self.list then self.cur =#self.list end
self:update_dy()
end
function Selector:setValue(target)
for i,v in ipairs(self.list) do
if v == target then
self:setCur(i)
end
end
end
function Selector:makeImage()
-- an image with all values
self.htot = self.h * (#self.list)
self.dyMax = self.htot - self.h
local img = image(self.w, self.htot)
local x,y = self.w/2
setContext(img)
do
background( self.bkg )
fill(self.frg)
fontSize(self.fontSize)
textMode(CENTER)
for i,v in ipairs(self.list) do
y = self.h * (i-0.5)
text( tostring(v) , x,y)
end
end
setContext()
return img
end
function Selector:draw()
if not self.visible then return end
-- draw the current value
spriteMode(CORNER)
clip(self.x,self.y,self.w,self.h)
sprite(self.img, self.x, self.y-self.dy)
clip()
-- add some decoration
stroke(self.stroke)
strokeWidth(self.strokeWidth)
fill(0,0)
rectMode(CORNER)
rect(self.x-1,self.y-1,self.w+2,self.h+2)
-- and the title
if self.title then
fontSize(self.titleFontSize)
fill(self.frg)
textMode(CORNER)
text(self.title,self.x+self.tdx, self.y+self.tdy)
end
end
function Selector:touched(t)
self.sensor:touched(t)
end
function Selector:drag(t)
if t.state == MOVING then
-- drag the image
self.dy = self.dy - t.deltaY
if self.dy < 0 then self.dy =0 end
if self.dy > self.dyMax then self.dy =self.dyMax end
elseif t.state == ENDED then
-- when finger released, finalize the value
self:update_cur()
self:update_dy()
self.callback( self.cur , self.list[ self.cur ] )
end
end
--# Dot
Dot = class()
-- just a dot object
function Dot:init(t)
self.x = t.x or WIDTH/2
self.y = t.y or HEIGHT/2
self.r = t.r or 50
self.w = self.r
self.h = self.r
end
function Dot:draw()
stroke(0)
strokeWidth(2)
fill(200)
ellipseMode(RADIUS)
ellipse(self.x,self.y,self.r)
end
function Dot:touched(touch)
end
--# Slider
Slider = class()
function Slider:init(data)
-- slider geometry
self.x0 = WIDTH - 20
self.x1 = self.x0
self.y0 = HEIGHT*0.7
self.y1 = HEIGHT*0.1
self.dy = 0
self.dyMax = self.y0-self.y1
-- manage and view the demo tabs
self.selector = Selector(data)
self.ratio = (self.y0-self.y1)/(self.selector.h * (#self.selector.list-1))
self.selector.x = self.x0 - self.selector.w - 50
self.selector.y = self.y0 - self.selector.h/2
self.selector.visible = false
-- a draggable dot to move the slider
self.dot = Dot{ x=self.x0, y=self.y0+self.dy, r=16}
self.dotSensor = Sensor{ parent=self.dot, xywhMode=RADIUS, extra=10}
self.dotSensor:onDrag( function(event) self:drag(event.touch) end )
end
-- set a choice in the selector list
function Slider:setCur(v)
self.selector:setCur(v)
self.dy = (v-1) * self.selector.h * self.ratio
self.selector.y = self.y0 - self.selector.h/2 - self.dy
self.dot.y = self.y0 - self.dy
end
function Slider:draw()
-- slider line
smooth()
stroke(0)
strokeWidth(10)
line(self.x0,self.y0,self.x1,self.y1)
stroke(200)
strokeWidth(6)
line(self.x0,self.y0,self.x1,self.y1)
-- slider dot
self.dot:draw()
self.selector:draw()
end
function Slider:drag(t)
local s = self.selector
if t.state == BEGAN then
s.visible = true
elseif t.state == MOVING then
self.dy = self.dy - t.deltaY
if self.dy < 0 then self.dy =0 end
if self.dy > self.dyMax then self.dy =self.dyMax end
s.dy = self.dy/self.ratio
s.y = self.y0 - s.h/2 - self.dy
self.dot.y = self.y0 - self.dy
elseif t.state == ENDED then
-- when finger released, finalize the value
s:update_cur()
s:update_dy()
s.callback( s.cur , s.list[ s.cur ] )
s.visible = false
end
end
function Slider:touched(t)
self.dotSensor:touched(t)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment