Skip to content

Instantly share code, notes, and snippets.

Created September 20, 2015 14:56
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/352a8fef0dee0814cee9 to your computer and use it in GitHub Desktop.
Save anonymous/352a8fef0dee0814cee9 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)
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