Created
May 17, 2013 20:12
-
-
Save loopspace/5601697 to your computer and use it in GitHub Desktop.
Harmony CModule Release v2.10 -A drawing application with lots of brush styles.
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
-- AirBrush | |
--[==[ | |
local Brush = cimport "Brush" | |
local AirBrush = class(Brush) | |
function AirBrush:init(tb) | |
Brush.init(self,"AirBrush",tb) | |
end | |
function AirBrush:stroke(x,id,t) | |
local dx = x - self.lines[id].finish | |
self.lines[id].finish = x | |
local dist = 100/(dx:len() +1) + 4 | |
self:addDisc({ | |
centre = x, | |
radius = dist * self.style.thickness / 2, | |
edgeOpacity = 0, | |
smooth = false | |
}) | |
end | |
function AirBrush:strokeEnd(v,id) | |
self.lastline = self.lines[id] | |
self.lines[id] = nil | |
end | |
return AirBrush | |
--]==] |
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
-- Brush | |
--[==[ | |
local Drawable = cimport "Drawable" | |
local Colour = unpack(cimport (BaseLib .. "Colour")) | |
cimport(BaseLib .. "Path") | |
cimport(BaseLib .. "Slider") | |
local Brush = class(Drawable) | |
function Brush:init(name,tb) | |
Drawable.init(self,name,tb) | |
self.lines = {} | |
self.touches = {} | |
self.mesh = mesh() | |
self.mesh:resize(30000) | |
self.nlines = 0 | |
end | |
function Brush:reset() | |
self.lines = {} | |
self.lastline = nil | |
end | |
function Brush:clear() | |
self.isfinished = false | |
self.touches = {} | |
self.mesh = mesh() | |
self.mesh:resize(30000) | |
self.nlines = 0 | |
self:reset() | |
end | |
function Brush:undo() | |
end | |
function Brush:redo() | |
end | |
function Brush:setAlpha(aim) | |
self.mesh.texture = aim | |
end | |
function Brush:strokeStart(x,id) | |
if self.style.join == JOINNONE then | |
self.lines[id] = {} | |
self.lines[id].finish = x | |
elseif self.style.join == JOINMOVE then | |
self.lines[id] = {} | |
self.lines[id].finish = x | |
elseif self.style.join == JOINLINE then | |
if self.lastline then | |
self.lines[id] = self.lastline | |
self.lastline = nil | |
self:stroke(x,id) | |
else | |
self.lines[id] = {} | |
self.lines[id].finish = x | |
end | |
self.style.join = self.style.oldjoin or JOINNONE | |
end | |
end | |
function Brush:stroke(x,id,t) | |
end | |
function Brush:basicStroke(x,id,t) | |
if self.lines[id] then | |
t = t or {} | |
local y,th | |
local l = self.lines[id] | |
if l.start then | |
if l.start:distSqr(l.finish) > 100 | |
--and math.abs((l.finish - l.start):normalize():rotate90():dot((x - l.finish):normalize())) > .2 | |
then | |
-- if false then | |
-- if true then | |
local bza,bzb | |
bza,bzb,th = QuickHobby(l.start,l.finish,x,l.th) | |
local ca = Bezierpt(1/3,unpack(bza)) | |
local cb = Bezierpt(2/3,unpack(bza)) | |
local a,b | |
if l.previousSegment then | |
if l.previousSegment.start then | |
a = (l.previousSegment.finish - | |
l.previousSegment.start):normalize() | |
b = (ca - | |
l.previousSegment.finish):normalize() | |
if a:dot(b) < -0.5 then | |
l.previousSegment.after = | |
l.previousSegment.finish - b | |
l.before = l.previousSegment.finish + a | |
else | |
l.previousSegment.after = ca | |
end | |
self:addLine(l.previousSegment) | |
end | |
end | |
local c = { | |
l.before, | |
l.start, | |
ca, | |
cb, | |
l.finish, | |
x} | |
for i=2,4 do | |
l.before = c[i-1] | |
l.start = c[i] | |
l.finish = c[i+1] | |
a = (c[i+1] - c[i]):normalize() | |
b = (c[i+2] - c[i+1]):normalize() | |
if a:dot(b) < -0.5 then | |
l.after = l.finish - b | |
c[i] = l.finish + a | |
else | |
l.after = c[i+2] | |
end | |
self:addLine(l) | |
if i ~= 4 then l.position = nil end | |
end | |
y = c[4] | |
else | |
local a,b | |
a = (l.finish - l.start):normalize() | |
b = (x - l.finish):normalize() | |
if a:dot(b) < -0.5 then | |
l.after = l.finish - b | |
y = l.finish + a | |
else | |
l.after = x | |
y = l.start | |
end | |
self:addLine(l) | |
end | |
end | |
l.previousSegment = nil | |
t.start = l.finish | |
t.before = y | |
t.finish = x | |
t.th = th | |
t.previousSegment = l | |
t.startCapData = l.startCapData | |
t.endCapData = l.endCapData | |
t.startCap = l.startCap | |
t.endCap = l.endCap | |
self.lines[id] = self:addLine(t) | |
end | |
end | |
function Brush:strokeEnd(v,id) | |
self:stroke(v,id) | |
self.lastline = self.lines[id] | |
self.lines[id] = nil | |
end | |
function Brush:processTouches(g) | |
self.touches = {} | |
self.ntouches = 0 | |
for _,t in ipairs(g.touchesArr) do | |
if t.updated then | |
table.insert(self.touches,t) | |
end | |
end | |
if g.type.ended then | |
if self.style.join == JOINNONE then | |
self.resetafter = true | |
end | |
self.isfinished = true | |
g:reset() | |
else | |
g:noted() | |
end | |
end | |
function Brush:predraw() | |
for _,t in ipairs(self.touches) do | |
local v = OrientationInverse( | |
PORTRAIT, vec2(t.touch.x,t.touch.y)) | |
if t.touch.state == BEGAN then | |
self.lines[t.touch.id] = nil | |
self:strokeStart(v,t.touch.id) | |
elseif t.touch.state == MOVING then | |
self:stroke(v,t.touch.id) | |
else | |
self:strokeEnd(v,t.touch.id) | |
end | |
end | |
self.touches = {} | |
if self.resetafter then | |
self:reset() | |
self.resetafter = false | |
end | |
end | |
function Brush:draw() | |
self.mesh:draw() | |
end | |
function Brush:addLine(t) | |
local s,e,ws,we,b,a,sw,ew,wl,wn,n,sm,bl,sc,ec | |
t.startThickness = t.startThickness or t.thickness or self.style.thickness | |
t.endThickness = t.endThickness or t.thickness or self.style.thickness | |
t.startColour = t.startColour or t.colour or self.style.colour | |
t.endColour = t.endColour or t.colour or self.style.colour | |
t.startOpacity = t.startOpacity or | |
t.opacity or self.style.opacity or 100 | |
t.endOpacity = t.endOpacity or | |
t.opacity or self.style.opacity or 100 | |
t.smooth = t.smooth or self.style.smooth | |
t.blur = t.blur or self.style.blur | |
t.startCap = t.startCap or self.style.cap | |
t.endCap = t.endCap or self.style.cap | |
t.startCapData = t.startCapData or {} | |
t.endCapData = t.endCapData or {} | |
ws = t.startThickness | |
we = t.endThickness | |
s = t.start | |
e = t.finish | |
b = t.before | |
a = t.after | |
bl = t.blur | |
sm = t.smooth | |
sc = Colour.opacity(t.startColour,t.startOpacity) | |
ec = Colour.opacity(t.endColour,t.endOpacity) | |
if sm then | |
we = math.max(0,we-2*bl) | |
ws = math.max(0,ws-2*bl) | |
end | |
we = we/2 | |
ws = ws/2 | |
wl = (e - s):normalize() | |
wn = wl:rotate90() | |
if b then | |
sw = (s - b):normalize() - wl | |
if wn:dot(sw) == 0 then | |
sw = wn | |
else | |
sw = sw/wn:dot(sw) | |
end | |
else | |
sw = wn | |
end | |
if a then | |
ew = (a - e):normalize() - wl | |
if wn:dot(ew) == 0 then | |
ew = wn | |
else | |
ew = ew/wn:dot(ew) | |
end | |
else | |
ew = wn | |
end | |
if ew:dot(sw) < 0 then | |
ew = - ew | |
end | |
if not b then | |
-- update start cap data | |
local ct = t.startCapData | |
ct.thickness = t.startThickness | |
ct.colour = t.startColour | |
ct.opacity = t.startOpacity | |
ct.smooth = t.smooth | |
ct.blur = t.blur | |
ct.cap = t.startCap | |
ct.start = s | |
ct.direction = -wl | |
t.startCapData = self:addCap(ct) | |
end | |
if not a then | |
-- update end cap data | |
local ct = t.endCapData | |
ct.thickness = t.endThickness | |
ct.colour = t.endColour | |
ct.opacity = t.endOpacity | |
ct.smooth = t.smooth | |
ct.blur = t.blur | |
ct.cap = t.endCap | |
ct.start = e | |
ct.direction = wl | |
t.endCapData = self:addCap(ct) | |
end | |
t.position = t.position or self.nlines | |
n = t.position | |
n = addQuad({ | |
mesh = self.mesh, | |
position = n, | |
vertices = { | |
{s-ws*sw,sc}, | |
{s+ws*sw,sc}, | |
{e-we*ew,ec}, | |
{e+we*ew,ec} | |
} | |
}) | |
if sm then | |
local l | |
local sct = Colour.opacity(sc,0) | |
local ect = Colour.opacity(ec,0) | |
local corners = { | |
{{s+ws*sw,sc},{s+(ws+bl)*sw,sct}}, | |
{{e+we*ew,ec},{e+(we+bl)*ew,ect}}, | |
{{e-we*ew,ec},{e-(we+bl)*ew,ect}}, | |
{{s-ws*sw,sc},{s-(ws+bl)*sw,sct}}, | |
} | |
for _,k in ipairs({1,3}) do | |
l=k%4+1 | |
n = addQuad({ | |
mesh = self.mesh, | |
position = n, | |
vertices = { | |
corners[k][1], | |
corners[k][2], | |
corners[l][1], | |
corners[l][2], | |
} | |
}) | |
end | |
end | |
self.nlines = math.max(self.nlines,n) | |
return t | |
end | |
function Brush:addCircle(t) | |
local w,c,r,n,bl,sm,col,e | |
t.colour = t.colour or self.style.colour | |
t.opacity = t.opacity or self.style.opacity or 100 | |
t.position = t.position or self.nlines | |
t.smooth = t.smooth or self.style.smooth | |
t.blur = t.blur or self.style.blur | |
t.accuracy = t.accuracy or 5 | |
t.thickness = t.thickness or self.style.thickness | |
w = t.thickness | |
c = t.centre | |
r = t.radius | |
n = t.position | |
bl = t.blur | |
sm = t.smooth | |
col = Colour.opacity(t.colour,t.opacity) | |
e = t.accuracy | |
if sm then | |
w = math.max(0,w-2*bl) | |
end | |
w = w/2 | |
local m = math.max(math.floor(2*math.pi*r/e),15) | |
local a = 2*math.pi/m | |
local n = self.nlines | |
local v = vec2(1,0) | |
local u = vec2(math.cos(a),math.sin(a)) | |
for i=1,m do | |
n = addQuad({ | |
mesh = self.mesh, | |
position = n, | |
vertices = { | |
{c+(r-w)*v,col}, | |
{c+(r+w)*v,col}, | |
{c+(r-w)*u,col}, | |
{c+(r+w)*u,col}, | |
} | |
}) | |
v = u | |
u = vec2(math.cos((i+1)*a),math.sin((i+1)*a)) | |
end | |
if sm then | |
local tcol = Colour.opacity(col,0) | |
v = vec2(1,0) | |
u = vec2(math.cos(a),math.sin(a)) | |
for i=1,m do | |
n = addQuad({ | |
mesh = self.mesh, | |
position = n, | |
vertices = { | |
{c+(r+w)*v,col}, | |
{c+(r+w+bl)*v,tcol}, | |
{c+(r+w)*u,col}, | |
{c+(r+w+bl)*u,tcol}, | |
} | |
}) | |
n = addQuad({ | |
mesh = self.mesh, | |
position = n, | |
vertices = { | |
{c+(r-w)*v,col}, | |
{c+(r-w-bl)*v,tcol}, | |
{c+(r-w)*u,col}, | |
{c+(r-w-bl)*u,tcol}, | |
} | |
}) | |
v = u | |
u = vec2(math.cos((i+1)*a),math.sin((i+1)*a)) | |
end | |
end | |
self.nlines = math.max(self.nlines,n) | |
return t | |
end | |
function Brush:addDisc(t) | |
local c,r,n,bl,sm,sc,ec,e | |
t.centreColour = t.centreColour or t.colour or self.style.colour | |
t.edgeColour = t.edgeColour or t.colour or self.style.colour | |
t.centreOpacity = t.centreOpacity | |
or t.opacity or self.style.opacity or 100 | |
t.edgeOpacity = t.edgeOpacity or | |
t.opacity or self.style.opacity or 100 | |
t.position = t.position or self.nlines | |
t.smooth = t.smooth or self.style.smooth | |
t.blur = t.blur or self.style.blur | |
t.accuracy = t.accuracy or 5 | |
c = t.centre | |
r = t.radius | |
n = t.position | |
bl = t.blur | |
sm = t.smooth | |
sc = Colour.opacity(t.centreColour,t.centreOpacity) | |
ec = Colour.opacity(t.edgeColour,t.edgeOpacity) | |
e = t.accuracy | |
if sm then | |
r = math.max(0,r-bl) | |
end | |
local m = math.max(math.floor(2*math.pi*r/e),15) | |
local a = 2*math.pi/m | |
local n = t.position | |
local v = vec2(1,0) | |
local u = vec2(math.cos(a),math.sin(a)) | |
for i=1,m do | |
n = addTriangle({ | |
mesh = self.mesh, | |
position = n, | |
vertices = { | |
{c,sc}, | |
{c+r*v,ec}, | |
{c+r*u,ec}, | |
} | |
}) | |
v = u | |
u = vec2(math.cos((i+1)*a),math.sin((i+1)*a)) | |
end | |
if sm then | |
local tec = Colour.opacity(ec,0) | |
v = vec2(1,0) | |
u = vec2(math.cos(a),math.sin(a)) | |
for i=1,m do | |
n = addQuad({ | |
mesh = self.mesh, | |
position = n, | |
vertices = { | |
{c+r*v,ec}, | |
{c+(r+bl)*v,tec}, | |
{c+r*u,ec}, | |
{c+(r+bl)*u,tec}, | |
} | |
}) | |
v = u | |
u = vec2(math.cos((i+1)*a),math.sin((i+1)*a)) | |
end | |
end | |
self.nlines = math.max(self.nlines,n) | |
return t | |
end | |
function Brush:addHalfDisc(t) | |
local c,r,n,bl,sm,sc,ec,e,nv,m,a,v,u | |
t.centreColour = t.centreColour or t.colour or self.style.colour | |
t.edgeColour = t.edgeColour or t.colour or self.style.colour | |
t.centreOpacity = t.centreOpacity | |
or t.opacity or self.style.opacity or 100 | |
t.edgeOpacity = t.edgeOpacity or | |
t.opacity or self.style.opacity or 100 | |
t.position = t.position or self.nlines | |
t.smooth = t.smooth or self.style.smooth | |
t.blur = t.blur or self.style.blur | |
t.accuracy = t.accuracy or 5 | |
c = t.centre | |
r = t.radius | |
nv = t.normal:normalize() | |
n = t.position | |
bl = t.blur | |
sm = t.smooth | |
sc = Colour.opacity(t.centreColour,t.centreOpacity) | |
ec = Colour.opacity(t.edgeColour,t.edgeOpacity) | |
e = t.accuracy | |
if sm then | |
r = math.max(0,r-bl) | |
end | |
m = math.max(math.floor(2*math.pi*r/e),15) | |
a = math.pi/m | |
v = nv | |
u = nv:rotate(a) | |
for i=1,m do | |
n = addTriangle({ | |
mesh = self.mesh, | |
position = n, | |
vertices = { | |
{c,sc}, | |
{c+r*v,ec}, | |
{c+r*u,ec}, | |
} | |
}) | |
v = u | |
u = nv:rotate((i+1)*a) | |
end | |
if sm then | |
local tec = Colour.opacity(ec,0) | |
v = nv | |
u = nv:rotate(a) | |
for i=1,m do | |
n = addQuad({ | |
mesh = self.mesh, | |
position = n, | |
vertices = { | |
{c+r*v,ec}, | |
{c+(r+bl)*v,tec}, | |
{c+r*u,ec}, | |
{c+(r+bl)*u,tec}, | |
} | |
}) | |
v = u | |
u = nv:rotate((i+1)*a) | |
end | |
end | |
self.nlines = math.max(self.nlines,n) | |
return t | |
end | |
function Brush:addCap(t) | |
local s,w,sw,wl,wn,n,sm,bl,sc | |
t.thickness = t.thickness or t.thickness or self.style.thickness | |
t.colour = t.colour or t.colour or self.style.colour | |
t.opacity = t.opacity or | |
t.opacity or self.style.opacity or 100 | |
t.smooth = t.smooth or self.style.smooth | |
t.blur = t.blur or self.style.blur | |
t.cap = t.cap or self.style.cap | |
t.position = t.position or self.nlines | |
if t.cap == CAPNONE then return t end | |
if t.cap == CAPSQUARE and not t.smooth then return t end | |
w = t.thickness | |
s = t.start | |
bl = t.blur | |
sm = t.smooth | |
sc = Colour.opacity(t.colour,t.opacity) | |
if sm then | |
w = math.max(0,w-2*bl) | |
end | |
w = w/2 | |
wl = t.direction:normalize() | |
wn = wl:rotate90() | |
if t.cap == CAPROUND then | |
t.normal = -wn | |
t.centre = s | |
t.radius = t.thickness/2 | |
t.centreColour = t.colour | |
t.edgeColour = t.colour | |
t.centreOpacity = t.opacity | |
t.edgeOpacity = t.opacity | |
return self:addHalfDisc(t) | |
end | |
if t.cap == CAPBUTT then | |
local e = s + w*wl | |
n = t.position | |
n = addQuad({ | |
mesh = self.mesh, | |
position = n, | |
vertices = { | |
{s-w*wn,sc}, | |
{s+w*wn,sc}, | |
{e-w*wn,sc}, | |
{e+w*wn,sc} | |
} | |
}) | |
if sm then | |
local l | |
local sct = Colour.opacity(sc,0) | |
local edges = {1,2,3} | |
local corners = { | |
{{s+w*wn,sc},{s+(w+bl)*wn,sct}}, | |
{{e+w*wn,sc},{e+(w+bl)*wn+bl*wl,sct}}, | |
{{e-w*wn,sc},{e-(w+bl)*wn+bl*wl,sct}}, | |
{{s-w*wn,sc},{s-(w+bl)*wn,sct}}, | |
} | |
for _,k in ipairs(edges) do | |
l=k%4+1 | |
n = addQuad({ | |
mesh = self.mesh, | |
position = n, | |
vertices = { | |
corners[k][1], | |
corners[k][2], | |
corners[l][1], | |
corners[l][2], | |
} | |
}) | |
end | |
end | |
self.nlines = math.max(self.nlines,n) | |
return t | |
end | |
if t.cap == CAPSQUARE and sm then | |
local l | |
local sct = Colour.opacity(sc,0) | |
n = t.position | |
n = addQuad({ | |
mesh = self.mesh, | |
position = n, | |
vertices = { | |
{s+w*wn,sc}, | |
{s+(w+bl)*wn+bl*wl,sct}, | |
{s-w*wn,sc}, | |
{s-(w+bl)*wn+bl*wl,sct} | |
} | |
}) | |
n = addTriangle({ | |
mesh = self.mesh, | |
position = n, | |
vertices = { | |
{s+w*wn,sc}, | |
{s+(w+bl)*wn+bl*wl,sct}, | |
{s+(w+bl)*wn,sct}, | |
} | |
}) | |
n = addTriangle({ | |
mesh = self.mesh, | |
position = n, | |
vertices = { | |
{s-w*wn,sc}, | |
{s-(w+bl)*wn+bl*wl,sct}, | |
{s-(w+bl)*wn,sct}, | |
} | |
}) | |
self.nlines = math.max(self.nlines,n) | |
return t | |
end | |
return t | |
end | |
return Brush | |
--]==] |
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
-- BrushEx | |
--[==[ | |
local Brush = cimport "Brush" | |
BrushEx = class(Brush) | |
function BrushEx:init(name,tb) | |
Brush.init(self,name,tb) | |
self.points = {} | |
self.count = 0 | |
self.pcount = 0 | |
self.lines = {} | |
self.touches = {} | |
end | |
function BrushEx:reset() | |
self.lines = {} | |
self.points = {} | |
self.count = 0 | |
self.pcount = 0 | |
self.lastline = nil | |
end | |
function BrushEx:undo() | |
self.pcount,self.count = self.count,self.pcount | |
end | |
function BrushEx:redo() | |
self.pcount,self.count = self.count,self.pcount | |
end | |
function BrushEx:predraw() | |
for _,t in ipairs(self.touches) do | |
local v = OrientationInverse( | |
PORTRAIT, vec2(t.touch.x,t.touch.y)) | |
if t.touch.state == BEGAN then | |
self.pcount = self.count | |
self.lines[t.touch.id] = nil | |
self:strokeStart(v,t.touch.id) | |
elseif t.touch.state == MOVING then | |
self:stroke(v,t.touch.id) | |
else | |
self:strokeEnd(v,t.touch.id) | |
end | |
self.count = self.count + 1 | |
self.points[self.count] = v | |
end | |
self.touches = {} | |
if self.resetafter then | |
self:reset() | |
self.resetafter = false | |
end | |
end | |
return BrushEx | |
--]==] |
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
-- Canvas | |
--[==[ | |
local JOINNONE = 0 | |
local JOINMOVE = 1 | |
local JOINLINE = 2 | |
local CAPNONE = 0 | |
local CAPSQUARE = 1 | |
local CAPBUTT = 2 | |
local CAPROUND = 3 | |
local BLENDS = { | |
{"Normal",{NORMAL}}, | |
{"Multiply",{MULTIPLY}}, | |
{"Additive",{ADDITIVE}}, | |
{"Eraser",{ZERO,ONE_MINUS_SRC_ALPHA}}, | |
{"Inverter",{ONE_MINUS_DST_COLOR,ONE_MINUS_SRC_COLOR,ZERO,ONE}}, | |
{"Mask",{ZERO,SRC_COLOR,ZERO,ONE}}, | |
{"Replace",{ONE,ZERO,ONE,ZERO}} | |
} | |
local Canvas = class() | |
local Colour = unpack(cimport (BaseLib .. "Colour")) | |
cimport (BaseLib .. "ColourNames") | |
cimport (BaseLib .. "Keyboard") | |
cimport (BaseLib .. "PictureBrowser") | |
cimport (BaseLib .. "FontPicker") | |
cimport (BaseLib .. "Menu") | |
local TextBlock = cimport "TextBlock" | |
local Picture = cimport "Picture" | |
local Brushes = { | |
"FlowLines", | |
"AirBrush", | |
"Chrome", | |
"Circles", | |
"Discs", | |
"Fur", | |
"LongFur", | |
"Shaded", | |
"Simple", | |
"Sketchy", | |
"Squares", | |
"Web" | |
} | |
for _,v in ipairs(Brushes) do | |
cimport (v) | |
end | |
function Canvas:init(t) | |
t = t or {} | |
if t.touchHandler then | |
t.touchHandler:pushHandler(self) | |
end | |
self.ui = t.ui | |
self.style = { | |
thickness = 2, | |
minthickness = 2, | |
maxthickness = 15, | |
blur = 1, | |
smooth = true, | |
bgcolour = Colour.opacity(Colour.svg.White,25), | |
curve = false, | |
join = JOINMOVE, | |
cap = CAPBUTT, | |
hidden = false, | |
colour = Colour.svg.Black, | |
alpha = 100, | |
txtcolour = Colour.svg.Black, | |
txtbgcolour = Colour.transparent, | |
font = "Georgia", | |
fontsize = 32, | |
keyboard = "fullqwerty", | |
blendmode = BLENDS[1][2], | |
picture = { | |
red = color(255, 0, 0, 0), | |
green = color(0, 255, 0, 0), | |
blue = color(0, 0, 255, 0), | |
alpha = color(0, 0, 0, 255), | |
redcurve = vec4(0,1,0,0), | |
greencurve = vec4(0,1,0,0), | |
bluecurve = vec4(0,1,0,0), | |
alphacurve = vec4(0,1,0,0), | |
brightness = vec4(0,1,0,0) | |
} | |
} | |
if t.initialStyle then | |
self:setStyle(t.initialStyle) | |
end | |
local useText = true | |
local usePictures = true | |
local singleBrush = false | |
if t.enableText ~= nil then | |
useText = t.enableText | |
end | |
if t.enablePictures ~= nil then | |
usePictures = t.enablePictures | |
end | |
if t.brushes ~= nil then | |
if type(t.brushes) == "table" then | |
if #t.brushes == 1 then | |
singleBrush = true | |
end | |
elseif type(t.brushes) == "string" then | |
singleBrush = true | |
end | |
end | |
if useText then | |
t.ui:declareKeyboard({ | |
name = "ArialMT", | |
type = self.style.keyboard | |
}) | |
end | |
if usePictures then | |
t.ui:setPictureList({directory = "Documents", | |
camera = true, | |
filter = function(n,w,h) | |
return math.min(w,h) > 500 | |
end}) | |
end | |
-- meshes | |
-- Background mesh, holding the background image | |
self.bgmesh = mesh() | |
self.bgmesh:addRect( | |
Portrait[3]/2,Portrait[4]/2,Portrait[3],Portrait[4]) | |
self.bgmesh:setColors(Colour.svg.White) | |
self.bgtcoords = { | |
vec2(0,0),vec2(1,0),vec2(1,1),vec2(0,0),vec2(1,1),vec2(0,1) | |
} -- normal | |
self.bgmesh.texCoords = self.bgtcoords | |
-- canvas mesh, everything drawn so far | |
self.canvas = image(Portrait[3],Portrait[4]) | |
self.canvasmesh = mesh() | |
self.canvasmesh:addRect( | |
Portrait[3]/2,Portrait[4]/2,Portrait[3],Portrait[4]) | |
self.canvasmesh.texture = self.canvas | |
self.canvasmesh:setRectTex(1,0,0,1,1) | |
-- undo mesh, very latest drawing | |
self.undoimage = image(Portrait[3],Portrait[4]) | |
-- undo booleans | |
self.undoable = false | |
self.undo = true | |
self.redoable = false | |
-- for rendering alpha | |
self.cvs = image(Portrait[3],Portrait[4]) | |
self.cvsmesh = mesh() | |
self.cvsmesh:addRect( | |
Portrait[3]/2,Portrait[4]/2,Portrait[3],Portrait[4]) | |
self.cvsmesh.texture = self.cvs | |
self.alphaim = image(5,5) | |
-- menus | |
local attach = true | |
if t.attachMenu ~= nil then | |
attach = t.attachMenu | |
end | |
local m = t.ui:addMenu({ | |
title = t.title or "Drawing", | |
attach = attach | |
}) | |
local stm = t.ui:addMenu({ | |
title = t.styleTitle or "Style", | |
attach = attach | |
}) | |
self.menu = m | |
self.stylemenu = stm | |
local bm,txtm,picm | |
if not singleBrush then | |
bm = t.ui:addMenu({}) | |
self.brushmenu = bm | |
bm:isChildOf(m) | |
end | |
local bgm = t.ui:addMenu({}) | |
if useText then | |
txtm = t.ui:addMenu({}) | |
txtm:isChildOf(m) | |
end | |
if usePictures then | |
picm = t.ui:addMenu({}) | |
picm:isChildOf(stm) | |
end | |
local sbm = t.ui:addMenu({}) | |
local bsm = t.ui:addMenu({}) | |
local pcm = t.ui:addMenu({}) | |
self.brushstylemenu = sbm | |
local sm = t.ui:addMenu({}) | |
sbm:isChildOf(stm) | |
sm:isChildOf(m) | |
bgm:isChildOf(m) | |
bsm:isChildOf(sbm) | |
pcm:isChildOf(sbm) | |
if not singleBrush then | |
m:addItem({ | |
title = "Brushes", | |
action = function(x,y) | |
bm.active = not bm.active | |
bm.x = x | |
bm.y = y | |
end, | |
highlight = function() | |
return bm.active | |
end, | |
deselect = function() | |
bm.active = false | |
end, | |
}) | |
end | |
stm:addItem({ | |
title = "Brush Style", | |
action = function(x,y) | |
if sbm.active then | |
sbm:deactivateDown() | |
else | |
sbm:activate() | |
sbm.x = x | |
sbm.y = y | |
end | |
end, | |
highlight = function() | |
return sbm.active | |
end, | |
deselect = function() | |
sbm:deactivateDown() | |
end, | |
}) | |
sbm:addItem({ | |
title = "Colour", | |
action = function() | |
t.ui:getColour( | |
self.style.colour, | |
function(c) self:setColour(c) return true end | |
) | |
return true | |
end | |
}) | |
sbm:addItem({ | |
title = "Thickness", | |
action = function() | |
t.ui:getParameter( | |
self.style.thickness, | |
self.style.minthickness, | |
self.style.maxthickness, | |
function(t) | |
self.style.thickness = t | |
return true | |
end, | |
function(t) | |
self.style.thickness = t | |
return true | |
end | |
) | |
return true | |
end | |
}) | |
sbm:addItem({ | |
title = "Blur", | |
action = function() | |
t.ui:getParameter( | |
self.style.blur, | |
0, | |
10, | |
function(t) | |
self.style.blur = t | |
return true | |
end, | |
function(t) | |
self.style.blur = t | |
return true | |
end | |
) | |
return true | |
end | |
}) | |
sbm:addItem({ | |
title = "Smooth", | |
action = function() | |
self.style.smooth = not self.style.smooth | |
return true | |
end, | |
highlight = function() return self.style.smooth end | |
}) | |
sbm:addItem({ | |
title = "Blend Style", | |
action = function(x,y) | |
if bsm.active then | |
bsm:deactivateDown() | |
else | |
bsm:activate() | |
bsm.x = x | |
bsm.y = y | |
end | |
end, | |
highlight = function() | |
return bsm.active | |
end, | |
deselect = function() | |
bsm:deactivateDown() | |
end, | |
}) | |
--[[ | |
sbm:addItem({ | |
title = "Curve", | |
action = function() | |
self.style.curve = not self.style.curve | |
return true | |
end, | |
highlight = function() return self.style.curve end | |
}) | |
--]] | |
sbm:addItem({ | |
title = "Join paths (line)", | |
action = function() | |
if self.style.join == JOINLINE then | |
self.style.join = JOINNONE | |
else | |
self.style.oldjoin = self.style.join | |
self.style.join = JOINLINE | |
end | |
return true | |
end, | |
highlight = function() return self.style.join == JOINLINE end | |
}) | |
sbm:addItem({ | |
title = "Join paths (move)", | |
action = function() | |
if self.style.join == JOINMOVE then | |
self.style.join = JOINNONE | |
else | |
self.style.join = JOINMOVE | |
end | |
return true | |
end, | |
highlight = function() return self.style.join == JOINMOVE end | |
}) | |
sbm:addItem({ | |
title = "Path Cap", | |
action = function(x,y) | |
if pcm.active then | |
pcm:deactivateDown() | |
else | |
pcm:activate() | |
pcm.x = x | |
pcm.y = y | |
end | |
end, | |
highlight = function() | |
return pcm.active | |
end, | |
deselect = function() | |
pcm:deactivateDown() | |
end, | |
}) | |
pcm:addItem({ | |
title = "Butt", | |
action = function() | |
self.style.cap = CAPBUTT | |
return true | |
end, | |
highlight = function() return self.style.cap == CAPBUTT end | |
}) | |
pcm:addItem({ | |
title = "Square", | |
action = function() | |
self.style.cap = CAPSQUARE | |
return true | |
end, | |
highlight = function() return self.style.cap == CAPSQUARE end | |
}) | |
pcm:addItem({ | |
title = "Round", | |
action = function() | |
self.style.cap = CAPROUND | |
return true | |
end, | |
highlight = function() return self.style.cap == CAPROUND end | |
}) | |
sbm:addItem({ | |
title = "Clear Current History", | |
action = function() | |
self.drawable:reset() | |
return true | |
end | |
}) | |
sbm:addItem({ | |
title = "Unclog Pen", | |
action = function() | |
self.drawable.touchId = nil | |
return true | |
end | |
}) | |
sbm:addItem({ | |
title = "Specific Options", | |
action = function(x,y) | |
if self.drawable.menu then | |
self.drawable.menu.active = | |
not self.drawable.menu.active | |
self.drawable.menu.x = x | |
self.drawable.menu.y = y | |
end | |
end, | |
highlight = function() | |
if self.drawable.menu then | |
return self.drawable.menu.active | |
else | |
return false | |
end | |
end, | |
deselect = function() | |
if self.drawable.menu then | |
self.drawable.menu.active = false | |
end | |
end, | |
}) | |
for _,v in ipairs(BLENDS) do | |
bsm:addItem({ | |
title = v[1], | |
action = function() | |
self.style.blendmode = v[2] | |
return true | |
end, | |
highlight = function() | |
return self.style.blendmode == v[2] | |
end, | |
}) | |
end | |
stm:addItem({ | |
title = "Background", | |
action = function(x,y) | |
bgm.active = not bgm.active | |
bgm.x = x | |
bgm.y = y | |
end, | |
highlight = function() | |
return bgm.active | |
end, | |
deselect = function() | |
bgm.active = false | |
end | |
}) | |
if useText then | |
m:addItem({ | |
title = "Add Node", | |
action = function() | |
self:drawcanvas() | |
self.drawable = TextBlock(self,t.ui) | |
return true | |
end | |
}) | |
stm:addItem({ | |
title = "Text Style", | |
action = function(x,y) | |
txtm.active = not txtm.active | |
txtm.x = x | |
txtm.y = y | |
end, | |
highlight = function() | |
return txtm.active | |
end, | |
deselect = function() | |
txtm.active = false | |
end | |
}) | |
end | |
if usePictures then | |
m:addItem({ | |
title = "Add Picture", | |
action = function() | |
self:drawcanvas() | |
self.drawable = Picture(self,t.ui) | |
return true | |
end | |
}) | |
stm:addItem({ | |
title = "Picture Style", | |
action = function(x,y) | |
picm.active = not picm.active | |
picm.x = x | |
picm.y = y | |
end, | |
highlight = function() | |
return picm.active | |
end, | |
deselect = function() | |
picm.active = false | |
end | |
}) | |
for _,v in ipairs({ | |
{"Red", "red"}, | |
{"Green", "green"}, | |
{"Blue", "blue"}, | |
{"Alpha", "alpha"} | |
}) do | |
picm:addItem({ | |
title = v[1] .. " Channel", | |
action = function() | |
t.ui:getColour( | |
self.style.picture[v[2]], | |
function(c) | |
self.style.picture[v[2]] = c | |
self.drawable:updateStyle() | |
return true | |
end | |
) | |
picm:deactivateUp() | |
return true | |
end | |
}) | |
picm:addItem({ | |
title = v[1] .. " Curve", | |
action = function() | |
t.ui:getCurve( | |
self.style.picture[v[2] .. "curve"], | |
function(c) | |
self.style.picture[v[2] .. "curve"] = c | |
self.drawable:updateStyle() | |
return true | |
end, | |
function(c) | |
self.style.picture[v[2] .. "curve"] = c | |
self.drawable:updateStyle() | |
end | |
) | |
picm:deactivateUp() | |
return true | |
end | |
}) | |
end | |
picm:addItem({ | |
title = "Brightness", | |
action = function() | |
t.ui:getCurve( | |
self.style.picture.brightness, | |
function(c) | |
self.style.picture.brightness = c | |
self.drawable:updateStyle() | |
return true | |
end, | |
function(c) | |
self.style.picture.brightness = c | |
self.drawable:updateStyle() | |
end | |
) | |
picm:deactivateUp() | |
return true | |
end | |
}) | |
picm:addItem({ | |
title = "Reset Values", | |
action = function() | |
self.style.picture = { | |
red = color(255, 0, 0, 0), | |
green = color(0, 255, 0, 0), | |
blue = color(0, 0, 255, 0), | |
alpha = color(0, 0, 0, 255), | |
redcurve = vec4(0,1,0,0), | |
greencurve = vec4(0,1,0,0), | |
bluecurve = vec4(0,1,0,0), | |
alphacurve = vec4(0,1,0,0), | |
brightness = vec4(0,1,0,0) | |
} | |
self.drawable:updateStyle() | |
return true | |
end | |
}) | |
bgm:addItem({ | |
title = "Background Image", | |
action = function() | |
t.ui:getPicture( | |
function(i) | |
self.bgmesh.texture = i | |
return true | |
end | |
) | |
return true | |
end | |
}) | |
for _,v in ipairs({ | |
{"Rotate Clockwise", USRotateCCW}, -- rotate tex coords other way | |
{"Rotate Anticlockwise", USRotateCW}, | |
{"Reflect Horizontally", USReflectH}, | |
{"Reflect Vertically", USReflectV}, | |
}) do | |
bgm:addItem({ | |
title = v[1], | |
action = function() | |
for l,u in ipairs(self.bgtcoords) do | |
self.bgtcoords[l] = v[2](u) | |
end | |
self.bgmesh.texCoords = self.bgtcoords | |
return true | |
end | |
}) | |
end | |
bgm:addItem({ | |
title = "Background Image Tint", | |
action = function() | |
t.ui:getColour( | |
function(c) | |
self.bgmesh:setColors(c) | |
return true | |
end | |
) | |
return true | |
end | |
}) | |
end | |
bgm:addItem({ | |
title = "Background Colour", | |
action = function() | |
t.ui:getColour( | |
self.style.bgcolour, | |
function(c) | |
self.style.bgcolour = c | |
return true | |
end | |
) | |
return true | |
end | |
}) | |
m:addItem({ | |
title = "Undo", | |
action = function() | |
if self.undoable then | |
self.undo = true | |
self.redoable = true | |
self.undoable = false | |
self.drawable:undo() | |
return true | |
end | |
return false | |
end, | |
highlight = function() | |
return self.undoable | |
end | |
}) | |
m:addItem({ | |
title = "Redo", | |
action = function() | |
if self.redoable then | |
self.undo = false | |
self.undoable = true | |
self.redoable = false | |
self.drawable:redo() | |
return true | |
end | |
return false | |
end, | |
highlight = function() | |
return self.redoable | |
end | |
}) | |
m:addItem({ | |
title = "Save to ...", | |
action = function(x,y) | |
sm.active = not sm.active | |
sm.x = x | |
sm.y = y | |
end, | |
highlight = function() | |
return sm.active | |
end, | |
deselect = function() | |
sm.active = false | |
end | |
}) | |
for _,d in ipairs({"Documents","Dropbox"}) do | |
sm:addItem({ | |
title = d, | |
action = function() | |
t.ui:getText( | |
function(s) | |
self:export(d,s) | |
return true | |
end) | |
return true | |
end | |
}) | |
end | |
m:addItem({ | |
title = "Clear Canvas", | |
action = function() | |
self:clear() | |
return true | |
end | |
}) | |
if useText then | |
txtm:addItem({ | |
title = "Text Colour", | |
action = function() | |
t.ui:getColour( | |
self.style.txtcolour, | |
function(c) | |
self.style.txtcolour = c | |
self.drawable:updateStyle() | |
return true | |
end | |
) | |
return true | |
end | |
}) | |
txtm:addItem({ | |
title = "Text Background Colour", | |
action = function() | |
t.ui:getColour( | |
self.style.txtbgcolour, | |
function(c) | |
self.style.txtbgcolour = c | |
self.drawable:updateStyle() | |
return true | |
end | |
) | |
return true | |
end | |
}) | |
txtm:addItem({ | |
title = "Font", | |
action = function() | |
t.ui:getFont( | |
function(c) | |
self.style.font = c | |
self.drawable:updateStyle() | |
return true | |
end | |
) | |
return true | |
end | |
}) | |
txtm:addItem({ | |
title = "Font Size", | |
action = function() | |
t.ui:getNumber( | |
function(c) | |
self.style.fontsize = c | |
self.drawable:updateStyle() | |
return true | |
end | |
) | |
return true | |
end | |
}) | |
end | |
t.ui:addHelp({ | |
title = "Drawing", | |
text = "Select a brush to draw a path with different effects. A path can be drawn in more than one go by selecting one of the \"join\" methods (\"line\" means that the segments are actually joined together). In this case, the effect uses the whole path. The alpha value of the colour is applied after a segment is completed meaning that crossings on the same segment are not overlaid but crossings on different segments are." | |
}) | |
self:initBrushes(t.brushes) | |
end | |
function Canvas:hide() | |
self.hidden = true | |
end | |
function Canvas:unhide() | |
self.hidden = false | |
end | |
function Canvas:exportIfDrawn(...) | |
if self.drawnon then | |
self:export(...) | |
end | |
end | |
function Canvas:export(d,s,o) | |
self:drawcanvas() | |
local sn = s | |
if d then | |
if not o then | |
local l = spriteList(d) | |
local lt = {} | |
for _,v in ipairs(l) do | |
lt[v] = true | |
end | |
local n = 0 | |
while lt[sn] do | |
n = n + 1 | |
sn = string.format("%s%03d",s,n) | |
end | |
end | |
sn = d .. ":" .. sn | |
end | |
saveImage(sn,self.canvas) | |
popStyle() | |
popMatrix() | |
end | |
function Canvas:setColour(c) | |
self.style.colour = Colour.opaque(c) | |
self.style.alpha = c.a/2.55 | |
self:setLineAlpha() | |
end | |
function Canvas:setLineAlpha(a) | |
a = a or self.style.alpha | |
self.alphaim = image(5,5) | |
pushMatrix() | |
pushStyle() | |
resetMatrix() | |
resetStyle() | |
noSmooth() | |
fill(Colour.opacity(Colour.svg.White,a)) | |
setContext(self.alphaim) | |
rect(0,0,5,5) | |
setContext() | |
popStyle() | |
popMatrix() | |
self.drawable:setAlpha(self.alphaim) | |
end | |
-- Brushes Management | |
function Canvas:initBrushes(br) | |
local t = Brushes | |
local brn | |
if br then | |
brn = {} | |
if type(br) == "string" then | |
brn[br] = true | |
else | |
for _,v in ipairs(br) do | |
brn[v] = true | |
end | |
end | |
end | |
local cb,dobrush,brush | |
local m = self.brushmenu | |
for _,v in ipairs(t) do | |
dobrush = true | |
if brn then | |
if not brn[v] then | |
dobrush = false | |
end | |
end | |
if dobrush then | |
brush = cimport (v) | |
local b = brush(self) | |
if not cb then cb = b end | |
if m then | |
m:addItem({ | |
title = b:getName(), | |
action = function() | |
if self.drawable ~= b then | |
self:drawcanvas() | |
self.drawable = b | |
end | |
return true | |
end, | |
highlight = function() | |
return self.drawable == b | |
end | |
}) | |
end | |
end | |
end | |
self.drawable = cb | |
end | |
function Canvas:setBrush(b) | |
if self.brushmenu then | |
self.brushmenu:invoke(b) | |
end | |
end | |
function Canvas:isTouchedBy(touch) | |
self.drawnon = true | |
return self.drawable:isTouchedBy(touch) | |
end | |
function Canvas:processTouches(g) | |
self.drawable:processTouches(g) | |
end | |
function Canvas:draw() | |
pushMatrix() | |
TransformOrientation(PORTRAIT) | |
local w,h = RectAnchorOf(Portrait,"size") | |
self.drawable:predraw() | |
if self.drawable:isFinished() then | |
self:drawcanvas() | |
end | |
pushStyle() | |
noSmooth() | |
blendMode(NORMAL) | |
--background(255, 255, 255, 255) | |
self.bgmesh:draw() | |
fill(self.style.bgcolour) | |
noStroke() | |
rectMode(CORNER) | |
rect(0,0,w,h) | |
self.canvasmesh:draw() | |
--blendMode(unpack(self.style.blendmode)) | |
self.drawable:draw() | |
--blendMode(NORMAL) | |
popStyle() | |
popMatrix() | |
if not self.hidden then | |
self.drawable:drawIcon() | |
end | |
end | |
function Canvas:drawcanvas() | |
pushStyle() | |
pushMatrix() | |
resetStyle() | |
resetMatrix() | |
noSmooth() | |
setContext(self.undoimage) | |
blendMode(NORMAL) | |
background(Colour.transparent) | |
self.canvasmesh:draw() | |
setContext() | |
-- local cvs = image(Portrait[3],Portrait[4]) | |
-- debug:log({name = "canvas", message = function() return cvs.width .. "," .. cvs.height end}) | |
self:setLineAlpha(100) | |
setContext(self.cvs) | |
blendMode(NORMAL) | |
background(Colour.transparent) | |
self.drawable:bake() | |
setContext() | |
self.cvsmesh:setColors(Colour.opacity( | |
Colour.svg.White,self.style.alpha)) | |
setContext(self.canvas) | |
blendMode(unpack(self.style.blendmode)) | |
self.cvsmesh:draw() | |
setContext() | |
self.drawable:clear() | |
self.undoable = true | |
self.redoable = false | |
self.undo = false | |
popMatrix() | |
popStyle() | |
self:setLineAlpha() | |
end | |
function Canvas:clear() | |
setContext(self.canvas) | |
background(Colour.transparent) | |
setContext() | |
setContext(self.undoimage) | |
background(Colour.transparent) | |
setContext() | |
self.drawable:clear() | |
self.drawnon = false | |
end | |
function Canvas:saveStyle() | |
local t = {} | |
for k,v in pairs(self.style) do | |
t[k] = v | |
end | |
t.drawable = self.drawable:getName() | |
return t | |
end | |
function Canvas:setStyle(t) | |
if t.drawable then | |
self:setBrush(t.drawable) | |
t.drawable = nil | |
end | |
for k,v in pairs(t) do | |
self.style[k] = v | |
end | |
self:setLineAlpha() | |
end | |
cmodule.gexport { | |
JOINNONE = JOINNONE, | |
JOINMOVE = JOINMOVE, | |
JOINLINE = JOINLINE, | |
CAPNONE = CAPNONE, | |
CAPSQUARE = CAPSQUARE, | |
CAPBUTT = CAPBUTT, | |
CAPROUND = CAPROUND, | |
BLENDS = BLENDS | |
} | |
return Canvas | |
--]==] |
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
--[[ | |
ChangeLog | |
========= | |
v2.1 Uploaded wrong project! | |
v2.0 Converted to toadkick's cmodule class for importing | |
--]] |
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
-- Chrome | |
--[==[ | |
local BrushEx = cimport "BrushEx" | |
local Colour = unpack(cimport (BaseLib .. "Colour")) | |
local Chrome = class(BrushEx) | |
function Chrome:init(tb) | |
BrushEx.init(self,"Chrome",tb) | |
self.ntouches = 0 | |
end | |
function Chrome:stroke(x,id,t) | |
self:basicStroke(x,id,t) | |
local c = Colour.opacity(self.style.colour,20) | |
if self.lines[id] then | |
local dx, d, a | |
local l = self.lines[id].start - x | |
for i = 1, self.count do | |
dx = self.points[i] - x | |
d = dx:lenSqr() | |
a = math.abs(dx:angleBetween(l)) | |
if d < 1000 and a > .1 then | |
self:addLine({ | |
start = x + dx * 0.2, | |
finish = self.points[i] - dx * 0.2, | |
colour = c, | |
ends = true | |
}) | |
end | |
end | |
end | |
end | |
return Chrome | |
--]==] |
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
-- Discs | |
--[==[ | |
local Brush = cimport "Brush" | |
local Discs = class(Brush) | |
function Discs:init(tb) | |
Brush.init(self,"Discs",tb) | |
end | |
function Discs:stroke(x,id,t) | |
local dx = x - self.lines[id].finish | |
self.lines[id].finish = x | |
local d = 2*dx:len() | |
local cx = math.floor(x.x / 100) * 100 + 50 | |
local cy = math.floor(x.y / 100) * 100 + 50 | |
local c = vec2(cx,cy) | |
local steps = math.floor( math.random() * 10 ) | |
local step_delta = d / steps | |
for i = 0, steps do | |
self:addCircle({ | |
centre = c, | |
radius = (steps - i) * step_delta | |
}) | |
end | |
end | |
return Discs | |
--]==] |
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
-- Circles | |
--[==[ | |
local Brush = cimport "Brush" | |
local Circles = class(Brush) | |
function Circles:init(tb) | |
Brush.init(self,"Circles",tb) | |
end | |
function Circles:stroke(x,id,t) | |
local dx = x - self.lines[id].finish | |
self.lines[id].finish = x | |
local dist = dx:len() | |
self:addCircle({ | |
centre = x, | |
radius = dist * self.style.thickness / 2, | |
thickness = self.style.thickness / 4 | |
}) | |
end | |
return Circles | |
--]==] |
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
--[==[ | |
local Drawable = class() | |
function Drawable:init(name,tb) | |
self.style = tb.style | |
self.name = name | |
end | |
function Drawable:draw() | |
end | |
function Drawable:predraw() | |
end | |
function Drawable:getName() | |
return self.name | |
end | |
function Drawable:isTouchedBy(touch) | |
return true | |
end | |
function Drawable:processTouches(g) | |
g:noted() | |
end | |
function Drawable:bake() | |
self:draw() | |
end | |
function Drawable:isFinished() | |
return self.isfinished | |
end | |
function Drawable:drawIcon() | |
end | |
function Drawable:setAlpha(aim) | |
end | |
function Drawable:reset() | |
end | |
function Drawable:undo() | |
end | |
function Drawable:redo() | |
end | |
function Drawable:clear() | |
self.isfinished = false | |
end | |
function Drawable:updateStyle() | |
end | |
return Drawable | |
--]==] |
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
-- FlowLines, version 1 | |
--[==[ | |
local Brush = cimport "Brush" | |
cimport (BaseLib .. "NumberSpinner") | |
local Colour = unpack(cimport (BaseLib .. "Colour")) | |
cimport (BaseLib .. "ColourNames") | |
local FlowLines = class(Brush) | |
function FlowLines:init(tb) | |
Brush.init(self,"Flow Lines",tb) | |
self.ntouches = 0 | |
local om = tb.ui:addMenu({}) | |
for _,v in ipairs({ | |
{"Swirls", "swirls",0.001, 1, 0.01}, | |
{"Length of path", "framesToLive", 1, 600, 20}, | |
{"Curliness", "curliness", 1, 16, .1}, | |
{"Speed", "gspeed", 0.1, 5, 5}, | |
{"Size", "gsize", 0.1, 50, 1.5}, | |
{"Brightness Variation", "varyBrightness", 0.0, 1.0, 0.45} | |
}) do | |
om:addItem({ | |
title = v[1], | |
action = function() | |
tb.ui:getNumberSpinner({ | |
value = self[v[2]], | |
action = function(n) | |
self[v[2]] = n | |
return true | |
end, | |
maxvalue = v[4], | |
minvalue = v[3] | |
}) | |
return true | |
end, | |
}) | |
self[v[2]] = v[5] | |
end | |
self.menu = om | |
om:isChildOf(tb.brushstylemenu) | |
self.seed = math.random(1000) | |
self.lastpts = {} | |
end | |
function FlowLines:clear() | |
Brush.clear(self) | |
self.seed = math.random(1000) | |
self.lastpts = {} | |
end | |
function FlowLines:stroke(x,id,t) | |
local v = 1.0 - self.varyBrightness * math.random() | |
local rc = Colour.shade(self.style.colour,v*100) | |
if self.lastpts[id] then | |
local dx = x - self.lastpts[id] | |
local l = dx:len() | |
dx = dx:normalize() | |
local sw = self.swirls | |
local s = self.seed | |
local speedRnd = self.gspeed * ( 1+ math.random()/2) | |
local r = 2 + self.gsize * ( 1 + math.random(-1,1)/2) | |
local angle = math.pi * self.curliness * (1+l)/(.5+l) | |
local px,sx,bx,ex,ax,sa,ea,st,et | |
local pts = {} | |
ex = x | |
ea = 100 | |
px = noise((s+ex.x)*sw, (s+ex.y)*sw) | |
dx = dx:rotate(px * angle) | |
ax = ex - dx * speedRnd | |
et = self.style.thickness | |
for i = 1,self.framesToLive do | |
if | |
x.x < 0 or | |
x.x > RectAnchorOf(Portrait,"width") or | |
x.y < 0 or | |
x.y > RectAnchorOf(Portrait,"height") | |
then | |
break | |
end | |
bx = sx | |
sx = ex | |
ex = ax | |
sa = ea | |
st = et | |
px = noise((s+ex.x)*sw, (s+ex.y)*sw) | |
dx = dx:rotate(px * angle) | |
ax = ax - dx * speedRnd * (1 - .1*math.random()) | |
ea = (1 - i / self.framesToLive) * 100 | |
et = (1 - i / self.framesToLive) * self.style.thickness | |
self:addLine({ | |
before = bx, | |
start = sx, | |
finish = ex, | |
after = ax, | |
colour = rc, | |
startOpacity = sa, | |
endOpacity = ea, | |
startThickness = st, | |
endThickness = et, | |
startCap = CAPNONE, | |
endCap = CAPNONE | |
}) | |
end | |
end | |
self.lastpts[id] = x | |
end | |
return FlowLines | |
--]==] |
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
-- Fur | |
--[==[ | |
local BrushEx = cimport "BrushEx" | |
local Colour = unpack(cimport (BaseLib .. "Colour")) | |
local Fur = class(BrushEx) | |
function Fur:init(tb) | |
BrushEx.init(self,"Fur",tb) | |
end | |
function Fur:stroke(x,id,t) | |
self:basicStroke(x,id,t) | |
local c = Colour.opacity(self.style.colour,20) | |
local dx, d | |
for i = 1, self.count do | |
dx = self.points[i] - x | |
d = dx:lenSqr() | |
if d < 2000 and math.random() > d/2000 then | |
self:addLine({ | |
start = x + dx * 0.5, | |
finish = x - dx * 0.5, | |
colour = c, | |
ends = true | |
}) | |
end | |
end | |
end | |
return Fur | |
--]==] |
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
--[[ | |
HarmonyCodea | |
Original code Copyright (c) 2012 Luca Ferrara | |
Modifications Copyright (c) 2012 Andrew Stacey | |
Permission is hereby granted, free of charge, to any person | |
obtaining a copy of this software and associated documentation | |
files (the "Software"), to deal in the Software without | |
restriction, including without limitation the rights to use, | |
copy, modify, merge, publish, distribute, sublicense, and/or sell | |
copies of the Software, and to permit persons to whom the | |
Software is furnished to do so, subject to the following | |
conditions: | |
The above copyright notice and this permission notice shall be | |
included in all copies or substantial portions of the Software. | |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES | |
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT | |
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | |
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |
OTHER DEALINGS IN THE SOFTWARE. | |
--]] | |
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
-- LongFur | |
--[==[ | |
local BrushEx = cimport "BrushEx" | |
local Colour = unpack(cimport (BaseLib .. "Colour")) | |
local LongFur = class(BrushEx) | |
function LongFur:init(tb) | |
BrushEx.init(self,"Long Fur",tb) | |
end | |
function LongFur:stroke(x,id,t) | |
self:basicStroke(x,id,t) | |
local c = Colour.opacity(self.style.colour,10) | |
local dx, d | |
for i = 1, self.count do | |
size = -math.random() | |
dx = self.points[i] - x | |
d = dx:lenSqr() | |
if d < 4000 and math.random() > d/4000 then | |
self:addLine({ | |
start = x + dx * size, | |
finish = x - dx * size, | |
colour = c, | |
ends = true | |
}) | |
end | |
end | |
end | |
return LongFur | |
--]==] |
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
-- Main | |
--[[ | |
To load pictures for selection as background images: | |
1. Click on the brackets: sprite() to bring up the selector | |
2. Select "Documents" | |
3. Select "Photo Library" | |
4. Choose your photo | |
5. Name it | |
6. Repeat from 3 to select more | |
7. Click outside the sprite selector to dismiss it | |
--]] | |
supportedOrientations(ANY) | |
displayMode(FULLSCREEN_NO_BUTTONS) | |
BaseLib = "Library CModule:" | |
VERSION = 2.1 | |
function setup() | |
AutoGist.setProjectInfo("Harmony CModule","Andrew Stacey","A drawing application with lots of brush styles.",VERSION) | |
AutoGist.backup(true) | |
cmodule "Harmony CModule" | |
local Touches = cimport (BaseLib .. "Touch") | |
local UI = cimport (BaseLib .. "UI") | |
local Debug = cimport (BaseLib .. "Debug") | |
local Canvas = cimport "Canvas" | |
touches = Touches() | |
ui = UI(touches) | |
ui:systemmenu() | |
ui:helpmenu() | |
debug = Debug({ui = ui}) | |
ui.messages:deactivate() | |
canvas = Canvas({ | |
ui = ui, | |
touchHandler = touches, | |
debug = debug, | |
--[[ | |
enableText = false, | |
enablePictures = false, | |
brushes = {"Simple","Flow Lines"} | |
--]] | |
}) | |
orientationChanged = _orientationChanged | |
end | |
function draw() | |
background(0, 0, 0, 255) | |
touches:draw() | |
canvas:draw() | |
ui:draw() | |
debug:draw() | |
AtEndOfDraw() | |
end | |
function touched(touch) | |
touches:addTouch(touch) | |
end | |
function _orientationChanged(o) | |
ui:orientationChanged(o) | |
debug:orientationChanged(o) | |
end | |
function hide() | |
ui:hide(5) | |
canvas:hide() | |
debug:hide() | |
end | |
function unhide() | |
ui:unhide() | |
canvas:unhide() | |
debug:unhide() | |
end |
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
--[==[ | |
local Drawable = cimport "Drawable" | |
cimport (BaseLib .. "PictureBrowser") | |
local Colour = unpack(cimport (BaseLib .. "Colour")) | |
cimport (BaseLib .. "ColourNames") | |
cimport (BaseLib .. "CubicSelector") | |
local Picture = class(Drawable) | |
local pictureShader | |
function Picture:init(tb,ui) | |
Drawable.init(self,"Picture",tb) | |
self.mesh = mesh() | |
self.shader = shader() | |
self.shader.vertexProgram,self.shader.fragmentProgram = pictureShader() | |
self:updateStyle() | |
ui:getPicture( | |
function(i) | |
self:setpicture(i) | |
return true | |
end | |
) | |
self.debug = 0 | |
debug:log({ name = "Drawing", | |
message = function() return self.debug end}) | |
end | |
function Picture:setpicture(i) | |
self.mesh.texture = i | |
self.mesh.shader = self.shader | |
local c = Colour.svg.White | |
local w,h = i.width, i.height | |
local s = math.min(1, | |
RectAnchorOf(Portrait,"width")/(2*w), | |
RectAnchorOf(Portrait,"height")/(2*h) | |
) | |
local x,y = RectAnchorOf(Portrait,"centre") | |
w,h = s*w/2,s*h/2 | |
self.corners = { | |
{vec2(x-w,y-h),c,vec2(0,0)}, | |
{vec2(x-w,y+h),c,vec2(0,1)}, | |
{vec2(x+w,y-h),c,vec2(1,0)}, | |
{vec2(x+w,y+h),c,vec2(1,1)}, | |
} | |
addQuad({ | |
mesh = self.mesh, | |
vertices = self.corners, | |
}) | |
end | |
function Picture:draw() | |
self.mesh:draw() | |
end | |
function Picture:isTouchedBy(touch) | |
local a = self.corners[1][1] | |
local b = self.corners[2][1] - a | |
local c = self.corners[3][1] - a | |
local t = vec2(touch.x,touch.y) - a | |
a = b:cross(c) | |
if a == 0 then | |
return false | |
end | |
b = b:cross(t)/a | |
if b < 0 or b > 1 then | |
return false | |
end | |
c = - c:cross(t)/a | |
if c < 0 or c > 1 then | |
return false | |
end | |
return true | |
end | |
function Picture:processTouches(g) | |
if g.updated then | |
local c = {} | |
if g.num == 1 then | |
local ta = g.touchesArr[1] | |
local sa = OrientationInverse(PORTRAIT, | |
vec2(ta.firsttouch.x,ta.firsttouch.y)) | |
local ea = OrientationInverse(PORTRAIT, | |
vec2(ta.touch.x,ta.touch.y)) | |
for k,v in ipairs(self.corners) do | |
c[k] = {v[1] + ea - sa} | |
end | |
elseif g.num == 2 then | |
local ta,tb = g.touchesArr[1],g.touchesArr[2] | |
local sa = OrientationInverse(PORTRAIT, | |
vec2(ta.firsttouch.x,ta.firsttouch.y)) | |
local ea = OrientationInverse(PORTRAIT, | |
vec2(ta.touch.x,ta.touch.y)) | |
local sb = OrientationInverse(PORTRAIT, | |
vec2(tb.firsttouch.x,tb.firsttouch.y)) | |
local eb = OrientationInverse(PORTRAIT, | |
vec2(tb.touch.x,tb.touch.y)) | |
local s = (eb - ea):len()/ (sb - sa):len() | |
local ang = (sb - sa):angleBetween(eb - ea) | |
local sc = (sb + sa)/2 | |
local ec = (ea + eb)/2 | |
for k,v in ipairs(self.corners) do | |
c[k] = {s*(v[1]-sc):rotate(ang) + ec} | |
end | |
end | |
addQuad({ | |
mesh = self.mesh, | |
position = 0, | |
vertices = c, | |
}) | |
if g.type.ended then | |
self.corners = c | |
end | |
end | |
if g.type.ended then | |
g:reset() | |
end | |
end | |
function Picture:updateStyle() | |
for k,v in pairs(self.style.picture) do | |
self.shader[k] = v | |
end | |
end | |
pictureShader = function() | |
return [[ | |
// | |
// A basic vertex shader | |
// | |
//This is the current model * view * projection matrix | |
// Codea sets it automatically | |
uniform mat4 modelViewProjection; | |
//This is the current mesh vertex position, color and tex coord | |
// Set automatically | |
attribute vec4 position; | |
attribute vec4 color; | |
attribute vec2 texCoord; | |
//This is an output variable that will be passed to the fragment shader | |
varying lowp vec4 vColor; | |
varying highp vec2 vTexCoord; | |
void main() | |
{ | |
//Pass the mesh color to the fragment shader | |
vColor = color; | |
vTexCoord = vec2(texCoord.x, texCoord.y); | |
//Multiply the vertex position by our combined transform | |
gl_Position = modelViewProjection * position; | |
} | |
]],[[ | |
// | |
// A basic fragment shader | |
// | |
//This represents the current texture on the mesh | |
uniform lowp sampler2D texture; | |
uniform lowp vec4 red; | |
uniform lowp vec4 green; | |
uniform lowp vec4 blue; | |
uniform lowp vec4 alpha; | |
uniform lowp vec4 redcurve; | |
uniform lowp vec4 greencurve; | |
uniform lowp vec4 bluecurve; | |
uniform lowp vec4 alphacurve; | |
uniform lowp vec4 brightness; | |
mediump vec4 csat = red + green + blue + alpha; | |
mediump float cnorm = max(max(max(1.,csat.r),csat.g),csat.b); | |
//The interpolated vertex color for this fragment | |
varying lowp vec4 vColor; | |
//The interpolated texture coordinate for this fragment | |
varying highp vec2 vTexCoord; | |
lowp float cubic(lowp vec4 c, lowp float t) | |
{ | |
return c.x + c.y * t + c.z * t * t + c.w * t * t * t; | |
} | |
void main() | |
{ | |
//Sample the texture at the interpolated coordinate | |
mediump vec4 col = texture2D( texture, vTexCoord ); | |
col *= vColor; | |
col.r = cubic(redcurve, col.r); | |
col.g = cubic(greencurve, col.g); | |
col.b = cubic(bluecurve, col.b); | |
col.a = cubic(alphacurve, col.a); | |
col.r = cubic(brightness, col.r); | |
col.g = cubic(brightness, col.g); | |
col.b = cubic(brightness, col.b); | |
col = col.r * red + col.g * green + col.b * blue + col.a * alpha; | |
col.rgb = col.rgb/cnorm; | |
//Set the output color to the texture color | |
gl_FragColor = col; | |
} | |
]] | |
end | |
return Picture | |
--]==] |
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
-- Shaded | |
--[==[ | |
local BrushEx = cimport "BrushEx" | |
local Colour = unpack(cimport (BaseLib .. "Colour")) | |
local Shaded = class(BrushEx) | |
function Shaded:init(tb) | |
BrushEx.init(self,"Shaded",tb) | |
end | |
function Shaded:stroke(x,id,t) | |
local dx, d | |
for i = 1, self.count do | |
dx = self.points[i] - x | |
d = dx:lenSqr() | |
if (d < 1000) then | |
self:addLine({ | |
start = x, | |
finish = self.points[i], | |
colour = Colour.opacity(self.style.colour,(1 - (d / 1000)) * 10), | |
ends = true | |
}) | |
end | |
end | |
end | |
return Shaded | |
--]==] |
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
-- Simple | |
--[==[ | |
local Brush = cimport "Brush" | |
local Simple = class(Brush) | |
function Simple:init(tb) | |
Brush.init(self,"Simple",tb) | |
end | |
function Simple:stroke(x,id,t) | |
self:basicStroke(x,id,t) | |
end | |
return Simple | |
--]==] |
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
-- Sketchy | |
--[==[ | |
local BrushEx = cimport "BrushEx" | |
local Colour = unpack(cimport (BaseLib .. "Colour")) | |
local Sketchy = class(BrushEx) | |
function Sketchy:init(tb) | |
BrushEx.init(self,"Sketchy",tb) | |
end | |
function Sketchy:stroke(x,id,t) | |
self:basicStroke(x,id,t) | |
local dx, d | |
for i = 1, self.count do | |
dx = self.points[i] - x | |
d = dx:lenSqr() | |
if (d < 4000 and math.random() > (d/2000)) then | |
self:addLine({ | |
start = x + dx * 0.3, | |
finish = self.points[i] - dx * 0.3, | |
colour = Colour.opacity(self.style.colour,(1 - (d / 1000)) * 10), | |
ends = true | |
}) | |
end | |
end | |
end | |
return Sketchy | |
--]==] |
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
-- Squares | |
--[==[ | |
local Brush = cimport "Brush" | |
local Squares = class(Brush) | |
function Squares:init(tb) | |
Brush.init(self,"Squares",tb) | |
end | |
function Squares:stroke(x,id,t) | |
local y = self.lines[id].finish | |
local dx = x - y | |
local angle = 1.57079633 | |
local p = dx:rotate(angle) | |
local corners = { | |
y - p, | |
y + p, | |
x + p, | |
x - p | |
} | |
for k=1,4 do | |
table.insert(corners,table.remove(corners,1)) | |
self:addLine({ | |
before = corners[1], | |
start = corners[2], | |
finish = corners[3], | |
after = corners[4] | |
}) | |
end | |
self.lines[id].finish = x | |
end | |
return Squares | |
--]==] |
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
-- Test | |
--[[ | |
--[==[ | |
local Brush = cimport "Brush" | |
local Test = class(Brush) | |
table.insert(Brushes,Test) | |
function Test:init(tb) | |
Brush.init(self,"Test",tb) | |
end | |
function Brush:strokeStart(x,id) | |
self.lines[id] = {} | |
self.lines.start = vec2(300,300) | |
self.lines.finish = vec2(300,400) | |
self:addline(self.lines[id]) | |
end | |
function Brush:strokeEnd(x,id) | |
if self.lines[id] then | |
t = t or {} | |
local y,th | |
local l = self.lines[id] | |
if l.start then | |
if l.start:distSqr(l.finish) > 100 | |
and math.abs((l.finish - l.start):normalize():rotate90():dot((x - l.finish):normalize())) > .2 | |
then | |
-- if true then | |
local bza,bzb | |
bza,bzb,th = QuickHobby(l.start,l.finish,x,l.th) | |
local ca = Bezierpt(1/3,unpack(bza)) | |
local cb = Bezierpt(2/3,unpack(bza)) | |
local a,b | |
if l.previousSegment then | |
if l.previousSegment.start then | |
a = (l.previousSegment.finish - | |
l.previousSegment.start):normalize() | |
b = (ca - | |
l.previousSegment.finish):normalize() | |
if a:dot(b) < -0.5 then | |
l.previousSegment.after = | |
l.previousSegment.finish - b | |
l.before = l.previousSegment.finish + a | |
else | |
l.previousSegment.after = ca | |
end | |
self:addLine(l.previousSegment) | |
end | |
end | |
local c = { | |
l.before, | |
l.start, | |
ca, | |
cb, | |
l.finish, | |
x} | |
for i=2,4 do | |
l.before = c[i-1] | |
l.start = c[i] | |
l.finish = c[i+1] | |
a = (c[i+1] - c[i]):normalize() | |
b = (c[i+2] - c[i+1]):normalize() | |
if a:dot(b) < -0.5 then | |
l.after = l.finish - b | |
c[i] = l.finish + a | |
else | |
l.after = c[i+2] | |
end | |
self:addLine(l) | |
if i ~= 4 then l.position = nil end | |
end | |
y = c[4] | |
else | |
y = l.start | |
l.after = x | |
self:addLine(l) | |
end | |
end | |
l.previousSegment = nil | |
t.start = l.finish | |
t.before = y | |
t.finish = x | |
t.th = th | |
t.previousSegment = l | |
t.startCapData = l.startCapData | |
t.endCapData = l.endCapData | |
t.startCap = l.startCap | |
t.endCap = l.endCap | |
self.lines[id] = self:addLine(t) | |
end | |
self.isfinished = false | |
end | |
return Test | |
--]==] | |
--]] |
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
--[==[ | |
local Drawable = cimport "Drawable" | |
local TextNode = cimport (BaseLib .. "TextNode") | |
local Font = unpack(cimport (BaseLib .. "Font")) | |
local TextBlock = class(Drawable) | |
function TextBlock:init(tb,ui) | |
Drawable.init(self,"TextBlock",tb) | |
self.node = TextNode({ | |
font = Font({name = self.style.font, | |
size = self.style.fontsize}), | |
textColour = self.style.txtcolour, | |
colour = self.style.txtbgcolour, | |
width = "20em", | |
maxHeight = "10lh", | |
anchor = "centre", | |
pos = function() return RectAnchorOf(Screen,"centre") end, | |
fit = true, | |
ui = ui, | |
keyboard = self.style.keyboard | |
}) | |
self.ostyle = {} | |
for _,v in ipairs({ | |
"font", | |
"fontsize", | |
"txtcolour", | |
"txtbgcolour" | |
}) do | |
self.ostyle[v] = self.style[v] | |
end | |
end | |
function TextBlock:draw() | |
pushMatrix() | |
resetMatrix() | |
self.node:draw() | |
popMatrix() | |
end | |
function TextBlock:bake() | |
self.node:setEdit(false) | |
pushMatrix() | |
TransformInverseOrientation(PORTRAIT) | |
self.node:draw() | |
popMatrix() | |
end | |
function TextBlock:isTouchedBy(touch) | |
return self.node:isTouchedBy(touch) | |
end | |
function TextBlock:processTouches(g) | |
self.node:processTouches(g) | |
end | |
function TextBlock:reset() | |
end | |
function TextBlock:updateStyle() | |
if self.style.txtcolour ~= self.ostyle.txtcolour then | |
self.node:setTextColour(self.style.txtcolour) | |
end | |
if self.style.font ~= self.ostyle.font | |
or self.style.fontsize ~= self.ostyle.fontsize then | |
self.node:setFont(Font( | |
{name = self.style.font, size = self.style.fontsize})) | |
end | |
if self.style.txtbgcolour ~= self.ostyle.txtbgcolour then | |
self.node:setColour(self.style.txtbgcolour) | |
end | |
for _,v in ipairs({ | |
"font", | |
"fontsize", | |
"txtcolour", | |
"txtbgcolour" | |
}) do | |
self.ostyle[v] = self.style[v] | |
end | |
end | |
return TextBlock | |
--]==] |
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
-- Web | |
--[==[ | |
local BrushEx = cimport "BrushEx" | |
local Colour = unpack(cimport (BaseLib .. "Colour")) | |
local Web = class(BrushEx) | |
function Web:init(tb) | |
BrushEx.init(self,"Web",tb) | |
end | |
function Web:stroke(x,id,t) | |
self:basicStroke(x,id,t) | |
local c = Colour.opacity(self.style.colour,20) | |
local dx, d | |
for i = 1, self.count do | |
dx = self.points[i] - x | |
d = dx:lenSqr() | |
if (d < 2500 and math.random() > 0.9) then | |
self:addLine({ | |
start = x + dx, | |
finish = self.points[i] - dx, | |
colour = c, | |
ends = true | |
}) | |
end | |
end | |
end | |
return Web | |
--]==] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment