From 7a01f6c63efe16895456c9bc6ccef69a5e4a98aa Mon Sep 17 00:00:00 2001 From: LDDestroier Date: Fri, 21 Dec 2018 03:31:16 -0500 Subject: [PATCH] Added PAIN 2 (WIP) I intend to remake PAIN, but better. More tools, less spaghetti, and a better UI. --- pain2.lua | 315 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 315 insertions(+) create mode 100644 pain2.lua diff --git a/pain2.lua b/pain2.lua new file mode 100644 index 0000000..46c557c --- /dev/null +++ b/pain2.lua @@ -0,0 +1,315 @@ +-- pain2 + +local scr_x, scr_y = term.getSize() +local mx, my = scr_x/2, scr_y/2 +local keysDown = {} +local miceDown = {} + +-- debug renderer is slower, but the normal one isn't functional yet +local useDebugRenderer = true + +local canvas = { + {{},{},{}} +} +local frame = 1 +local dot = 1 + +local pain = { + screenWidth = scr_x, + screenHeight = scr_y, + scrollX = 0, + scrollY = 0, + doRender = true, + dots = { + [0] = { + " ", + " ", + " " + }, + [1] = { + " ", + "f", + "0" + }, + [2] = { + " ", + "f", + "e" + }, + }, + tool = "pencil" +} + +local control = { + scrollUp = keys.up, -- decrease scrollY + scrollDown = keys.down, -- increase scrollY + scrollLeft = keys.left, -- decrease scrollX + scrollRight = keys.right, -- increase scrollX + moveMod = keys.leftShift, -- hold to move image instead of scrolling + creepMod = keys.leftAlt, -- hold to only scroll/move one dot at a time + toolSelect = keys.leftShift -- hold and push specific buttons to quick select tool +} + +-- converts hex colors to colors api, and back +local to_colors, to_blit = { + [' '] = 0, + ['0'] = 1, + ['1'] = 2, + ['2'] = 4, + ['3'] = 8, + ['4'] = 16, + ['5'] = 32, + ['6'] = 64, + ['7'] = 128, + ['8'] = 256, + ['9'] = 512, + ['a'] = 1024, + ['b'] = 2048, + ['c'] = 4096, + ['d'] = 8192, + ['e'] = 16384, + ['f'] = 32768, +}, {} +for k,v in pairs(to_colors) do + to_blit[v] = k +end + +-- takes two coordinates, and returns every point between the two +local getDotsInLine = function( startX, startY, endX, endY ) + local out = {} + startX = math.floor(startX) + startY = math.floor(startY) + endX = math.floor(endX) + endY = math.floor(endY) + if startX == endX and startY == endY then + out = {{x=startX,y=startY}} + return out + end + local minX = math.min( startX, endX ) + if minX == startX then + minY = startY + maxX = endX + maxY = endY + else + minY = endY + maxX = startX + maxY = startY + end + local xDiff = maxX - minX + local yDiff = maxY - minY + if xDiff > math.abs(yDiff) then + local y = minY + local dy = yDiff / xDiff + for x=minX,maxX do + out[#out+1] = {x=x,y=math.floor(y+0.5)} + y = y + dy + end + else + local x = minX + local dx = xDiff / yDiff + if maxY >= minY then + for y=minY,maxY do + out[#out+1] = {x=math.floor(x+0.5),y=y} + x = x + dx + end + else + for y=minY,maxY,-1 do + out[#out+1] = {x=math.floor(x+0.5),y=y} + x = x - dx + end + end + end + return out +end + +-- places a dot on the canvas, predictably enough +local placeDot = function(x, y, frame, dot) + if not canvas[frame][1][y] then + canvas[frame][1][y] = {} + canvas[frame][2][y] = {} + canvas[frame][3][y] = {} + end + canvas[frame][1][y][x] = dot[1] + canvas[frame][2][y][x] = dot[2] + canvas[frame][3][y][x] = dot[3] +end + +-- used for tools that involve dragging +local dragPos = {} + +-- every tool at your disposal +local tools = { + pencil = function(arg) + if arg.event == "mouse_click" then + if arg.button == 1 then + placeDot(arg.sx, arg.sy, frame, arg.dot) + elseif arg.button == 2 then + placeDot(arg.sx, arg.sy, frame, {" "," "," "}) + end + dragPos = {arg.sx, arg.sy} + else + if #dragPos == 0 then + dragPos = {arg.sx, arg.sy} + end + local poses = getDotsInLine(arg.sx, arg.sy, dragPos[1], dragPos[2]) + for i = 1, #poses do + if arg.button == 1 then + placeDot(poses[i].x, poses[i].y, frame, arg.dot) + elseif arg.button == 2 then + placeDot(poses[i].x, poses[i].y, frame, {" "," "," "}) + end + end + dragPos = {arg.sx, arg.sy} + end + end, + text = function(arg) + term.setCursorPos(arg.x, arg.y) + term.setTextColor(to_colors[arg.dot[2]]) + term.setBackgroundColor(to_colors[arg.dot[3]]) + local text = read() + -- re-render every keypress, requires custom read function + for i = 1, #text do + placeDot(arg.sx + i - 1, arg.sy, frame, {text:sub(i,i), dot[2], dot[3]}) + end + end +} + +local render = function(x, y, width, height) + local buffer = {{},{},{}} + local cx, cy + -- see, it wouldn't do if I just individually set the cursor position for every dot + if useDebugRenderer then + + term.clear() + local cx, cy + for yy, line in pairs(canvas[frame][1]) do + for xx, dot in pairs(canvas[frame][1][yy]) do + cx = xx - pain.scrollX + cy = yy - pain.scrollY + if cx >= x and cx <= (x + width - 1) and cy >= y and cy <= (x + width - 1) then + term.setCursorPos(cx, cy) + term.blit( + canvas[frame][1][yy][xx], + canvas[frame][2][yy][xx], + canvas[frame][3][yy][xx] + ) + end + end + end + + else + + for yy = y, height do + buffer[1][yy] = "" + buffer[2][yy] = "" + buffer[3][yy] = "" + for xx = x, width do + cx = xx - pain.scrollX + cy = yy - pain.scrollY + for c = 1, 3 do + buffer[c][yy] = buffer[c][yy] .. canvas[frame][c][cy]:sub(cx,cx) + end + end + end + for yy = 0, height - 1 do + for xx = 0, width - 1 do + term.setCursorPos(x + xx, y + yy) + term.blit(buffer[1][yy+1], buffer[2][yy+1], buffer[3][yy+1]) + end + end + + end +end + +local tryTool = function() + for butt = 1, 3 do + if miceDown[butt] and tools[pain.tool] then + tools[pain.tool]({ + x = miceDown[butt][1], + y = miceDown[butt][2], + sx = miceDown[butt][1] + pain.scrollX, + sy = miceDown[butt][2] + pain.scrollY, + dot = pain.dots[dot], + button = butt, + event = miceDown[butt][3] + }) + break + end + end +end + +getInput = function() + local evt + while true do + evt = {os.pullEvent()} + if evt[1] == "mouse_click" or evt[1] == "mouse_drag" then + miceDown[evt[2]] = {evt[3], evt[4], evt[1]} + elseif evt[1] == "key" then + keysDown[evt[2]] = true + elseif evt[1] == "mouse_up" then + miceDown[evt[2]] = false + elseif evt[1] == "key_up" then + keysDown[evt[2]] = false + end + tryTool() + end +end + +-- executes everything that doesn't run asynchronously +main = function() + while true do + + render(1, 1, scr_x, scr_y) + + -- handle scrolling + if keysDown[control.scrollLeft] then + pain.scrollX = pain.scrollX - 1 + end + if keysDown[control.scrollRight] then + pain.scrollX = pain.scrollX + 1 + end + if keysDown[control.scrollUp] then + pain.scrollY = pain.scrollY - 1 + end + if keysDown[control.scrollDown] then + pain.scrollY = pain.scrollY + 1 + end + + if keysDown[control.toolSelect] then + -- dot palette selection + if keysDown[keys.one] then + dot = 1 + elseif keysDown[keys.two] then + dot = 2 + elseif keysDown[keys.three] then + dot = 3 + elseif keysDown[keys.four] then + dot = 4 + elseif keysDown[keys.five] then + dot = 5 + elseif keysDown[keys.six] then + dot = 6 + elseif keysDown[keys.seven] then + dot = 7 + elseif keysDown[keys.eight] then + dot = 8 + elseif keysDown[keys.nine] then + dot = 9 + elseif keysDown[keys.zero] then + dot = 0 + end + -- tool selection + if keysDown[keys.p] then + pain.tool = "pencil" + elseif keysDown[keys.t] then + pain.tool = "text" + end + end + + sleep(0.05) + end +end + +term.clear() + +parallel.waitForAny( main, getInput )