diff --git a/alignedlabels.lua b/alignedlabels.lua index d86b955..d982d26 100644 --- a/alignedlabels.lua +++ b/alignedlabels.lua @@ -1,4 +1,4 @@ -local _tl_compat; if (tonumber((_VERSION or ''):match('[%d.]*$')) or 0) < 5.3 then local p, m = pcall(require, 'compat53.module'); if p then _tl_compat = m end end; local assert = _tl_compat and _tl_compat.assert or assert; local ipairs = _tl_compat and _tl_compat.ipairs or ipairs; local pairs = _tl_compat and _tl_compat.pairs or pairs; local string = _tl_compat and _tl_compat.string or string; require("love") +local _tl_compat; if (tonumber((_VERSION or ''):match('[%d.]*$')) or 0) < 5.3 then local p, m = pcall(require, 'compat53.module'); if p then _tl_compat = m end end; local assert = _tl_compat and _tl_compat.assert or assert; local ipairs = _tl_compat and _tl_compat.ipairs or ipairs; local math = _tl_compat and _tl_compat.math or math; local pairs = _tl_compat and _tl_compat.pairs or pairs; local string = _tl_compat and _tl_compat.string or string; require("love") local g = love.graphics @@ -82,15 +82,16 @@ function AlignedLabels:draw(x, y) g.print(v, i - self.font:getWidth(v) / 2, y) i = i + dw elseif type(v) == "table" then - local width = 0 + local width = 0. for _, g in ipairs(v) do width = width + self.font:getWidth(g) end - assert(#(v) == #self.colors[k]) + + assert(#(v) == #self.colors[math.floor(k)]) local xpos = i - width / 2 for j, p in pairs(v) do - g.setColor(self.colors[k][j]) + g.setColor(self.colors[math.floor(k)][math.floor(j)]) g.print(p, xpos, y) xpos = xpos + self.font:getWidth(p) end diff --git a/alignedlabels.tl b/alignedlabels.tl index f9b8042..5b2b19c 100644 --- a/alignedlabels.tl +++ b/alignedlabels.tl @@ -78,19 +78,20 @@ function AlignedLabels:draw(x: number, y: number) g.setFont(self.font) for k, v in pairs(self.data as {any:any}) do if type(v) == "string" then - g.setColor(self.colors[k as number]) + g.setColor(self.colors[k as integer]) g.print(v as string, i - self.font:getWidth(v as string) / 2, y) i = i + dw elseif type(v) == "table" then - local width = 0 + local width = 0. for _, g in ipairs(v as {string}) do width = width + self.font:getWidth(g) end - assert(#(v as {string}) == #self.colors[k as number]) + --assert(#(v as {string}) == #self.colors[k as number]) + assert(#(v as {string}) == #self.colors[math.floor(k as number)]) local xpos = i - width / 2 for j, p in pairs(v as {any:any}) do --print(type(self.colors[k]), inspect(self.colors[k]), k, j) - g.setColor(self.colors[k as number][j as number]) + g.setColor(self.colors[math.floor(k as number)][math.floor(j as number)]) g.print(p as string, xpos, y) xpos = xpos + self.font:getWidth(p as string) end diff --git a/background.lua b/background.lua index 6ce665a..927df99 100644 --- a/background.lua +++ b/background.lua @@ -173,9 +173,9 @@ function Block:process(dt) self.active = false - self.back.blocks[self.xidx][self.yidx] = {} + self.back.blocks[math.floor(self.xidx)][math.floor(self.yidx)] = {} - self.back.blocks[self.newXidx][self.newYidx] = self + self.back.blocks[math.floor(self.newXidx)][math.floor(self.newYidx)] = self self.oldXidx, self.oldYidx = self.xidx, self.yidx self.xidx = self.newXidx self.yidx = self.newYidx @@ -291,7 +291,7 @@ function Background:fillGrid() local fieldWidth, fieldHeight = #self.blocks, #self.blocks[1] self.execList = {} - for i = 1, self.emptyNum do + for _ = 1, self.emptyNum do local xidx = math.random(1, fieldWidth) local yidx = math.random(1, fieldHeight) @@ -325,7 +325,7 @@ function Background:update(dt) print(string.format("v.xidx = %d, v.yidx = %d", v.xidx, v.yidx)) - local x, y = self:findDirection(xidx, yidx) + local x, y = self:findDirection(math.floor(xidx), math.floor(yidx)) diff --git a/background.tl b/background.tl index 33e4daf..0be37e4 100644 --- a/background.tl +++ b/background.tl @@ -173,9 +173,9 @@ function Block:process(dt: number): boolean -- приехали -- флаг ничего не делает, влияет только на рисовку обводки блока. self.active = false - self.back.blocks[self.xidx][self.yidx] = {} + self.back.blocks[math.floor(self.xidx)][math.floor(self.yidx)] = {} --print("self.newXidx, self.newYidx", self.newXidx, self.newYidx) - self.back.blocks[self.newXidx][self.newYidx] = self + self.back.blocks[math.floor(self.newXidx)][math.floor(self.newYidx)] = self self.oldXidx, self.oldYidx = self.xidx, self.yidx self.xidx = self.newXidx self.yidx = self.newYidx @@ -186,7 +186,7 @@ function Block:process(dt: number): boolean return ret end -function Background:get(xidx: number, yidx: number): Block +function Background:get(xidx: integer, yidx: integer): Block local firstColumn = self.blocks[1] --print("xidx, yidx", xidx, yidx) if xidx >= 1 and xidx <= #self.blocks and @@ -203,7 +203,7 @@ end -- Как можно разделить функцию на две части? -- Скажем одна делает обращение к массиву с проверкой границ и отладочным -- выводом, а другая - занимается поиском подходящей ячейки. -function Background:findDirection(xidx: number, yidx: number): number, number +function Background:findDirection(xidx: integer, yidx: integer): integer, integer local x, y = xidx, yidx -- почему-то иногда возвращает не измененный результат, тот же, что и ввод. -- приводит к падению программы @@ -291,7 +291,7 @@ function Background:fillGrid() local fieldWidth, fieldHeight = #self.blocks, #self.blocks[1] self.execList = {} - for i = 1, self.emptyNum do + for _ = 1, self.emptyNum do -- случайный пустой блок, куда будет двигаться сосед local xidx = math.random(1, fieldWidth) local yidx = math.random(1, fieldHeight) @@ -325,7 +325,7 @@ function Background:update(dt: number) print(string.format("v.xidx = %d, v.yidx = %d", v.xidx, v.yidx)) -- поиск индексов нового блока по новым рассчитанным индексам - local x, y = self:findDirection(xidx, yidx) + local x, y = self:findDirection(math.floor(xidx), math.floor(yidx)) --print(string.format("x - xidx = %d, y - yidx = %d", xidx, yidx)) --print(string.format("xidx = %d, yidx = %d", xidx, yidx)) --print(string.format("xidx - x = %d, yidx - y = %d", diff --git a/cmn.lua b/cmn.lua index e3776d1..ec33139 100644 --- a/cmn.lua +++ b/cmn.lua @@ -1,8 +1,9 @@ local _tl_compat; if (tonumber((_VERSION or ''):match('[%d.]*$')) or 0) < 5.3 then local p, m = pcall(require, 'compat53.module'); if p then _tl_compat = m end end; local ipairs = _tl_compat and _tl_compat.ipairs or ipairs; local pairs = _tl_compat and _tl_compat.pairs or pairs; local string = _tl_compat and _tl_compat.string or string; require("love") require("nbtypes") require("constants") + local i18n = require("i18n") -local gooi = require("gooi.gooi") + local serpent = require("serpent") @@ -11,6 +12,29 @@ onAndroid = love.system.getOS() == "Android" useKeyboard = true preventiveFirstRun = true +require("pviewer") +require("menu") +require("help") +require("tiledbackground") + + + + + + + +function initGlobals() + menu = require("menu").new() + pviewer = require("pviewer").new() + help = require("help").new() + + tiledback = require("tiledbackground"):new() +end + + + + + function pack(...) return { ... } end @@ -100,21 +124,40 @@ function percentage(signals, pressed) end -function storeGooi() - local g = { components = gooi.components } - gooi.components = {} - return g + + + + + + + + + + + + + + + + +function storeUI() + + + + + + return {} end -function restoreGooi(g) +function restoreUI(g) if g == nil then error("g == nil") end - gooi.components = g.components + end function compareDates(now, date) @@ -132,7 +175,7 @@ function compareDates(now, date) local result = i18n("moreTime") - local t1, t2, diff = now.yday * 24 + now.hour, date.yday * 24 + date.hour, 0 + local t1, t2, diff = now.yday * 24 + now.hour, date.yday * 24 + date.hour, 0. if date.year == now.year then diff = t1 - t2 else @@ -163,11 +206,11 @@ function readSettings() local result if data then - local ok, func = serpent.load(data) + local ok, res = serpent.load(data) if not ok then result = getDefaultSettings() else - result = func() + result = res end else result = getDefaultSettings() diff --git a/cmn.tl b/cmn.tl index 5bd1a16..6e7c679 100644 --- a/cmn.tl +++ b/cmn.tl @@ -3,7 +3,7 @@ require "nbtypes" require "constants" local i18n = require "i18n" -local gooi = require "gooi.gooi" +--local gooi = require "gooi.gooi" local serpent = require "serpent" global settings: Settings @@ -12,6 +12,29 @@ global onAndroid = love.system.getOS() == "Android" global useKeyboard = true global preventiveFirstRun = true +require "pviewer" +require "menu" +require "help" +require "tiledbackground" + +global menu: Menu +global pviewer: Pviewer +global help: Help +global tiledback: TiledBackround +--global nback: Nback + +function initGlobals() + menu = require "menu".new() + pviewer = require "pviewer".new() + help = require "help".new() + --nback = require "nback".new() + tiledback = require "tiledbackground":new() +end + +--return { + --initGlobals = initGlobals, +--} + function pack(...: any): any return {...} end @@ -101,6 +124,7 @@ function percentage(signals: Signals, pressed: Signals.Eq): Percentage end --require "deepcopy" +--[[ function storeGooi(): Gooi --local g = { components = deepcopy(gooi.components) } --print("gooi.components", inspect(gooi.components)) @@ -117,6 +141,24 @@ function restoreGooi(g: Gooi) --assert(g) gooi.components = g.components end +--]] + +function storeUI(): any + --local g = { components = deepcopy(gooi.components) } + --print("gooi.components", inspect(gooi.components)) + --local g = { components = table.deepcopy(gooi.components) } + --local g = { components = gooi.components } + --gooi.components = {} + return {} +end + +function restoreUI(g: any) + if g == nil then + error("g == nil") + end + --assert(g) + --gooi.components = g.components +end function compareDates(now: Date, date: Date): string local ranges = { @@ -133,7 +175,7 @@ function compareDates(now: Date, date: Date): string local result = i18n("moreTime") --print("now", inspect(os.date("*t"))) --print("date", inspect(date)) - local t1, t2, diff = now.yday * 24 + now.hour, date.yday * 24 + date.hour, 0 + local t1, t2, diff = now.yday * 24 + now.hour, date.yday * 24 + date.hour, 0. if date.year == now.year then diff = t1 - t2 else @@ -164,11 +206,11 @@ function readSettings(): Settings local result: Settings if data then - local ok, func = serpent.load(data) + local ok, res = serpent.load(data) if not ok then result = getDefaultSettings() else - result = func() as Settings + result = res as Settings end else result = getDefaultSettings() diff --git a/globals.tl b/globals.tl index a8faa5c..c50effa 100644 --- a/globals.tl +++ b/globals.tl @@ -1,4 +1,5 @@ --require "nback" +--[[ require "menu" require "pviewer" require "help" @@ -21,3 +22,4 @@ end return { initGlobals = initGlobals, } +--]] diff --git a/gooi b/gooi deleted file mode 160000 index d2f075e..0000000 --- a/gooi +++ /dev/null @@ -1 +0,0 @@ -Subproject commit d2f075e5ffa0c440095f3a62fab77a22cc3cd69d diff --git a/help.tl b/help.tl index 4e9a7a3..1a22c65 100644 --- a/help.tl +++ b/help.tl @@ -4,7 +4,7 @@ require "layout" require "cmn" require "globals" -local gooi = require "gooi.gooi" +--local gooi = require "gooi.gooi" local pallete = require "pallete" local fonts = require "fonts" local i18n = require "i18n" diff --git a/hex.lua b/hex.lua index 5e587b7..8b13789 100644 --- a/hex.lua +++ b/hex.lua @@ -1,306 +1 @@ -local inspect = require "libs.inspect" -local vec = require "libs.vector" -local gr = love.graphics -require "common" ---local vec2 = require "vector-light" -function getHexPolygonWidth(hex) - return dist(hex[3], hex[4], hex[11], hex[12]) -end - -function getHexPolygonHeight(hex) - return dist(hex[1], hex[2], hex[7], hex[8]) -end - -local Hex = {} -Hex.__index = Hex - -function Hex:getVertices() - local vertices = {} - for i = 1, 6 do - table.insert(vertices, self[i]) - end - return vertices -end - -function Hex:getDebugCanvas() - local polyW = getHexPolygonWidth(self) - --local canvas = gr.newCanvas(getHexPolygonWidth(self), - --getHexPolygonHeight(self)) - local t, w, h = self:getAABB() - local screenW, screenH = gr.getDimensions() - --[[ - [local snap = 30 - [t[1] = t[1] - snap - [t[2] = t[2] - snap - [t[3] = t[3] + snap - [t[4] = t[4] + snap - ]] - local canvas = gr.newCanvas(gr.getDimensions()) - --local canvas = gr.newCanvas(w, h) - - gr.setCanvas(canvas) - gr.clear(0, 0, 1) - - gr.push() - --gr.scale(polyW / screenW, polyW / screenW) - - local vi = 1 - for i = 1, #self - 2, 2 do - gr.setColor{1, 1, 1, 1} - gr.print(string.format("(%d)", vi), self[i], self[i+1]) - vi = vi + 1 - end - gr.line(t[1], t[2], t[3], t[4]) - gr.setColor{1, 0, 0} - gr.rectangle("line", t[1], t[2], w, h) - - gr.pop() - gr.setCanvas() - - return canvas -end - -function Hex:setMesh(mesh, endindex) - self.mesh = mesh - self.endindex = endindex -end - -function Hex:setVertexColor(index, color) - local vertex = {self.mesh:getVertex(self.endindex - index + 0)} - --print("vertex", inspect(vertex)) - self.mesh:setVertex(self.endindex - index + 0, vertex) -end - -function Hex:setColor(color) - for i = 1, 6 do - self:setVertexColor(i, color) - end -end - --- [[ --- return {x1, y1, x2, y2 }, w * 2, h * 2 --- ]] -function Hex:getAABB() - local w, h = getHexPolygonWidth(self) / 2, getHexPolygonHeight(self) / 2 - return {self.cx - w, self.cy - h, self.cx + w, self.cx + h}, w * 2, h * 2 -end - -function newHexPolygon(cx, cy, rad) - local hex = setmetatable({}, Hex) - - local d = math.pi * 2 / 6 - local c = 0 - for i = 1, 7 do - local x, y = cx + math.sin(c) * rad, cy + math.cos(c) * rad - table.insert(hex, x) - table.insert(hex, y) - c = c + d - end - - hex.rad = rad - hex.selected = false - hex.cx, hex.cy = cx, cy - - return hex -end - -function addVertex(array, x, y, color) - table.insert(array, { - math.floor(x), math.floor(y), - 0, 0, -- u v - color[1], color[2], color[3], color[4] - }) - return #array -end - -function addHex(data, hex, color) - addVertex(data, hex.cx, hex.cy, color) - addVertex(data, hex[1], hex[2], color) - addVertex(data, hex[3], hex[4], color) - - addVertex(data, hex.cx, hex.cy, color) - addVertex(data, hex[3], hex[4], color) - addVertex(data, hex[5], hex[6], color) - - addVertex(data, hex.cx, hex.cy, color) - addVertex(data, hex[5], hex[6], color) - addVertex(data, hex[7], hex[8], color) - - addVertex(data, hex.cx, hex.cy, color) - addVertex(data, hex[7], hex[8], color) - addVertex(data, hex[9], hex[10], color) - - addVertex(data, hex.cx, hex.cy, color) - addVertex(data, hex[9], hex[10], color) - addVertex(data, hex[11], hex[12], color) - - addVertex(data, hex.cx, hex.cy, color) - addVertex(data, hex[11], hex[12], color) - return addVertex(data, hex[1], hex[2], color) -end - -function addVertex2(array, x, y) - table.insert(array, { - math.floor(x), math.floor(y), - --math.floor(x), math.floor(y), - 0, 0, -- u v - 1, 1, 1, 1, - }) -end - --- добавляет линию из пары треугольников и шести вершин -function addLine(array, x1, y1, x2, y2) - --TODO Оптимизировать вектора - local len = dist(x1, y1, x2, y2) - local dirx, diry = vec(x2 - x1) / len, vec(y2 - y1) / len - local dir1, dir2 = vec(x2 - x1, y2 - y1) / len, vec(x1 - x2, y1 - y2) / len - - local width = 3 - local p1 = vec(x1, y1) + dir1:perpendicular() * width - local p2 = vec(x1, y1) + dir2:perpendicular() * width - local p3 = vec(x2, y2) + dir1:perpendicular() * width - local p4 = vec(x2, y2) + dir2:perpendicular() * width - - addVertex2(array, p1.x, p1.y) - addVertex2(array, p2.x, p2.y) - addVertex2(array, p3.x, p3.y) - - addVertex2(array, p4.x, p4.y) - addVertex2(array, p3.x, p3.y) - addVertex2(array, p2.x, p2.y) -end - -function addBorder(data, hex) - addLine(data, hex[1], hex[2], hex[3], hex[4]) - addLine(data, hex[3], hex[4], hex[5], hex[6]) - addLine(data, hex[5], hex[6], hex[7], hex[8]) - addLine(data, hex[7], hex[8], hex[9], hex[10]) - addLine(data, hex[9], hex[10], hex[11], hex[12]) - addLine(data, hex[11], hex[12], hex[1], hex[2]) -end - --- map - 2d array -function newHexField(startcx, startcy, map,rad, color) - --print(inspect(map)) - --print(#map) - local xcount = #map - local ycount = #map[1] - assert(xcount == ycount) - - local Handler = { - map = deepcopy(map), - } - Handler.__index = Handler - - function Handler:get(x, y) - --print(inspect(Handler)) - --print("x, y", x, y, Handler.map[x][y] or nil) - return Handler.map[x][y] or nil - end - - local result = {} - setmetatable(result, Handler) - - local mesh = gr.newMesh((6 * 3 + 6 * 6) * xcount * ycount, "triangles", "dynamic") - local meshData = {} - - local cx, cy = startcx, startcy - local hasWH = false - local w, h - - local prevHorizon = nil - local horizon = {} - - for j = 1, ycount do - for i = 1, xcount do - local last = newHexPolygon(cx, cy, rad) - last.j = j - last.i = i - - --table.insert(result, last) - - local visible = map[j][i] ~= 0 - - if visible then - Handler.map[j][i] = last - last.mapIndex = {j, i} - table.insert(horizon, last) - end - - --[[ - [1] left - [2] lt - [3] rt - [4] right - [5] rb - [6] lb ]] - last.refs = {} - ---[[ - [ for i = 1, 6 do - [ last.refs[#last.refs + 1] = false - [ end - [ - [ if prevHorizon then - [ last.refs[2] = prevHorizon[i] - [ if i + 1 <= #prevHorizon then - [ last.refs[2] = prevHorizon[i + 1] - [ end - [ end - [ if i > 1 then - [ last.refs[1] = horizon[i - 1] - [ - [ horizon[i - 1].refs[4] = last - [ end - ]] - - if not hasWH then - w, h = getHexPolygonWidth(last), getHexPolygonHeight(last) - end - - local lastIndex - if visible then - lastIndex = addHex(meshData, last, color) - addBorder(meshData, last) - last:setMesh(mesh, lastIndex) - end - - cx = cx + w - end - - for k, v in pairs(horizon) do - table.insert(result, v) - end - prevHorizon = horizon - horizon = {} - - cy = cy + h * 3 / 4 - cx = j % 2 == 1 and startcx + w / 2 or startcx - end - - --updateNeighbors(result, xcount, ycount) - - mesh:setVertices(meshData) - - --print("result", inspect(result)) - return result, mesh -end - -function updateNeighbors(tbl, xcount, ycount) - for k, v in pairs(tbl) do - v.refs = { - --[[ - left lt top rt right rb bottom lb - --]] - } - if v.j > 1 then - - end - end -end - -return { - newHexField = newHexField, - newHexPolygon = newHexPolygon, -} diff --git a/hex.tl b/hex.tl new file mode 100644 index 0000000..4166dd6 --- /dev/null +++ b/hex.tl @@ -0,0 +1,303 @@ +--[[ +local vec = require "vector" +local inspect = require "libs.inspect" +--local vec = require "libs.vector" +local gr = love.graphics +require "common" +--local vec2 = require "vector-light" + +function getHexPolygonWidth(hex) + return dist(hex[3], hex[4], hex[11], hex[12]) +end + +function getHexPolygonHeight(hex) + return dist(hex[1], hex[2], hex[7], hex[8]) +end + +local Hex = {} +Hex.__index = Hex + +function Hex:getVertices() + local vertices = {} + for i = 1, 6 do + table.insert(vertices, self[i]) + end + return vertices +end + +function Hex:getDebugCanvas() + local polyW = getHexPolygonWidth(self) + --local canvas = gr.newCanvas(getHexPolygonWidth(self), + --getHexPolygonHeight(self)) + local t, w, h = self:getAABB() + local screenW, screenH = gr.getDimensions() + + --local snap = 30 + --t[1] = t[1] - snap + --t[2] = t[2] - snap + --t[3] = t[3] + snap + --t[4] = t[4] + snap + + local canvas = gr.newCanvas(gr.getDimensions()) + --local canvas = gr.newCanvas(w, h) + + gr.setCanvas(canvas) + gr.clear(0, 0, 1) + + gr.push() + --gr.scale(polyW / screenW, polyW / screenW) + + local vi = 1 + for i = 1, #self - 2, 2 do + gr.setColor{1, 1, 1, 1} + gr.print(string.format("(%d)", vi), self[i], self[i+1]) + vi = vi + 1 + end + gr.line(t[1], t[2], t[3], t[4]) + gr.setColor{1, 0, 0} + gr.rectangle("line", t[1], t[2], w, h) + + gr.pop() + gr.setCanvas() + + return canvas +end + +function Hex:setMesh(mesh, endindex) + self.mesh = mesh + self.endindex = endindex +end + +function Hex:setVertexColor(index, color) + local vertex = {self.mesh:getVertex(self.endindex - index + 0)} + --print("vertex", inspect(vertex)) + self.mesh:setVertex(self.endindex - index + 0, vertex) +end + +function Hex:setColor(color) + for i = 1, 6 do + self:setVertexColor(i, color) + end +end + +-- return {x1, y1, x2, y2 }, w * 2, h * 2 +function Hex:getAABB() + local w, h = getHexPolygonWidth(self) / 2, getHexPolygonHeight(self) / 2 + return {self.cx - w, self.cy - h, self.cx + w, self.cx + h}, w * 2, h * 2 +end + +function newHexPolygon(cx, cy, rad) + local hex = setmetatable({}, Hex) + + local d = math.pi * 2 / 6 + local c = 0 + for i = 1, 7 do + local x, y = cx + math.sin(c) * rad, cy + math.cos(c) * rad + table.insert(hex, x) + table.insert(hex, y) + c = c + d + end + + hex.rad = rad + hex.selected = false + hex.cx, hex.cy = cx, cy + + return hex +end + +function addVertex(array, x, y, color) + table.insert(array, { + math.floor(x), math.floor(y), + 0, 0, -- u v + color[1], color[2], color[3], color[4] + }) + return #array +end + +function addHex(data, hex, color) + addVertex(data, hex.cx, hex.cy, color) + addVertex(data, hex[1], hex[2], color) + addVertex(data, hex[3], hex[4], color) + + addVertex(data, hex.cx, hex.cy, color) + addVertex(data, hex[3], hex[4], color) + addVertex(data, hex[5], hex[6], color) + + addVertex(data, hex.cx, hex.cy, color) + addVertex(data, hex[5], hex[6], color) + addVertex(data, hex[7], hex[8], color) + + addVertex(data, hex.cx, hex.cy, color) + addVertex(data, hex[7], hex[8], color) + addVertex(data, hex[9], hex[10], color) + + addVertex(data, hex.cx, hex.cy, color) + addVertex(data, hex[9], hex[10], color) + addVertex(data, hex[11], hex[12], color) + + addVertex(data, hex.cx, hex.cy, color) + addVertex(data, hex[11], hex[12], color) + return addVertex(data, hex[1], hex[2], color) +end + +function addVertex2(array, x, y) + table.insert(array, { + math.floor(x), math.floor(y), + --math.floor(x), math.floor(y), + 0, 0, -- u v + 1, 1, 1, 1, + }) +end + +-- добавляет линию из пары треугольников и шести вершин +function addLine(array, x1, y1, x2, y2) + --TODO Оптимизировать вектора + local len = dist(x1, y1, x2, y2) + local dirx, diry = vec(x2 - x1) / len, vec(y2 - y1) / len + local dir1, dir2 = vec(x2 - x1, y2 - y1) / len, vec(x1 - x2, y1 - y2) / len + + local width = 3 + local p1 = vec(x1, y1) + dir1:perpendicular() * width + local p2 = vec(x1, y1) + dir2:perpendicular() * width + local p3 = vec(x2, y2) + dir1:perpendicular() * width + local p4 = vec(x2, y2) + dir2:perpendicular() * width + + addVertex2(array, p1.x, p1.y) + addVertex2(array, p2.x, p2.y) + addVertex2(array, p3.x, p3.y) + + addVertex2(array, p4.x, p4.y) + addVertex2(array, p3.x, p3.y) + addVertex2(array, p2.x, p2.y) +end + +function addBorder(data, hex) + addLine(data, hex[1], hex[2], hex[3], hex[4]) + addLine(data, hex[3], hex[4], hex[5], hex[6]) + addLine(data, hex[5], hex[6], hex[7], hex[8]) + addLine(data, hex[7], hex[8], hex[9], hex[10]) + addLine(data, hex[9], hex[10], hex[11], hex[12]) + addLine(data, hex[11], hex[12], hex[1], hex[2]) +end + +-- map - 2d array +function newHexField(startcx, startcy, map,rad, color) + --print(inspect(map)) + --print(#map) + local xcount = #map + local ycount = #map[1] + assert(xcount == ycount) + + local Handler = { + map = deepcopy(map), + } + Handler.__index = Handler + + function Handler:get(x, y) + --print(inspect(Handler)) + --print("x, y", x, y, Handler.map[x][y] or nil) + return Handler.map[x][y] or nil + end + + local result = {} + setmetatable(result, Handler) + + local mesh = gr.newMesh((6 * 3 + 6 * 6) * xcount * ycount, "triangles", "dynamic") + local meshData = {} + + local cx, cy = startcx, startcy + local hasWH = false + local w, h + + local prevHorizon = nil + local horizon = {} + + for j = 1, ycount do + for i = 1, xcount do + local last = newHexPolygon(cx, cy, rad) + last.j = j + last.i = i + + --table.insert(result, last) + + local visible = map[j][i] ~= 0 + + if visible then + Handler.map[j][i] = last + last.mapIndex = {j, i} + table.insert(horizon, last) + end + + --[1] left + --[2] lt + --[3] rt + --[4] right + --[5] rb + --[6] lb + + last.refs = {} + + for i = 1, 6 do + last.refs[#last.refs + 1] = false + end + + if prevHorizon then + last.refs[2] = prevHorizon[i] + if i + 1 <= #prevHorizon then + last.refs[2] = prevHorizon[i + 1] + end + end + if i > 1 then + last.refs[1] = horizon[i - 1] + + horizon[i - 1].refs[4] = last + end + + if not hasWH then + w, h = getHexPolygonWidth(last), getHexPolygonHeight(last) + end + + local lastIndex + if visible then + lastIndex = addHex(meshData, last, color) + addBorder(meshData, last) + last:setMesh(mesh, lastIndex) + end + + cx = cx + w + end + + for k, v in pairs(horizon) do + table.insert(result, v) + end + prevHorizon = horizon + horizon = {} + + cy = cy + h * 3 / 4 + cx = j % 2 == 1 and startcx + w / 2 or startcx + end + + --updateNeighbors(result, xcount, ycount) + + mesh:setVertices(meshData) + + --print("result", inspect(result)) + return result, mesh +end + +function updateNeighbors(tbl, xcount, ycount) + for k, v in pairs(tbl) do + v.refs = { + --left lt top rt right rb bottom lb + } + if v.j > 1 then + + end + end +end + +return { + newHexField = newHexField, + newHexPolygon = newHexPolygon, +} +--]] diff --git a/i18n/init.lua b/i18n/init.lua new file mode 100644 index 0000000..660a936 --- /dev/null +++ b/i18n/init.lua @@ -0,0 +1,197 @@ +local i18n = {} + +local inspect = require "inspect" + +local store +local locale +local pluralizeFunction +local defaultLocale = 'en' +local fallbackLocale = defaultLocale + +local currentFilePath = (...):gsub("%.init$","") + +local plural = require(currentFilePath .. '.plural') +local interpolate = require(currentFilePath .. '.interpolate') +local variants = require(currentFilePath .. '.variants') +local version = require(currentFilePath .. '.version') + +i18n.plural, i18n.interpolate, i18n.variants, i18n.version, i18n._VERSION = + plural, interpolate, variants, version, version + +-- private stuff + +local function dotSplit(str) + local fields, length = {},0 + str:gsub("[^%.]+", function(c) + length = length + 1 + fields[length] = c + end) + return fields, length +end + +local function isPluralTable(t) + return type(t) == 'table' and type(t.other) == 'string' +end + +local function isPresent(str) + return type(str) == 'string' and #str > 0 +end + +local function assertPresent(functionName, paramName, value) + if isPresent(value) then return end + + local msg = "i18n.%s requires a non-empty string on its %s. Got %s (a %s value)." + error(msg:format(functionName, paramName, tostring(value), type(value))) +end + +local function assertPresentOrPlural(functionName, paramName, value) + if isPresent(value) or isPluralTable(value) then return end + + local msg = "i18n.%s requires a non-empty string or plural-form table on its %s. Got %s (a %s value)." + error(msg:format(functionName, paramName, tostring(value), type(value))) +end + +local function assertPresentOrTable(functionName, paramName, value) + if isPresent(value) or type(value) == 'table' then return end + + local msg = "i18n.%s requires a non-empty string or table on its %s. Got %s (a %s value)." + error(msg:format(functionName, paramName, tostring(value), type(value))) +end + +local function assertFunctionOrNil(functionName, paramName, value) + if value == nil or type(value) == 'function' then return end + + local msg = "i18n.%s requires a function (or nil) on param %s. Got %s (a %s value)." + error(msg:format(functionName, paramName, tostring(value), type(value))) +end + +local function defaultPluralizeFunction(count) + return plural.get(variants.root(i18n.getLocale()), count) +end + +local function pluralize(t, data) + assertPresentOrPlural('interpolatePluralTable', 't', t) + data = data or {} + local count = data.count or 1 + local plural_form = pluralizeFunction(count) + return t[plural_form] +end + +local function treatNode(node, data) + if type(node) == 'string' then + return interpolate(node, data) + elseif isPluralTable(node) then + return interpolate(pluralize(node, data), data) + end + return node +end + +local function recursiveLoad(currentContext, data) + local composedKey + for k,v in pairs(data) do + composedKey = (currentContext and (currentContext .. '.') or "") .. tostring(k) + assertPresent('load', composedKey, k) + assertPresentOrTable('load', composedKey, v) + if type(v) == 'string' then + i18n.set(composedKey, v) + else + recursiveLoad(composedKey, v) + end + end +end + +local function localizedTranslate(key, loc, data) + local path, length = dotSplit(loc .. "." .. key) + local node = store + + for i=1, length do + node = node[path[i]] + if not node then return nil end + end + + return treatNode(node, data) +end + +-- public interface + +function i18n.set(key, value) + assertPresent('set', 'key', key) + assertPresentOrPlural('set', 'value', value) + + local path, length = dotSplit(key) + local node = store + + for i=1, length-1 do + key = path[i] + node[key] = node[key] or {} + node = node[key] + end + + local lastKey = path[length] + node[lastKey] = value +end + +function i18n.translate(key, data) + assertPresent('translate', 'key', key) + + data = data or {} + local usedLocale = data.locale or locale + + local fallbacks = variants.fallbacks(usedLocale, fallbackLocale) + for i=1, #fallbacks do + local value = localizedTranslate(key, fallbacks[i], data) + if value then return value end + end + + return data.default +end + +function i18n.setLocale(newLocale, newPluralizeFunction) + assertPresent('setLocale', 'newLocale', newLocale) + assertFunctionOrNil('setLocale', 'newPluralizeFunction', newPluralizeFunction) + locale = newLocale + pluralizeFunction = newPluralizeFunction or defaultPluralizeFunction +end + +function i18n.setFallbackLocale(newFallbackLocale) + assertPresent('setFallbackLocale', 'newFallbackLocale', newFallbackLocale) + fallbackLocale = newFallbackLocale +end + +function i18n.getFallbackLocale() + return fallbackLocale +end + +function i18n.getLocale() + return locale +end + +function i18n.reset() + store = {} + plural.reset() + i18n.setLocale(defaultLocale) + i18n.setFallbackLocale(defaultLocale) +end + +function i18n.load(data) + recursiveLoad(nil, data) +end + +function i18n.loadFile(path, callback) + local chunk + if callback == nil then + chunk = assert(loadfile(path)) + else + chunk = assert(callback(path)) + end + local data = chunk() + i18n.load(data) + print("i18n", inspect(i18n)) + print("locale", inspect(locale)) +end + +setmetatable(i18n, {__call = function(_, ...) return i18n.translate(...) end}) + +i18n.reset() + +return i18n diff --git a/i18n/interpolate.lua b/i18n/interpolate.lua new file mode 100644 index 0000000..c6bb242 --- /dev/null +++ b/i18n/interpolate.lua @@ -0,0 +1,60 @@ +local unpack = unpack or table.unpack -- lua 5.2 compat + +local FORMAT_CHARS = { c=1, d=1, E=1, e=1, f=1, g=1, G=1, i=1, o=1, u=1, X=1, x=1, s=1, q=1, ['%']=1 } + +-- matches a string of type %{age} +local function interpolateValue(string, variables) + return string:gsub("(.?)%%{%s*(.-)%s*}", + function (previous, key) + if previous == "%" then + return + else + return previous .. tostring(variables[key]) + end + end) +end + +-- matches a string of type %.d +local function interpolateField(string, variables) + return string:gsub("(.?)%%<%s*(.-)%s*>%.([cdEefgGiouXxsq])", + function (previous, key, format) + if previous == "%" then + return + else + return previous .. string.format("%" .. format, variables[key] or "nil") + end + end) +end + +local function escapePercentages(string) + return string:gsub("(%%)(.?)", function(_, char) + if FORMAT_CHARS[char] then + return "%" .. char + else + return "%%" .. char + end + end) +end + +local function unescapePercentages(string) + return string:gsub("(%%%%)(.?)", function(_, char) + if FORMAT_CHARS[char] then + return "%" .. char + else + return "%%" .. char + end + end) +end + +local function interpolate(pattern, variables) + variables = variables or {} + local result = pattern + result = interpolateValue(result, variables) + result = interpolateField(result, variables) + result = escapePercentages(result) + result = string.format(result, unpack(variables)) + result = unescapePercentages(result) + return result +end + +return interpolate diff --git a/i18n/plural.lua b/i18n/plural.lua new file mode 100644 index 0000000..bb99804 --- /dev/null +++ b/i18n/plural.lua @@ -0,0 +1,280 @@ +local plural = {} +local defaultFunction = nil +-- helper functions + +local function assertPresentString(functionName, paramName, value) + if type(value) ~= 'string' or #value == 0 then + local msg = "Expected param %s of function %s to be a string, but got %s (a value of type %s) instead" + error(msg:format(paramName, functionName, tostring(value), type(value))) + end +end + +local function assertNumber(functionName, paramName, value) + if type(value) ~= 'number' then + local msg = "Expected param %s of function %s to be a number, but got %s (a value of type %s) instead" + error(msg:format(paramName, functionName, tostring(value), type(value))) + end +end + +-- transforms "foo bar baz" into {'foo','bar','baz'} +local function words(str) + local result, length = {}, 0 + str:gsub("%S+", function(word) + length = length + 1 + result[length] = word + end) + return result +end + +local function isInteger(n) + return n == math.floor(n) +end + +local function between(value, min, max) + return value >= min and value <= max +end + +local function inside(v, list) + for i=1, #list do + if v == list[i] then return true end + end + return false +end + + +-- pluralization functions + +local pluralization = {} + +local f1 = function(n) + return n == 1 and "one" or "other" +end +pluralization[f1] = words([[ + af asa bem bez bg bn brx ca cgg chr da de dv ee el + en eo es et eu fi fo fur fy gl gsw gu ha haw he is + it jmc kaj kcg kk kl ksb ku lb lg mas ml mn mr nah + nb nd ne nl nn no nr ny nyn om or pa pap ps pt rm + rof rwk saq seh sn so sq ss ssy st sv sw syr ta te + teo tig tk tn ts ur ve vun wae xh xog zu +]]) + +local f2 = function(n) + return (n == 0 or n == 1) and "one" or "other" +end +pluralization[f2] = words("ak am bh fil guw hi ln mg nso ti tl wa") + +local f3 = function(n) + if not isInteger(n) then return 'other' end + return (n == 0 and "zero") or + (n == 1 and "one") or + (n == 2 and "two") or + (between(n % 100, 3, 10) and "few") or + (between(n % 100, 11, 99) and "many") or + "other" +end +pluralization[f3] = {'ar'} + +local f4 = function() + return "other" +end +pluralization[f4] = words([[ + az bm bo dz fa hu id ig ii ja jv ka kde kea km kn + ko lo ms my root sah ses sg th to tr vi wo yo zh +]]) + +local f5 = function(n) + if not isInteger(n) then return 'other' end + local n_10, n_100 = n % 10, n % 100 + return (n_10 == 1 and n_100 ~= 11 and 'one') or + (between(n_10, 2, 4) and not between(n_100, 12, 14) and 'few') or + ((n_10 == 0 or between(n_10, 5, 9) or between(n_100, 11, 14)) and 'many') or + 'other' +end +pluralization[f5] = words('be bs hr ru sh sr uk') + +local f6 = function(n) + if not isInteger(n) then return 'other' end + local n_10, n_100 = n % 10, n % 100 + return (n_10 == 1 and not inside(n_100, {11,71,91}) and 'one') or + (n_10 == 2 and not inside(n_100, {12,72,92}) and 'two') or + (inside(n_10, {3,4,9}) and + not between(n_100, 10, 19) and + not between(n_100, 70, 79) and + not between(n_100, 90, 99) + and 'few') or + (n ~= 0 and n % 1000000 == 0 and 'many') or + 'other' +end +pluralization[f6] = {'br'} + +local f7 = function(n) + return (n == 1 and 'one') or + ((n == 2 or n == 3 or n == 4) and 'few') or + 'other' +end +pluralization[f7] = {'cz', 'sk'} + +local f8 = function(n) + return (n == 0 and 'zero') or + (n == 1 and 'one') or + (n == 2 and 'two') or + (n == 3 and 'few') or + (n == 6 and 'many') or + 'other' +end +pluralization[f8] = {'cy'} + +local f9 = function(n) + return (n >= 0 and n < 2 and 'one') or + 'other' +end +pluralization[f9] = {'ff', 'fr', 'kab'} + +local f10 = function(n) + return (n == 1 and 'one') or + (n == 2 and 'two') or + ((n == 3 or n == 4 or n == 5 or n == 6) and 'few') or + ((n == 7 or n == 8 or n == 9 or n == 10) and 'many') or + 'other' +end +pluralization[f10] = {'ga'} + +local f11 = function(n) + return ((n == 1 or n == 11) and 'one') or + ((n == 2 or n == 12) and 'two') or + (isInteger(n) and (between(n, 3, 10) or between(n, 13, 19)) and 'few') or + 'other' +end +pluralization[f11] = {'gd'} + +local f12 = function(n) + local n_10 = n % 10 + return ((n_10 == 1 or n_10 == 2 or n % 20 == 0) and 'one') or + 'other' +end +pluralization[f12] = {'gv'} + +local f13 = function(n) + return (n == 1 and 'one') or + (n == 2 and 'two') or + 'other' +end +pluralization[f13] = words('iu kw naq se sma smi smj smn sms') + +local f14 = function(n) + return (n == 0 and 'zero') or + (n == 1 and 'one') or + 'other' +end +pluralization[f14] = {'ksh'} + +local f15 = function(n) + return (n == 0 and 'zero') or + (n > 0 and n < 2 and 'one') or + 'other' +end +pluralization[f15] = {'lag'} + +local f16 = function(n) + if not isInteger(n) then return 'other' end + if between(n % 100, 11, 19) then return 'other' end + local n_10 = n % 10 + return (n_10 == 1 and 'one') or + (between(n_10, 2, 9) and 'few') or + 'other' +end +pluralization[f16] = {'lt'} + +local f17 = function(n) + return (n == 0 and 'zero') or + ((n % 10 == 1 and n % 100 ~= 11) and 'one') or + 'other' +end +pluralization[f17] = {'lv'} + +local f18 = function(n) + return((n % 10 == 1 and n ~= 11) and 'one') or + 'other' +end +pluralization[f18] = {'mk'} + +local f19 = function(n) + return (n == 1 and 'one') or + ((n == 0 or + (n ~= 1 and isInteger(n) and between(n % 100, 1, 19))) + and 'few') or + 'other' +end +pluralization[f19] = {'mo', 'ro'} + +local f20 = function(n) + if n == 1 then return 'one' end + if not isInteger(n) then return 'other' end + local n_100 = n % 100 + return ((n == 0 or between(n_100, 2, 10)) and 'few') or + (between(n_100, 11, 19) and 'many') or + 'other' +end +pluralization[f20] = {'mt'} + +local f21 = function(n) + if n == 1 then return 'one' end + if not isInteger(n) then return 'other' end + local n_10, n_100 = n % 10, n % 100 + + return ((between(n_10, 2, 4) and not between(n_100, 12, 14)) and 'few') or + ((n_10 == 0 or n_10 == 1 or between(n_10, 5, 9) or between(n_100, 12, 14)) and 'many') or + 'other' +end +pluralization[f21] = {'pl'} + +local f22 = function(n) + return (n == 0 or n == 1) and 'one' or + 'other' +end +pluralization[f22] = {'shi'} + +local f23 = function(n) + local n_100 = n % 100 + return (n_100 == 1 and 'one') or + (n_100 == 2 and 'two') or + ((n_100 == 3 or n_100 == 4) and 'few') or + 'other' +end +pluralization[f23] = {'sl'} + +local f24 = function(n) + return (isInteger(n) and (n == 0 or n == 1 or between(n, 11, 99)) and 'one') + or 'other' +end +pluralization[f24] = {'tzm'} + +local pluralizationFunctions = {} +for f,locales in pairs(pluralization) do + for _,locale in ipairs(locales) do + pluralizationFunctions[locale] = f + end +end + +-- public interface + +function plural.get(locale, n) + assertPresentString('i18n.plural.get', 'locale', locale) + assertNumber('i18n.plural.get', 'n', n) + + local f = pluralizationFunctions[locale] or defaultFunction + + return f(math.abs(n)) +end + +function plural.setDefaultFunction(f) + defaultFunction = f +end + +function plural.reset() + defaultFunction = pluralizationFunctions['en'] +end + +plural.reset() + +return plural diff --git a/i18n/variants.lua b/i18n/variants.lua new file mode 100644 index 0000000..0cfad42 --- /dev/null +++ b/i18n/variants.lua @@ -0,0 +1,49 @@ +local variants = {} + +local function reverse(arr, length) + local result = {} + for i=1, length do result[i] = arr[length-i+1] end + return result, length +end + +local function concat(arr1, len1, arr2, len2) + for i = 1, len2 do + arr1[len1 + i] = arr2[i] + end + return arr1, len1 + len2 +end + +function variants.ancestry(locale) + local result, length, accum = {},0,nil + locale:gsub("[^%-]+", function(c) + length = length + 1 + accum = accum and (accum .. '-' .. c) or c + result[length] = accum + end) + return reverse(result, length) +end + +function variants.isParent(parent, child) + return not not child:match("^".. parent .. "%-") +end + +function variants.root(locale) + return locale:match("[^%-]+") +end + +function variants.fallbacks(locale, fallbackLocale) + if locale == fallbackLocale or + variants.isParent(fallbackLocale, locale) then + return variants.ancestry(locale) + end + if variants.isParent(locale, fallbackLocale) then + return variants.ancestry(fallbackLocale) + end + + local ancestry1, length1 = variants.ancestry(locale) + local ancestry2, length2 = variants.ancestry(fallbackLocale) + + return concat(ancestry1, length1, ancestry2, length2) +end + +return variants diff --git a/i18n/version.lua b/i18n/version.lua new file mode 100644 index 0000000..eb78888 --- /dev/null +++ b/i18n/version.lua @@ -0,0 +1 @@ +return '0.9.2' diff --git a/layout.lua b/layout.lua index 5195476..aee177d 100644 --- a/layout.lua +++ b/layout.lua @@ -64,7 +64,7 @@ function Layout.new(x, y, w, h) end function assertVariadic(...) - local sum = 0 + local sum = 0. for i = 1, select("#", ...) do sum = sum + select(i, ...) end @@ -104,13 +104,14 @@ function splitv(tbl, ...) return _tl_table_unpack(subTbls) end -function splitvAlign(tbl, alignMode, ...) + +function splitvAlign(tbl, alignMode) assert(false, "Not yet implemented") assertHelper(tbl) assertAlign(alignMode) - local subTbls = {} - for i = 1, select("#", ...) do - end + + + assert(false, "Not implemented") end @@ -118,7 +119,7 @@ function splithByNum(tbl, piecesNum) assertHelper(tbl) local subTbls = {} local prevy, h = tbl.y, tbl.h / piecesNum - for i = 1, piecesNum do + for _ = 1, piecesNum do table.insert(subTbls, { x = tbl.x, y = prevy, w = tbl.w, h = h }) prevy = prevy + h end @@ -129,7 +130,7 @@ function splitvByNum(tbl, piecesNum) assertHelper(tbl) local subTbls = {} local prevx, w = tbl.x, tbl.w / piecesNum - for i = 1, piecesNum do + for _ = 1, piecesNum do table.insert(subTbls, { x = prevx, y = tbl.y, w = w, h = tbl.h }) prevx = prevx + w end diff --git a/layout.tl b/layout.tl index 1b4635a..078e0d2 100644 --- a/layout.tl +++ b/layout.tl @@ -64,7 +64,7 @@ function Layout.new(x: number|Layout, y: number, w: number, h: number): Layout end function assertVariadic(...: number) - local sum = 0 + local sum = 0. for i = 1, select("#", ...) do sum = sum + select(i, ...) end @@ -104,13 +104,14 @@ function splitv(tbl: Layout, ...: number): Layout... return table.unpack(subTbls) end -function splitvAlign(tbl: Layout, alignMode: Layout.AlignMode, ...: number): Layout... +--function splitvAlign(tbl: Layout, alignMode: Layout.AlignMode, ...: number): Layout... +function splitvAlign(tbl: Layout, alignMode: Layout.AlignMode): Layout... assert(false, "Not yet implemented") assertHelper(tbl) assertAlign(alignMode) - local subTbls = {} - for i = 1, select("#", ...) do - end + --local subTbls = {} + --for i = 1, select("#", ...) do + --end assert(false, "Not implemented") end @@ -118,7 +119,7 @@ function splithByNum(tbl: Layout, piecesNum: number): Layout... assertHelper(tbl) local subTbls = {} local prevy, h = tbl.y, tbl.h / piecesNum - for i = 1, piecesNum do + for _ = 1, piecesNum do table.insert(subTbls, {x = tbl.x, y = prevy, w = tbl.w, h = h}) prevy = prevy + h end @@ -129,7 +130,7 @@ function splitvByNum(tbl: Layout, piecesNum: number): Layout... assertHelper(tbl) local subTbls = {} local prevx, w = tbl.x, tbl.w / piecesNum - for i = 1, piecesNum do + for _ = 1, piecesNum do table.insert(subTbls, {x = prevx, y = tbl.y, w = w, h = tbl.h}) prevx = prevx + w end diff --git a/nbtypes.lua b/nbtypes.lua index 1cf1ccc..049d4e1 100644 --- a/nbtypes.lua +++ b/nbtypes.lua @@ -3,6 +3,9 @@ + + + Date = {} @@ -54,3 +57,12 @@ Percentage = {} + + + + + + + + + History = {} diff --git a/pviewer.tl b/pviewer.tl index 3bc4481..fef133e 100644 --- a/pviewer.tl +++ b/pviewer.tl @@ -1,6 +1,5 @@ require "love" require "common" -require "gooi.gooi" require "drawstat" local serpent = require "serpent" @@ -25,7 +24,7 @@ global type Pviewer = record buildLayout: function(Pviewer) enter: function(Pviewer) sortByDate: function(Pviewer) - updateRender: function(Pviewer, number) + updateRender: function(Pviewer, integer) end local pviewer_mt: metatable = { @@ -50,7 +49,7 @@ end -- создает новый экземпляр просмотрщика статистики для текущего положения -- индекса pviewer.activeIndex -function Pviewer:updateRender(index: number) +function Pviewer:updateRender(index: integer) print("updateRender()", index) if self.data and index >= 1 and index <= #self.data then local data = self.data[index] diff --git a/signal.lua b/signal.lua index 890a549..dfeb570 100644 --- a/signal.lua +++ b/signal.lua @@ -1,383 +1,5 @@ -local g = love.graphics -local inspect = require "libs.inspect" -local serpent = require "serpent" -local vector = require "libs.vector" -require "hex" - -local conbuf = require "kons".new(0, 0) - -local signal = {} -signal.__index = signal - -local fragmentCode = g.newShader("vertex1.glsl") - ---[[ --- Типы сигналов и их порядок в канвасах слева на право: --- quad, circle, rhombus, trup, trdown, trupdown ---]] -local types = {"quad", "circle", "rhombus", "trup", "trdown", "trupdown"} - --- width - ширина ячейки для фигурки --- soundPack - имя подкаталога в 'sfx' с набором звуков -function signal.new(hexfield, startcx, startcy, map, width, soundPack) - local circleImage = g.newImage("circle.png") - local width = hexfield[1].rad - local self = { - circleImage = circleImage, - imageQuad = g.newQuad(0, 0, width, width, - circleImage:getWidth(), circleImage:getHeight()), - iCount = 10, - hexfield = hexfield, - startcx = startcx, - startcy = startcy, - map = map, - width = width, - sounds = {}, - canvas = nil, - borderColor = {0, 0, 0}, - borderLineWidth = 3, - } - - wavePath = "sfx/" .. soundPack - for k, v in pairs(love.filesystem.getDirectoryItems(wavePath)) do - table.insert(self.sounds, love.audio.newSource(wavePath .. "/" .. v, - "static")) - end - - self = setmetatable(self, signal) - - --self:exampleFilling() - - self:setCorner(0, 0) - self:resize(self.width) - return self -end - -function signal:exampleFilling() - local exampleHex = self.hexfield[1] - self.exampleCanvas = g.newCanvas(g.getDimensions()) - - local x1, y1 = exampleHex[11], exampleHex[12] - local x2, y2 = exampleHex[5], exampleHex[6] - local dup_x1, dup_y1, dup_x2, dup_y2 = x1, y1, x2, y2 - local snap = 10 - - local prevWidth = g.getLineWidth() - g.setCanvas({self.exampleCanvas, stencil=true}) - - g.stencil(function() - g.polygon("fill", exampleHex) - end, "invert", 1) - - g.setStencilTest("greater", 1) - - for i = 1, 10 do - g.line(dup_x1, dup_y1, dup_x2, dup_y2) - dup_x1, dup_y1 = dup_x1 - snap, dup_y1 - snap - dup_x2, dup_y2 = dup_x2 - snap, dup_y2 - snap - - g.line(x1, y1, x2, y2) - x1, y1 = x1 + snap, y1 + snap - x2, y2 = x2 + snap, y2 + snap - end - - x1, y1, x2, y2 = exampleHex[3], exampleHex[4], exampleHex[9], exampleHex[10] - dup_x1, dup_y1, dup_x2, dup_y2 = x1, y1, x2, y2 - - for i = 1, 10 do - g.line(dup_x1, dup_y1, dup_x2, dup_y2) - dup_x1, dup_y1 = dup_x1 + snap, dup_y1 - snap - dup_x2, dup_y2 = dup_x2 + snap, dup_y2 - snap - - g.line(x1, y1, x2, y2) - x1, y1 = x1 - snap, y1 + snap - x2, y2 = x2 - snap, y2 + snap - end - - g.setStencilTest() - g.setCanvas() - g.setLineWidth(prevWidth) -end - --- установить координаты левого верхнего угла, от которого идет отсчет ячеек. --- обязательно вызывать перед рисовкой. -function signal:setCorner(x, y) - self.x0, self.y0 = x, y -end - -function signal:resize(width) - self.width = width - - self.canvas = g.newCanvas(width, width * 6, {msaa = 2}) - self.canvases = {} - for i = 1, 6 do - table.insert(self.canvases, g.newCanvas(width, width, {msaa = 2})) - end - - self:drawFigures2Canvas() -end - -function signal:draw2Canvas(index) - local xd, yd = 1, 1 - local border = 5 - local w, h = self.width - border * 2, self.width - border * 2 - local x = self.x0 + xd * self.width + border - local y = self.y0 + yd * self.width + border - - g.setColor{1, 1, 1} - g.setCanvas(self.canvases[index]) - local funcName = types[index] - self[funcName](self, 0, 0, w, h) - g.setCanvas() - - self.canvases[index]:newImageData():encode("png", "signals/" .. funcName .. ".png") -end - -function signal:drawFigures2Canvas() - love.filesystem.createDirectory("signals") - for k, v in ipairs(types) do - self:draw2Canvas(k) - end -end - --- xd, yd - целочисленная позиция фигуры в матрице. --- type - тип рисуемой картинки(квадрат, круг, треугольник вниз, --- треугольник вверх, пересечение треугольников, ромб) --- color - текущий цвет -function signal:draw(xd, yd, type_, color) - - local currentHex = self.hexfield:get(xd, yd) - - local border = 1 - local w, h = self.width - border * 2, self.width - border * 2 - local x = self.x0 + xd * self.width + border - local y = self.y0 + yd * self.width + border - - self.borderColor[4] = color[4] -- анимирую альфа-канал цвета рамки - g.setColor(color) - local oldWidth = g.getLineWidth() - g.setLineWidth(self.borderLineWidth) - - if currentHex and type(currentHex) == "table" then - - --g.setShader(fragmentCode) - --safesend(fragmentCode, "iTime", love.timer.getTime()) - --safesend(fragmentCode, "iCount", self.iCount) - - local rad = math.floor(getHexPolygonWidth(self.hexfield[1]) / 2) - - --g.setShader() - - local idx = 0 - for k, v in pairs(types) do - if v == type_ then - idx = k - break - end - end - - local x, y = currentHex.cx - w / 2, currentHex.cy - h / 2 - g.draw(self.canvases[idx], x, y) - end - - g.setLineWidth(oldWidth) - - g.setColor{1, 1, 1} - --g.draw(self.exampleCanvas, 0, 0) - -end - --- хорошая идея добавить проигрывание звука, но как ориентироваться в --- сэмплах? На стадии создания сигнала загрузить набор сэмплов и --- ориентироваться по их номерам? Тогда нужно предоставить пользователю --- сигнала диапазон возможных значений номеров сэмпла 1..samplesCount -function signal:play(index) - assert(index <= #self.sounds) - --self.sounds[index]:play() -end - -function signal:quad(x, y, w, h) - local delta = 5 - g.rectangle("fill", x + delta, y + delta, w - delta * 2, h - delta * 2) - g.setColor(self.borderColor) - g.rectangle("line", x + delta, y + delta, w - delta * 2, h - delta * 2) -end - -function signal:circle(x, y, w, h) - g.circle("fill", x + w / 2, y + h / 2, w / 2.3) - g.setColor(self.borderColor) - g.circle("line", x + w / 2, y + h / 2, w / 2.3) -end - -function signal:trdown(x, y, w, h) - local magic = 2.64 - local tri = {} - local rad = w / 2 - for i = 1, 3 do - local alpha = 2 * math.pi * i / 3 - local sx = x + w / 2 + rad * math.sin(alpha) - local sy = y + h / magic + rad * math.cos(alpha) - tri[#tri + 1] = sx - tri[#tri + 1] = sy - end - g.polygon("fill", tri) - g.setColor(self.borderColor) - g.polygon("line", tri) -end - -function signal:trup(x, y, w, h) - local magic = 1.64 - local tri = {} - local rad = w / 2 - for i = 1, 3 do - local alpha = math.pi + 2 * math.pi * i / 3 - local sx = x + w / 2 + rad * math.sin(alpha) - local sy = y + h / magic + rad * math.cos(alpha) - tri[#tri + 1] = sx - tri[#tri + 1] = sy - end - g.polygon("fill", tri) - g.setColor(self.borderColor) - g.polygon("line", tri) -end - --- функция расчитывает и возвращает шесть точек пересечения между линиями --- двух треугольников. up, down - координаты точек треугольника вершинами --- вверх и вершинами вниз соответственно. Вершины лежат в массиве плоско. -function signal:calculateIntersections(up, down) - local points = {} - local p - - -- 1 - p = intersection(vector(up[5], up[6]), vector(up[1], up[2]), - vector(down[5], down[6]), vector(down[3], down[4])) - points[#points + 1] = p.x - points[#points + 1] = p.y - - -- 2 - p = intersection(vector(up[5], up[6]), vector(up[1], up[2]), - vector(down[3], down[4]), vector(down[1], down[2])) - points[#points + 1] = p.x - points[#points + 1] = p.y - - -- 3 - p = intersection(vector(up[3], up[4]), vector(up[5], up[6]), - vector(down[3], down[4]), vector(down[1], down[2])) - points[#points + 1] = p.x - points[#points + 1] = p.y - - -- 4 - p = intersection(vector(up[3], up[4]), vector(up[5], up[6]), - vector(down[1], down[2]), vector(down[5], down[6])) - points[#points + 1] = p.x - points[#points + 1] = p.y - - -- 5 - p = intersection(vector(up[3], up[4]), vector(up[1], up[2]), - vector(down[1], down[2]), vector(down[5], down[6])) - points[#points + 1] = p.x - points[#points + 1] = p.y - - -- 6 - p = intersection(vector(up[3], up[4]), vector(up[1], up[2]), - vector(down[3], down[4]), vector(down[5], down[6])) - points[#points + 1] = p.x - points[#points + 1] = p.y - - return points -end - -function signal:trupdown(x, y, w, h) - local tri_up, tri_down = {}, {} - local rad = w / 2 - for i = 1, 3 do - local alpha = 2 * math.pi * i / 3 - local sx = w / 2 + rad * math.sin(alpha) - local sy = h / 2 + rad * math.cos(alpha) - tri_up[#tri_up + 1] = sx - tri_up[#tri_up + 1] = sy - local alpha = math.pi + 2 * math.pi * i / 3 - local sx = w / 2 + rad * math.sin(alpha) - local sy = h / 2 + rad * math.cos(alpha) - tri_down[#tri_down + 1] = sx - tri_down[#tri_down + 1] = sy - end - - g.polygon("fill", tri_up) - g.polygon("fill", tri_down) - - local points = self:calculateIntersections(tri_up, tri_down) - - local borderVertices = { - tri_up[1], tri_up[2], - points[1], points[2], - tri_down[3], tri_down[4], - points[3], points[4], - tri_up[5], tri_up[6], - points[5], points[6], - tri_down[1], tri_down[2], - points[7], points[8], - tri_up[3], tri_up[4], - points[9], points[10], - tri_down[5], tri_down[6], - points[11], points[12], - tri_up[1], tri_up[2], - tri_down[3], tri_down[4], - } - - local oldcolor = {g.getColor()} - g.setColor(self.borderColor) - g.polygon("line", borderVertices) - g.setColor(oldcolor) -end - -function signal:rhombus(x, y, w, h) - local delta = 6 - g.polygon("fill", {x + delta, y + h / 2, x + w / 2, y + h - delta, - x + w - delta, y + h / 2, - x + w / 2, y + delta}) - g.setColor(self.borderColor) - g.polygon("line", {x + delta, y + h / 2, x + w / 2, y + h - delta, - x + w - delta, y + h / 2, - x + w / 2, y + delta}) -end - --- параметры - hump.vector --- источник: https://users.livejournal.com/-winnie/152327.html -function intersection(start1, end1, start2, end2) - assert(vector.isvector(start1) and vector.isvector(end1) and - vector.isvector(start2) and vector.isvector(end2)) - - local dir1 = end1 - start1; - local dir2 = end2 - start2; - - --считаем уравнения прямых проходящих через отрезки - local a1 = -dir1.y; - local b1 = dir1.x; - local d1 = -(a1*start1.x + b1*start1.y); - - local a2 = -dir2.y; - local b2 = dir2.x; - local d2 = -(a2*start2.x + b2*start2.y); - - --подставляем концы отрезков, для выяснения в каких полуплоскотях они - local seg1_line2_start = a2 * start1.x + b2 * start1.y + d2; - local seg1_line2_end = a2 * end1.x + b2 * end1.y + d2; - - local seg2_line1_start = a1 * start2.x + b1 * start2.y + d1; - local seg2_line1_end = a1 * end2.x + b1 * end2.y + d1; - - --если концы одного отрезка имеют один знак, значит он в одной полуплоскости и пересечения нет. - if (seg1_line2_start * seg1_line2_end >= 0 or - seg2_line1_start * seg2_line1_end >= 0) then - return nil - end - - local u = seg1_line2_start / (seg1_line2_start - seg1_line2_end); - - return start1 + u*dir1; -end - -return { - new = signal.new, -} +require("love") +require("hex") +require("vector") + +local g = love.graphics diff --git a/signal.tl b/signal.tl index 19a236e..dac7c65 100644 --- a/signal.tl +++ b/signal.tl @@ -4,11 +4,15 @@ require "vector" local g = love.graphics +--[[ +Что делает этот класс? +--]] +--[[ global type SignalView = record new: function(Hex, number, number, any, number, string): SignalView setCorner: function(SignalView, number, number) resize: function(SignalView, number, number) - draw2Canvas: function(SignalView, number) + draw2Canvas: function(SignalView, integer) drawFigures2Canvas: function(SignalView) draw: function(SignalView, number, number, string, {number}) @@ -42,10 +46,8 @@ local enum Types "trupdown" end ---[[ -- Типы сигналов и их порядок в канвасах слева на право: -- quad, circle, rhombus, trup, trdown, trupdown ---]] local types: {string} = {"quad", "circle", "rhombus", "trup", "trdown", "trupdown"} -- параметры - hump.vector @@ -120,6 +122,7 @@ function SignalView.new(hexfield: H, startcx: number, startcy: number, map: {{nu self:resize(self.width) return self end +--]] --[[ function signal:exampleFilling() @@ -171,6 +174,7 @@ end -- установить координаты левого верхнего угла, от которого идет отсчет ячеек. -- обязательно вызывать перед рисовкой. +--[[ function SignalView:setCorner(x: number, y: number) self.x0, self.y0 = x, y end @@ -187,7 +191,7 @@ function SignalView:resize(width: number) self:drawFigures2Canvas() end -function SignalView:draw2Canvas(index: number) +function SignalView:draw2Canvas(index: integer) --local xd, yd = 1, 1 --local border = 5 --local w, h = self.width - border * 2, self.width - border * 2 @@ -421,3 +425,5 @@ return { new = SignalView.new, } + +--]] diff --git a/tiledbackground.lua b/tiledbackground.lua index bb44680..9572766 100644 --- a/tiledbackground.lua +++ b/tiledbackground.lua @@ -1,46 +1,60 @@ +local _tl_compat; if (tonumber((_VERSION or ''):match('[%d.]*$')) or 0) < 5.3 then local p, m = pcall(require, 'compat53.module'); if p then _tl_compat = m end end; local math = _tl_compat and _tl_compat.math or math; require("love") local gr = love.graphics -local TiledBackround = {} -TiledBackround.__index = TiledBackround + TiledBackround = {} + + + + + + + + + +local TiledBackround_mt = { + __index = TiledBackround, +} + function TiledBackround:new() - local self = setmetatable({}, TiledBackround) - self.img = gr.newImage("gfx/tile1.png") - self:prepareDrawing() - return self + + local self = setmetatable({}, TiledBackround_mt) + self.img = gr.newImage("gfx/tile1.png") + self:prepareDrawing() + return self end function TiledBackround:prepareDrawing() - local w, h = gr.getDimensions() - self.canvas = gr.newCanvas(w, h) - gr.clear(0, 0, 0, 0) - gr.setColor{1, 1, 1} - gr.setCanvas(self.canvas) - local cam = require "camera".new() - cam:zoom(0.12) - local maxi, maxj = math.ceil(h / (self.img:getHeight() * cam.scale)), math.ceil(w / (self.img:getWidth() * cam.scale)) - local k = 1 / cam.scale - cam:lookAt((w / 2) * k, (h / 2) * k) - cam:attach() - for i = 0, maxi do - for j = 0, maxj do - gr.draw(self.img, j * self.img:getWidth(), i * self.img:getHeight()) - end - end - cam:detach() - gr.setCanvas() - --self.canvas:newImageData():encode("png", "tiledback.png") + local w, h = gr.getDimensions() + self.canvas = gr.newCanvas(w, h) + gr.clear(0, 0, 0, 0) + gr.setColor({ 1, 1, 1 }) + gr.setCanvas(self.canvas) + local cam = require("camera").new() + cam:zoom(0.12) + local maxi, maxj = math.ceil(h / (self.img:getHeight() * cam.scale)), math.ceil(w / (self.img:getWidth() * cam.scale)) + local k = 1 / cam.scale + cam:lookAt((w / 2) * k, (h / 2) * k) + cam:attach() + for i = 0, maxi do + for j = 0, maxj do + gr.draw(self.img, j * self.img:getWidth(), i * self.img:getHeight()) + end + end + cam:detach() + gr.setCanvas() + end function TiledBackround:draw(alpha) - gr.clear(0, 0, 0, 0) - gr.setColor(1, 1, 1, alpha or 1) - gr.draw(self.canvas, 0, 0) + gr.clear(0, 0, 0, 0) + gr.setColor(1, 1, 1, alpha or 1) + gr.draw(self.canvas, 0, 0) end function TiledBackround:resize(neww, newh) - self:prepareDrawing() + self:prepareDrawing() end return TiledBackround