From 44e17e831dfb742ad7993c52211f2e4183d5bde2 Mon Sep 17 00:00:00 2001 From: LDDestroier Date: Fri, 26 Oct 2018 13:21:46 -0400 Subject: [PATCH] Fixed up fillTool finally FINALLY it works and hey, it doesn't crash when: a. exposed to the infinite canvas, or b. when tasked with filling more than 256 dots and it's animated, and can optionally fill diagonal --- pain.lua | 240 ++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 151 insertions(+), 89 deletions(-) diff --git a/pain.lua b/pain.lua index 63efac8..64592b9 100644 --- a/pain.lua +++ b/pain.lua @@ -1,12 +1,10 @@ --[[ PAIN image editor for ComputerCraft Get it with - wget https://raw.githubusercontent.com/LDDestroier/CC/beta/pain.lua + wget https://raw.githubusercontent.com/LDDestroier/CC/master/pain.lua std ld pain pain - This is a beta release. You fool! - To do: - + a god damned fill function + This is a stable release. You fool! --]] local askToSerialize = false local defaultSaveFormat = 4 -- will change if importing image, or making new file with extension in name @@ -23,6 +21,9 @@ local readNonImageAsNFP = true local useFlattenGIF = true local undoBufferSize = 8 +local doFillDiagonal = false -- checks for diagonal dots when using fill tool +local doFillAnimation = true -- whether or not to animate the fill tool + local displayHelp = function() local progname = fs.getName(shell.getRunningProgram()) print(progname) @@ -644,87 +645,6 @@ local getOnscreenCoords = function(tbl,_x,_y) end end -local fillTool = function(frame,cx,cy,dot) -- takes a frame, not the whole paintEncoded - local maxX, maxY = 0, 0 - local minX, minY = 0, 0 - local scx, scy = cx+paint.scrollX, cy+paint.scrollY - local output = {} - local initDot - for a = 1, #frame do - maxX = math.max(maxX, frame[a].x) - maxY = math.max(maxY, frame[a].y) - minX = math.min(minX, frame[a].x) - minY = math.min(minY, frame[a].y) - end - local doop = {} - for y = minY, maxY do - doop[y] = {} - for x = minX, maxX do - doop[y][x] = false - end - end - for a = 1, #frame do - doop[frame[a].y][frame[a].x] = frame[a] - if frame[a].x == scx and frame[a].y == scy then - initDot = frame[a] - end - end - local touched = {} - local check = {{scx, scy}} - local chkpos = function(x, y) - if (x < minX or x > maxX) or (y < minY or y > maxY) then - return false - else - if initDot then - if (doop[y][x].b ~= initDot.b) or (doop[y][x].t ~= initDot.t) or (doop[y][x].c ~= initDot.c) then - return false - end - elseif doop[y][x] then - return false - end - for a = 1, #touched do - if (touched[1] == x and touched[2] == y) then - return false - end - end - for a = 1, #check do - if (check[1] == x and check[2] == y) then - return false - end - end - return true - end - end - local a = 0 - while true do - a = a + 1 - chX, chY = check[a][1], check[a][2] - frame[#frame+1] = { - x = chX, - y = chY, - c = dot.c, - t = dot.t, - b = dot.b - } - touched[#touched+1] = {chX, chY} - if chkpos(chX+1, chY) then - check[#check+1] = {chX+1, chY} - end - if chkpos(chX-1, chY) then - check[#check+1] = {chX-1, chY} - end - if chkpos(chX, chY+1) then - check[#check+1] = {chX, chY+1} - end - if chkpos(chX, chY-1) then - check[#check+1] = {chX, chY-1} - end - if #touched == #check then - break - end - end -end - local clearAllRedundant = function(info) local output = {} for a = 1, #info do @@ -1534,6 +1454,149 @@ local reRenderPAIN = function() doRenderBar = _reallyDoRenderBar end +local fillTool = function(_frame,cx,cy,dot) -- "_frame" is the frame NUMBER + local maxX, maxY = 0, 0 + local minX, minY = 0, 0 + paintEncoded = clearAllRedundant(paintEncoded) + local frame = paintEncoded[_frame] + local scx, scy = cx+paint.scrollX, cy+paint.scrollY + local output = {} + for a = 1, #frame do + maxX = math.max(maxX, frame[a].x) + maxY = math.max(maxY, frame[a].y) + minX = math.min(minX, frame[a].x) + minY = math.min(minY, frame[a].y) + end + + maxX = math.max(maxX, scx) + maxY = math.max(maxY, scy) + minX = math.min(minX, scx) + minY = math.min(minY, scy) + + maxX = math.max(maxX, screenEdges[1]) + maxY = math.max(maxY, screenEdges[2]) + + local doop = {} + local touched = {} + local check = {[scy] = {[scx] = true}} + for y = minY, maxY do + doop[y] = {} + touched[y] = {} + for x = minX, maxX do + doop[y][x] = { + c = " ", + b = 0, + t = 0 + } + touched[y][x] = false + end + end + for a = 1, #frame do + doop[frame[a].y][frame[a].x] = { + c = frame[a].c, + t = frame[a].t, + b = frame[a].b + } + end + local initDot = { + c = doop[scy][scx].c, + t = doop[scy][scx].t, + b = doop[scy][scx].b + } + local chkpos = function(x, y, checkList) + if (x < minX or x > maxX) or (y < minY or y > maxY) then + return false + else + if (doop[y][x].b ~= initDot.b) or (doop[y][x].t ~= initDot.t) or (doop[y][x].c ~= initDot.c) then + return false + end + if check[y] then + if check[y][x] then + return false + end + end + if touched[y][x] then + return false + end + return true + end + end + local doBreak + local step = 0 + while true do + doBreak = true + for chY, v in pairs(check) do + for chX, isTrue in pairs(v) do + if isTrue and (not touched[chY][chX]) then + step = step + 1 + if doFillAnimation then + if (chX-paint.scrollX >= 1 and chX-paint.scrollX <= scr_x and chY-paint.scrollY >= 1 and chY-paint.scrollY <= scr_y) then + reRenderPAIN() + end + end + frame[#frame+1] = { + x = chX, + y = chY, + c = dot.c, + t = dot.t, + b = dot.b + } + touched[chY][chX] = true + -- check adjacent + if chkpos(chX+1, chY) then + check[chY][chX+1] = true + doBreak = false + end + if chkpos(chX-1, chY) then + check[chY][chX-1] = true + doBreak = false + end + if chkpos(chX, chY+1) then + check[chY+1] = check[chY+1] or {} + check[chY+1][chX] = true + doBreak = false + end + if chkpos(chX, chY-1) then + check[chY-1] = check[chY-1] or {} + check[chY-1][chX] = true + doBreak = false + end + -- check diagonal + if doFillDiagonal then + if chkpos(chX-1, chY-1) then + check[chY-1] = check[chY-1] or {} + check[chY-1][chX-1] = true + doBreak = false + end + if chkpos(chX+1, chY-1) then + check[chY-1] = check[chY-1] or {} + check[chY-1][chX+1] = true + doBreak = false + end + if chkpos(chX-1, chY+1) then + check[chY+1] = check[chY+1] or {} + check[chY+1][chX-1] = true + doBreak = false + end + if chkpos(chX+1, chY+1) then + check[chY+1] = check[chY+1] or {} + check[chY+1][chX+1] = true + doBreak = false + end + end + if step % 1024 == 0 then -- tries to prevent crash + sleep(0) + end + end + end + end + if doBreak then + break + end + end + paintEncoded = clearAllRedundant(paintEncoded) +end + local boxCharSelector = function() local co = function(pos) if pos then @@ -2586,7 +2649,8 @@ local getInput = function() --gotta catch them all x = 2*x y = 3*y end - fillTool(paintEncoded[frame], x, y, paint) + renderBottomBar("Filling area...") + fillTool(frame, x, y, paint) miceDown = {} keysDown = {} end @@ -2790,7 +2854,7 @@ runPainEditor = function(...) --needs to be cleaned up write("That is a") sleep(0.1) term.setTextColor(colors.red) - write(" FUCKING") + write(" DAMNED") sleep(0.4) print(" FOLDER.") term.setTextColor(colors.white) @@ -2840,8 +2904,6 @@ runPainEditor = function(...) --needs to be cleaned up end end - --paintEncoded = tun(tse(paintEncoded):gsub("bg","b"):gsub("txt","t"):gsub("char","c"):gsub("meta","m")) -- gotta have backwards compatibility, sorta, okay maybe not - if not paintEncoded[frame] then paintEncoded = {paintEncoded} end if pMode == 1 then doRenderBar = 0