From 779fcbabccf7e3513912db6d3c86cccdb635653a Mon Sep 17 00:00:00 2001 From: LDDestroier Date: Thu, 25 Oct 2018 14:53:18 -0400 Subject: [PATCH 1/5] Started working on fill tool it's been too long --- pain.lua | 70 +++++++++++++++----------------------------------------- 1 file changed, 18 insertions(+), 52 deletions(-) diff --git a/pain.lua b/pain.lua index 9e1df7b..379d771 100644 --- a/pain.lua +++ b/pain.lua @@ -1,10 +1,12 @@ --[[ PAIN image editor for ComputerCraft Get it with - wget https://raw.githubusercontent.com/LDDestroier/CC/master/pain.lua + wget https://raw.githubusercontent.com/LDDestroier/CC/beta/pain.lua std ld pain pain - This is a stable release. You fool! + This is a beta release. You fool! + To do: + + a god damned fill function --]] local askToSerialize = false local defaultSaveFormat = 4 -- will change if importing image, or making new file with extension in name @@ -135,7 +137,7 @@ local explode = function(div,str) return arr end -local function cutString(max_line_length, str) -- from stack overflow +local cutString = function(max_line_length, str) -- from stack overflow local lines = {} local line str:gsub('(%s*)(%S+)', @@ -642,58 +644,22 @@ local getOnscreenCoords = function(tbl,_x,_y) end end -local fillTool = function(info,cx,cy,color,layer) -- takes a frame, not the whole paintEncoded - local x,y +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 output = {} - for a = 1, #info do - if (info[a].x == cx) and (info[a].y == cy) then - x = cx - y = cy - replaceColor = info[a].b - break - end + for a = 1, #frame do + maxX = math.max(maxX, frame[a].x) + maxY = math.max(maxY, frame[a].y) + mixX = math.min(maxX, frame[a].x) + minY = math.min(maxY, frame[a].y) end - if not x and y then - return - end - if color == replaceColor then - return - end - table.insert(output,{ - ["x"] = x, - ["y"] = y, - ["b"] = color, - ["t"] = color, - ["c"] = " ", - ["m"] = paint.m - }) - local loops = 0 - local tAffectedPoints = { - [1] = { - x = x+tTerm.scroll.x, - z = z+tTerm.scroll.z - } - } - while #tAffectedPoints > 0 do - if loops%200 == 0 then - sleep(0.05) + local touched = {} + local check = {dot.x, dot.y} + while true do + for a = 1, #check do + --do finish please... end - for i=-1,1,2 do - local x = tAffectedPoints[1]["x"]+i - local z = tAffectedPoints[1]["z"] - if tBlueprint[layer][x][z] == replaceColor and x >= tTerm.viewable.sX and x <= tTerm.viewable.eX and z >= tTerm.viewable.sZ and z <= tTerm.viewable.eZ then - drawPoint(x,z,color,layer,true,true) - table.insert(tAffectedPoints,{["x"] = x,["z"] = z}) - end - x = tAffectedPoints[1]["x"] - z = tAffectedPoints[1]["z"]+i - if tBlueprint[layer][x][z] == replaceColor and x >= tTerm.viewable.sX and x <= tTerm.viewable.eX and z >= tTerm.viewable.sZ and z <= tTerm.viewable.eZ then - drawPoint(x,z,color,layer,true,true) - table.insert(tAffectedPoints,{["x"] = x,["z"] = z}) - end - end - table.remove(tAffectedPoints,1) - loops = loops+1 end end From ef9b122f24f55b6b7b03760d32893a4ffa51ac2e Mon Sep 17 00:00:00 2001 From: LDDestroier Date: Thu, 25 Oct 2018 19:05:37 -0400 Subject: [PATCH 2/5] Added fill tool (hopefully) --- pain.lua | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 58 insertions(+), 3 deletions(-) diff --git a/pain.lua b/pain.lua index 379d771..a64dc5c 100644 --- a/pain.lua +++ b/pain.lua @@ -655,10 +655,45 @@ local fillTool = function(frame,cx,cy,dot) -- takes a frame, not the whole paint minY = math.min(maxY, frame[a].y) end local touched = {} - local check = {dot.x, dot.y} + local check = {{dot.x, dot.y}} + local chkpos = function(x, y) + if (x < minX or x > maxX) or (y < minY or y > maxY) then + return false + else + for a = 1, #touched do + if (touched[1] == x and touched[2] == y) then + return false + end + end + return true + end + end + local a = 0 while true do - for a = 1, #check do - --do finish please... + a = a + 1 + chX, chY = check[a].x, check[a].y + frame[#frame+1] = { + x = check[a].x, + y = check[a].y, + 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 @@ -2512,6 +2547,26 @@ local getInput = function() --gotta catch them all changedImage = true isDragging = false end + if key == keys.f and not (keysDown[keys.leftShift] or keysDown[keys.rightShift]) then + local mevt + repeat + mevt = {os.pullEvent()} + until (mevt[1] == "key" and mevt[2] == keys.x) or (mevt[2] == 1 and (mevt[4] or scr_y) < scr_y-(renderBlittle and 0 or doRenderBar)) + if not (mevt[1] == "key" and mevt[2] == keys.x) then + local x,y = mevt[3],mevt[4] + if renderBlittle then + x = 2*x + y = 3*y + end + fillTool(paintEncoded[frame], x, y, paint) + miceDown = {} + keysDown = {} + end + doRender = true + changedImage = true + isDragging = false + renderBottomBar("Click to fill region.") + end if key == keys.p then renderBottomBar("Pick color with cursor:") paintEncoded = clearAllRedundant(paintEncoded) From b78fb561312eb7e3663c8ba444155ba146b27982 Mon Sep 17 00:00:00 2001 From: LDDestroier Date: Thu, 25 Oct 2018 19:10:10 -0400 Subject: [PATCH 3/5] Update pain.lua --- pain.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pain.lua b/pain.lua index a64dc5c..398620f 100644 --- a/pain.lua +++ b/pain.lua @@ -655,7 +655,7 @@ local fillTool = function(frame,cx,cy,dot) -- takes a frame, not the whole paint minY = math.min(maxY, frame[a].y) end local touched = {} - local check = {{dot.x, dot.y}} + local check = {{cx+paint.scrollX, cy+paint.scrollY}} local chkpos = function(x, y) if (x < minX or x > maxX) or (y < minY or y > maxY) then return false @@ -2548,6 +2548,7 @@ local getInput = function() --gotta catch them all isDragging = false end if key == keys.f and not (keysDown[keys.leftShift] or keysDown[keys.rightShift]) then + renderBottomBar("Click to fill area.") local mevt repeat mevt = {os.pullEvent()} From 4c921fb8c85e22af2d2d30487c3fff53efd9f8fc Mon Sep 17 00:00:00 2001 From: LDDestroier Date: Fri, 26 Oct 2018 10:18:51 -0400 Subject: [PATCH 4/5] Update pain.lua --- pain.lua | 39 +++++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/pain.lua b/pain.lua index 398620f..63efac8 100644 --- a/pain.lua +++ b/pain.lua @@ -647,34 +647,61 @@ 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) - mixX = math.min(maxX, frame[a].x) - minY = math.min(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 = {{cx+paint.scrollX, cy+paint.scrollY}} + 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].x, check[a].y + chX, chY = check[a][1], check[a][2] frame[#frame+1] = { - x = check[a].x, - y = check[a].y, + x = chX, + y = chY, c = dot.c, t = dot.t, b = dot.b From 44e17e831dfb742ad7993c52211f2e4183d5bde2 Mon Sep 17 00:00:00 2001 From: LDDestroier Date: Fri, 26 Oct 2018 13:21:46 -0400 Subject: [PATCH 5/5] 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