-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathcanvas.script
executable file
·138 lines (132 loc) · 5.07 KB
/
canvas.script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
function init(self)
msg.post("@render:", "clear_color", {color = vmath.vector4(1, 1, 1, 1)})
-- size of texture when scaled to nearest power of two
local width = 1024
local height = 2048
local channels = 4
-- we have to create table with next fields: buffer, width, height, channels
self.buffer_info = {
buffer = buffer.create(width * height, {{name = hash("rgba"), type = buffer.VALUE_TYPE_UINT8, count = channels}}),
width = width,
height = height,
channels = channels -- 3 for rgb, 4 for rgba
}
self.dirty = true
self.current_color = vmath.vector4(0, 0, 0, 1)
self.current_tool = "pencil"
-- drawing params
self.prev_pos = vmath.vector3()
self.resource_path = go.get("#sprite", "texture0")
self.header = {
width = width,
height = height,
type = resource.TEXTURE_TYPE_2D,
format = resource.TEXTURE_FORMAT_RGBA,
num_mip_maps = 1
}
self.rotation = 0
end
function update(self, dt)
-- update texture if it's dirty (ie we've drawn to it)
if self.dirty then
resource.set_texture(self.resource_path, self.header, self.buffer_info.buffer)
self.dirty = false
end
self.rotation = self.rotation + 1
if self.rotation > 360 then
self.rotation = 0
end
end
function on_message(self, message_id, message, sender)
if message_id == hash("change_color") then
self.current_color = message.color
if self.current_tool == "eraser" then
self.current_tool = "pencil"
end
elseif message_id == hash("change_tool") then
self.current_tool = message.tool
self.bezier_dots = {}
self.last_pos = {}
elseif message_id == hash("clear") then
drawpixels.fill(self.buffer_info, 0, 0, 0, 0)
self.dirty = true
end
end
local function color_vector_to_bytes(color)
return color.x * 255, color.y * 255, color.z * 255, color.w * 255
end
local function bytes_to_color_vector(r, g, b, a)
return vmath.vector4(r / 255, g / 255, b / 255, a / 255)
end
function on_input(self, action_id, action)
if action_id == hash("touch") then
local pos = vmath.vector3(action.x, action.y, 0)
if action.pressed then
self.drawing = true
self.touch_pos = pos
elseif action.released then
self.drawing = false
if not self.last_pos.x then
self.last_pos.x = pos.x
self.last_pos.y = pos.y
else
self.last_pos.x = nil
end
if self.current_tool == "bezier" then
if #self.bezier_dots == 2 then
self.bezier_dots = {}
else
local bz = {}
bz.x = pos.x
bz.y = pos.y
self.bezier_dots[#self.bezier_dots + 1] = bz
end
end
end
if self.drawing then
-- calculate the length and direction from the previous touch
-- position to the current position
local length = math.ceil(vmath.length(self.touch_pos - pos))
local dir = vmath.normalize(self.touch_pos - pos)
if length == 0 then
length = 1
dir = vmath.vector3(0)
end
if self.prev_pos == pos then
return false
end
self.prev_pos = self.touch_pos
-- use current tool from the previous touch position to
-- the current touch position0
while length > 0 do
local r, g, b, a = color_vector_to_bytes(self.current_color)
if self.current_tool == "pencil" then
drawpixels.pixel(self.buffer_info, self.touch_pos.x, self.touch_pos.y, r, g, b, a)
elseif self.current_tool == "colorpicker" then
local r,g,b,a = drawpixels.color(self.buffer_info, self.touch_pos.x, self.touch_pos.y)
self.current_color = bytes_to_color_vector(r, g, b, a)
elseif self.current_tool == "circle" then
drawpixels.circle(self.buffer_info, self.touch_pos.x, self.touch_pos.y, 40, r, g, b, a)
elseif self.current_tool == "line" and self.last_pos.x then
drawpixels.line(self.buffer_info, self.last_pos.x, self.last_pos.y, self.touch_pos.x, self.touch_pos.y, r, g, b, a)
elseif self.current_tool == "filled_circle" then
drawpixels.filled_circle(self.buffer_info, self.touch_pos.x, self.touch_pos.y, 40, r, g, b, a)
elseif self.current_tool == "rect" then
drawpixels.rect(self.buffer_info, self.touch_pos.x, self.touch_pos.y, 40, 60, r, g, b, a)
elseif self.current_tool == "filled_rect" then
drawpixels.filled_rect(self.buffer_info, self.touch_pos.x, self.touch_pos.y, 60, 40, r, g, b, a)
elseif self.current_tool == "eraser" then
drawpixels.rect(self.buffer_info, self.touch_pos.x, self.touch_pos.y, 40, 40, 0, 0, 0, 0)
elseif self.current_tool == "rotated_rect" then
drawpixels.filled_rect(self.buffer_info, self.touch_pos.x, self.touch_pos.y, 60, 40, r, g, b, a, self.rotation)
elseif self.current_tool == "bezier" and #self.bezier_dots == 2 then
local pos = self.bezier_dots
drawpixels.bezier(self.buffer_info, pos[1].x, pos[1].y, self.touch_pos.x, self.touch_pos.y, pos[2].x, pos[2].y, r, g, b, a)
end
self.dirty = true
self.touch_pos = self.touch_pos - dir
length = length - 1
end
end
end
end