-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.lua
370 lines (318 loc) · 8.61 KB
/
main.lua
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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
require "run"
require "grid"
io.stdout:setvbuf("no")
local CHARS = 8
local CHAR_WIDTH = 8
local CHAR_HEIGHT = 16
local showfps = true
local pause = false
function setFont(name)
local hinting = "mono"
local size = viewGrid.rows
while true do
if name == nil or name == "default" then
font = love.graphics.newFont(size, hinting)
else
font = love.graphics.newFont("fonts/"..name, size, hinting)
end
-- Font may be a little too big; strangely the size is just a "request"
if font:getHeight() > viewGrid.rows and size > 1 then
size = size - 1
else
break
end
end
end
function currentAction()
return actions[action]
end
function actionCommand(a)
a = a or currentAction()
return a.command
end
function actionText(a)
a = a or currentAction()
return a.text
end
function invisibleAction(a)
local cmd = actionCommand(a)
return cmd == "C" or cmd == "F" or cmd == "LC" or cmd == "DC" or cmd == "OC" or cmd == "FPS"
end
function blankWidth(a)
local text = actionText(a)
if text:len() == 0 then
return viewGrid.cols
else
return text:len()
end
end
function handleInvisibleAction()
local cmd = actionCommand()
local text = actionText()
if cmd == "C" then
viewGrid.dark_color = dark_color
viewGrid.outline_color = outline_color
viewGrid:clear()
elseif cmd == "F" then
setFont(text)
elseif cmd == "LC" then
light_color = Grid.stringToColor(text)
elseif cmd == "DC" then
dark_color = Grid.stringToColor(text)
elseif cmd == "OC" then
outline_color = Grid.stringToColor(text)
elseif cmd == "FPS" then
fps = tonumber(text)
end
end
function addAction(command, text)
actions[actions.size] = { command = command, text = text }
actions.size = actions.size + 1
end
function addActionLine(line)
if line:match("^#") then return end
if line:match("^%s*$") then return end
local command = line
local text = ""
local pos = line:find(" ")
if pos ~= nil then
command = line:sub(1, pos - 1)
text = line:sub(pos + 1, -1)
end
addAction(command, text)
end
-- Ensure there is at least one visible action; otherwise, the program will hang.
function ensureOneVisibleAction()
local haveVisibleActions = false
for i = 0, actions.size - 1 do
if not invisibleAction(actions[i]) then haveVisibleActions = true end
end
if not haveVisibleActions then addAction("S", "") end
end
function loadActions(filename)
actions = { size = 0 }
addAction("FPS", "40")
addAction("F", "default")
addAction("LC", Grid.colorToString(light_color))
addAction("DC", Grid.colorToString(dark_color))
addAction("OC", Grid.colorToString(outline_color))
local lines
if filename then
lines = io.lines(filename)
else
lines = love.filesystem.lines("messages/example.txt")
end
for line in lines do
addActionLine(line)
end
ensureOneVisibleAction()
action = -1
step = 0
steps = 1
substep = 0
substeps = 1
end
function initViewGrid()
viewGrid = Grid:new(CHARS * CHAR_WIDTH, CHAR_HEIGHT, light_color, dark_color, outline_color)
viewGrid:clear()
end
function love.load(arg)
light_color = { 0.85, 0, 0 }
dark_color = { 0, 0, 0 }
outline_color = { 1, 0.5, 0.5 }
initViewGrid()
setFont()
loadActions(arg[1])
end
function love.keypressed(key, scancode, isrepeat)
if key == "escape" then
love.event.quit()
elseif key == "f" then
love.window.setFullscreen(not love.window.getFullscreen())
elseif key == "f1" then
showfps = not showfps
elseif key == "space" then
pause = not pause
end
end
function calculateActionSteps()
steps = 1
substeps = 1
local cmd = actionCommand()
local text = actionText()
if cmd == "W" then
steps = math.floor(fps * tonumber(text))
if steps < 1 then steps = 1 end
elseif cmd == "S" then
steps = 1
elseif cmd == "SL" or cmd == "SR" then
steps = sourceGrid.cols
elseif cmd == "SU" or cmd == "SD" then
steps = sourceGrid.rows
end
-- TODO
end
function updateSourceGrid()
-- Create text drawing object with the text of the current action.
local text = love.graphics.newText(font, actionText())
-- Create canvas to hold text.
local width = text:getWidth()
local height = viewGrid.rows -- should match text:getHeight()
if width < 1 then width = blankWidth() end
local canvas = love.graphics.newCanvas(width, height)
-- Print text on canvas.
canvas:renderTo(function()
love.graphics.setColor(1, 1, 1)
love.graphics.draw(text)
end);
-- Copy canvas to source grid.
local imageData = canvas:newImageData()
sourceGrid = Grid:new(width, height, light_color, dark_color, outline_color)
for row = 0, sourceGrid.rows - 1 do
for col = 0, sourceGrid.cols - 1 do
local r, g, b = imageData:getPixel(col, row)
if r == 1 and g == 1 and b == 1 then
sourceGrid:setLightDot(col, row)
else
sourceGrid:setDarkDot(col, row)
end
end
end
end
function moveToNextStep()
substep = substep + 1
if substep >= substeps then
substep = 0
step = step + 1
if step >= steps then
step = 0
action = action + 1
if action >= actions.size then action = 0 end
if invisibleAction() then
handleInvisibleAction()
else
updateSourceGrid()
end
calculateActionSteps()
end
end
end
-- returns padLeft, columns
function centerSource()
if sourceGrid.cols > viewGrid.cols then
return 0, viewGrid.cols
else
return math.floor((viewGrid.cols - sourceGrid.cols) / 2), sourceGrid.cols
end
end
function updateViewGrid_Show()
local padLeft, cols = centerSource()
for row = 0, viewGrid.rows - 1 do
for col = 0, cols - 1 do
local dot = sourceGrid:getDot(col, row)
viewGrid:setDot(padLeft + col, row, dot)
end
end
end
function updateViewGrid_ScrollLeft()
viewGrid:scrollLeft()
local col = viewGrid.cols - 1
for row = 0, viewGrid.rows - 1 do
local dot = sourceGrid:getDot(step, row)
viewGrid:setDot(col, row, dot)
end
end
function updateViewGrid_ScrollRight()
viewGrid:scrollRight()
local col = 0
for row = 0, viewGrid.rows - 1 do
local dot = sourceGrid:getDot(sourceGrid.cols - 1 - step, row)
viewGrid:setDot(col, row, dot)
end
end
function updateViewGrid_ScrollUp()
viewGrid:scrollUp()
local padLeft, cols = centerSource()
local row = viewGrid.rows - 1
for col = 0, padLeft - 1 do
viewGrid:setDarkDot(col, row)
end
for col = 0, cols - 1 do
local dot = sourceGrid:getDot(col, step)
viewGrid:setDot(padLeft + col, row, dot)
end
for col = padLeft + cols, viewGrid.cols - 1 do
viewGrid:setDarkDot(col, row)
end
end
function updateViewGrid_ScrollDown()
viewGrid:scrollDown()
local padLeft, cols = centerSource()
local row = 0
for col = 0, padLeft - 1 do
viewGrid:setDarkDot(col, row)
end
for col = 0, cols - 1 do
local dot = sourceGrid:getDot(col, sourceGrid.rows - 1 - step)
viewGrid:setDot(padLeft + col, row, dot)
end
for col = padLeft + cols, viewGrid.cols - 1 do
viewGrid:setDarkDot(col, row)
end
end
function updateViewGrid()
local cmd = actionCommand()
local text = actionText()
if cmd == "W" then
-- do nothing to grid
elseif cmd == "S" then
updateViewGrid_Show()
elseif cmd == "SL" then
updateViewGrid_ScrollLeft()
elseif cmd == "SR" then
updateViewGrid_ScrollRight()
elseif cmd == "SU" then
updateViewGrid_ScrollUp()
elseif cmd == "SD" then
updateViewGrid_ScrollDown()
end
-- TODO
end
function love.update(dt)
if pause then return end
repeat
moveToNextStep()
until not invisibleAction()
updateViewGrid()
end
function drawViewGrid()
local hdiameter = (love.graphics.getWidth() - 1) / viewGrid.cols
local vdiameter = (love.graphics.getHeight() - 1) / viewGrid.rows
local diameter = math.min(hdiameter, vdiameter)
local radius = 0.82 * diameter / 2
local padTop = (love.graphics.getHeight() - viewGrid.rows * diameter) / 2
if padTop < 0 then padTop = 0 end
for row = 0, viewGrid.rows - 1 do
for col = 0, viewGrid.cols - 1 do
local x = 1 + col * diameter + radius
local y = 1 + row * diameter + radius + padTop
local dot = viewGrid:getDot(col, row)
love.graphics.setColor(dot.fill_color)
love.graphics.circle("fill", x, y, radius)
love.graphics.setColor(dot.outline_color)
love.graphics.circle("line", x, y, radius)
end
end
end
function drawFps()
local text = tostring(love.timer.getFPS())
local font = love.graphics.getFont()
local width = font:getWidth(text)
local x = love.graphics.getWidth() - width
love.graphics.setColor(1, 1, 1)
love.graphics.print(text, x, 0)
end
function love.draw()
drawViewGrid()
if showfps then drawFps() end
end