Created
September 20, 2015 14:56
-
-
Save anonymous/352a8fef0dee0814cee9 to your computer and use it in GitHub Desktop.
Gists Codea Upload
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--# 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) | |
ellipse(d/2, d/2, d) | |
-- ############ here is the blendmode setting ################################# | |
blendMode(ZERO, ONE_MINUS_SRC_ALPHA) -- | |
-- ############ and now let's see the effect ############ | |
ellipseMode(CENTER) | |
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 | |
fill(c2) | |
ellipse(d/2, d/2, d) | |
blendMode(ZERO, ONE_MINUS_SRC_ALPHA) | |
ellipseMode(CENTER) | |
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() | |
demo[#demo] = nil -- remove Slider tab from the list | |
demo[#demo] = nil -- remove Selector tab from the list | |
demo[#demo] = nil -- remove Main tab from the list | |
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) | |
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 | |
local x0,y0,mainSelected = 0,0 | |
function mainTouched(t) | |
if slider:touched(t) then return true end | |
if touchedDemo(t) then return true end | |
if t.state == BEGAN then | |
mainSelected = true | |
x0 = t.x | |
y0 = t.y | |
elseif t.state == MOVING and mainSelected and touchable then | |
elseif t.state == ENDED and mainSelected and touchable then | |
mainSelected = false | |
local deltaX = t.x-x0 | |
x0 = t.x | |
y0 = t.y | |
local mini = 70 | |
if deltaX < -mini and current<#demo then setTab(current + 1) end | |
if deltaX > mini and current>1 then setTab(current - 1) end | |
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 | |
--# 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.touchable = (#self.list~=1) -- if 1 option only, this is just a text box | |
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() | |
-- 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 | |
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() | |
-- 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 | |
local abs = math.abs | |
function Selector:inbox(t) | |
-- check if the box is touched | |
return abs(t.x-self.xr)<self.wr and abs(t.y-self.yr)<self.hr | |
end | |
function Selector:touched(t) | |
if not self.touchable then return end | |
if t.state == BEGAN and self:inbox(t) then | |
self.isSelected = true | |
elseif t.state == MOVING and self.isSelected 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 and self.isSelected then | |
-- when finger released, finalize the value | |
self.isSelected = false | |
self:update_cur() | |
self:update_dy() | |
self.callback( self.cur , self.list[ self.cur ] ) | |
end | |
return self.isSelected | |
end | |
--# Slider | |
Slider = class() | |
function Slider:init(data) | |
self.selector = Selector(data) | |
local dx = 20 | |
self.x0 = WIDTH - dx | |
self.x1 = self.x0 | |
self.y0 = HEIGHT*0.7 | |
self.y1 = HEIGHT*0.1 | |
self.ratio = (self.y0-self.y1)/(self.selector.h * (#self.selector.list-1)) | |
self.dy = 0 | |
self.dyMax = self.y0-self.y1 | |
self.selector.x = self.x0 - self.selector.w - 50 | |
self.selector.y = self.y0 - self.selector.h/2 | |
end | |
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 | |
end | |
function Slider:draw() | |
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) | |
stroke(0) | |
strokeWidth(2) | |
fill(200) | |
ellipse(self.x0,self.y0-self.dy,25) | |
if self.isSelected then | |
self.selector:draw() | |
end | |
end | |
local abs = math.abs | |
function Slider:inbox(t) | |
local r = 30 | |
return abs(t.x-self.x0)<r and abs(t.y-self.y0+self.dy)<r | |
end | |
function Slider:touched(t) | |
local s = self.selector | |
if t.state == BEGAN and self:inbox(t) then | |
self.isSelected = true | |
elseif t.state == MOVING and self.isSelected 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 | |
elseif t.state == ENDED and self.isSelected then | |
-- when finger released, finalize the value | |
self.isSelected = false | |
s:update_cur() | |
s:update_dy() | |
s.callback( s.cur , s.list[ s.cur ] ) | |
end | |
return self.isSelected | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment