From f228db33f28a5dd205901212522085fc830adde9 Mon Sep 17 00:00:00 2001 From: Robert Jelic <36573031+NoryiE@users.noreply.github.com> Date: Wed, 21 Sep 2022 22:07:33 +0200 Subject: [PATCH] Bimg - added some basic bimg support - added basaltdraw.blit (and frame.blit for internal use) --- Basalt/Frame.lua | 13 ++- Basalt/Object.lua | 11 +- Basalt/libraries/basaltDraw.lua | 50 +++++++++ Basalt/libraries/images.lua | 32 ++++++ Basalt/objects/Image.lua | 185 +++++--------------------------- 5 files changed, 118 insertions(+), 173 deletions(-) create mode 100644 Basalt/libraries/images.lua diff --git a/Basalt/Frame.lua b/Basalt/Frame.lua index c225374..af49f20 100644 --- a/Basalt/Frame.lua +++ b/Basalt/Frame.lua @@ -1055,13 +1055,20 @@ return function(name, parent, pTerm, basalt) end end; - blit = function (self, x, y, t, b, f) + blit = function (self, x, y, t, f, b) local obx, oby = self:getAnchorPosition() if (y >= 1) and (y <= self:getHeight()) then + local w = self:getWidth() if (self.parent ~= nil) then - self.parent:blit(max(x + (obx - 1), obx), oby + y - 1, sub(text, max(1 - x + 1, 1), self:getWidth() - x + 1), bgCol, fgCol) + t = sub(t, max(1 - x + 1, 1), w - x + 1) + f = sub(f, max(1 - x + 1, 1), w - x + 1) + b = sub(b, max(1 - x + 1, 1), w - x + 1) + self.parent:blit(max(x + (obx - 1), obx), oby + y - 1, t, f, b) else - basaltDraw.blit(max(x + (obx - 1), obx), oby + y - 1, sub(text, max(1 - x + 1, 1), max(self:getWidth() - x + 1,1)), bgCol, fgCol) + t = sub(t, max(1 - x + 1, 1), max(w - x + 1,1)) + f = sub(f, max(1 - x + 1, 1), max(w - x + 1,1)) + b = sub(b, max(1 - x + 1, 1), max(w - x + 1,1)) + basaltDraw.blit(max(x + (obx - 1), obx), oby + y - 1, t, f, b) end end end, diff --git a/Basalt/Object.lua b/Basalt/Object.lua index 98f9dff..8c1df18 100644 --- a/Basalt/Object.lua +++ b/Basalt/Object.lua @@ -784,16 +784,9 @@ return function(name) dragHandler = function(self, button, x, y) if(isDragging)then - local xO, yO, parentX, parentY = 0, 0, 1, 1 - if (self.parent ~= nil) then - xO, yO = self.parent:getOffsetInternal() - xO = xO < 0 and math.abs(xO) or -xO - yO = yO < 0 and math.abs(yO) or -yO - parentX, parentY = self.parent:getAbsolutePosition(self.parent:getAnchorPosition()) - end - local dX, dY = x + dragXOffset - (parentX - 1) + xO, y + dragYOffset - (parentY - 1) + yO - local val = eventSystem:sendEvent("mouse_drag", self, "mouse_drag", button, dX, dY, dragStartX-x, dragStartY-y, x, y) local objX, objY = self:getAbsolutePosition(self:getAnchorPosition()) + local dX, dY = x - objX + 1, y - objY + 1 + local val = eventSystem:sendEvent("mouse_drag", self, "mouse_drag", button, dX, dY, dragStartX-x, dragStartY-y, x, y) dragStartX, dragStartY = x, y if(val~=nil)then return val end if(self.parent~=nil)then diff --git a/Basalt/libraries/basaltDraw.lua b/Basalt/libraries/basaltDraw.lua index 778ac9d..c4fb1b5 100644 --- a/Basalt/libraries/basaltDraw.lua +++ b/Basalt/libraries/basaltDraw.lua @@ -126,6 +126,52 @@ return function(drawTerm) end end + local function blit(x, y, t, fg, bg) + if(#t == #fg)or(#t == #bg)then + if (y >= 1) and (y <= height) then + if (x + t:len() > 0) and (x <= width) then + local oldCacheT = cacheT[y] + local oldCacheFG = cacheFG[y] + local oldCacheBG = cacheBG[y] + local newCacheT, newCacheFG, newCacheBG + local nEnd = x + #t - 1 + + if (x < 1) then + local startN = 1 - x + 1 + local endN = width - x + 1 + t = sub(t, startN, endN) + fg = sub(fg, startN, endN) + bg = sub(bg, startN, endN) + elseif (nEnd > width) then + local endN = width - x + 1 + t = sub(t, 1, endN) + fg = sub(fg, 1, endN) + bg = sub(bg, 1, endN) + end + + if (x > 1) then + local endN = x - 1 + newCacheT = sub(oldCacheT, 1, endN) .. t + newCacheFG = sub(oldCacheFG, 1, endN) .. fg + newCacheBG = sub(oldCacheBG, 1, endN) .. bg + else + newCacheT = t + newCacheFG = fg + newCacheBG = bg + end + if nEnd < width then + newCacheT = newCacheT .. sub(oldCacheT, nEnd + 1, width) + newCacheFG = newCacheFG .. sub(oldCacheFG, nEnd + 1, width) + newCacheBG = newCacheBG .. sub(oldCacheBG, nEnd + 1, width) + end + cacheT[y] = newCacheT + cacheFG[y] = newCacheFG + cacheBG[y] = newCacheBG + end + end + end + end + local drawHelper = { setSize = function(w, h) width, height = w, h @@ -147,6 +193,10 @@ return function(drawTerm) setFG(x, y, colorStr) end; + blit = function(x, y, t, fg, bg) + blit(x, y, t, fg, bg) + end, + drawBackgroundBox = function(x, y, width, height, bgCol) for n = 1, height do setBG(x, y + (n - 1), rep(tHex[bgCol], width)) diff --git a/Basalt/libraries/images.lua b/Basalt/libraries/images.lua new file mode 100644 index 0000000..b5fcb94 --- /dev/null +++ b/Basalt/libraries/images.lua @@ -0,0 +1,32 @@ +local function loadNFP(path) + return paintutils.loadImage(path), "nfp" +end + +local function loadBIMG(path) + local f = fs.open(path, "r") + local content = load("return "..f.readAll())() + f.close() + if(content~=nil)then + return content, "bimg" + end +end + +local function loadImage(path, f) + if(f==nil)then + if(path:find(".bimg"))then + return loadBIMG(path) + elseif(path:find(".bbf"))then + return loadBBF(path) + else + return loadNFP(path) + end + end + -- ... +end + +return { + loadNFP = loadNFP, + loadBIMG = loadBIMG, + loadImage = loadImage, + +} \ No newline at end of file diff --git a/Basalt/objects/Image.lua b/Basalt/objects/Image.lua index b4d62f7..3b4533b 100644 --- a/Basalt/objects/Image.lua +++ b/Basalt/objects/Image.lua @@ -1,135 +1,15 @@ local Object = require("Object") local xmlValue = require("utils").getValueFromXML +local images = require("images") +local unpack = table.unpack return function(name) -- Image local base = Object(name) local objectType = "Image" base:setZIndex(2) local image - local shrinkedImage - local imageGotShrinked = false - - local function shrink() - -- shrinkSystem is copy pasted (and slightly changed) from blittle by Bomb Bloke: http://www.computercraft.info/forums2/index.php?/topic/25354-cc-176-blittle-api/ - local relations = { [0] = { 8, 4, 3, 6, 5 }, { 4, 14, 8, 7 }, { 6, 10, 8, 7 }, { 9, 11, 8, 0 }, { 1, 14, 8, 0 }, { 13, 12, 8, 0 }, { 2, 10, 8, 0 }, { 15, 8, 10, 11, 12, 14 }, - { 0, 7, 1, 9, 2, 13 }, { 3, 11, 8, 7 }, { 2, 6, 7, 15 }, { 9, 3, 7, 15 }, { 13, 5, 7, 15 }, { 5, 12, 8, 7 }, { 1, 4, 7, 15 }, { 7, 10, 11, 12, 14 } } - - local colourNum, exponents, colourChar = {}, {}, {} - for i = 0, 15 do - exponents[2 ^ i] = i - end - do - local hex = "0123456789abcdef" - for i = 1, 16 do - colourNum[hex:sub(i, i)] = i - 1 - colourNum[i - 1] = hex:sub(i, i) - colourChar[hex:sub(i, i)] = 2 ^ (i - 1) - colourChar[2 ^ (i - 1)] = hex:sub(i, i) - - local thisRel = relations[i - 1] - for i = 1, #thisRel do - thisRel[i] = 2 ^ thisRel[i] - end - end - end - - local function getBestColourMatch(usage) - local lastCol = relations[exponents[usage[#usage][1]]] - - for j = 1, #lastCol do - local thisRelation = lastCol[j] - for i = 1, #usage - 1 do - if usage[i][1] == thisRelation then - return i - end - end - end - - return 1 - end - - local function colsToChar(pattern, totals) - if not totals then - local newPattern = {} - totals = {} - for i = 1, 6 do - local thisVal = pattern[i] - local thisTot = totals[thisVal] - totals[thisVal], newPattern[i] = thisTot and (thisTot + 1) or 1, thisVal - end - pattern = newPattern - end - - local usage = {} - for key, value in pairs(totals) do - usage[#usage + 1] = { key, value } - end - - if #usage > 1 then - -- Reduce the chunk to two colours: - while #usage > 2 do - table.sort(usage, function(a, b) - return a[2] > b[2] - end) - local matchToInd, usageLen = getBestColourMatch(usage), #usage - local matchFrom, matchTo = usage[usageLen][1], usage[matchToInd][1] - for i = 1, 6 do - if pattern[i] == matchFrom then - pattern[i] = matchTo - usage[matchToInd][2] = usage[matchToInd][2] + 1 - end - end - usage[usageLen] = nil - end - - -- Convert to character. Adapted from oli414's function: - -- http://www.computercraft.info/forums2/index.php?/topic/25340-cc-176-easy-drawing-characters/ - local data = 128 - for i = 1, #pattern - 1 do - if pattern[i] ~= pattern[6] then - data = data + 2 ^ (i - 1) - end - end - return string.char(data), colourChar[usage[1][1] == pattern[6] and usage[2][1] or usage[1][1]], colourChar[pattern[6]] - else - -- Solid colour character: - return "\128", colourChar[pattern[1]], colourChar[pattern[1]] - end - end - - local results, width, height, bgCol = { {}, {}, {} }, 0, #image + #image % 3, base.bgColor or colors.black - for i = 1, #image do - if #image[i] > width then - width = #image[i] - end - end - - for y = 0, height - 1, 3 do - local cRow, tRow, bRow, counter = {}, {}, {}, 1 - - for x = 0, width - 1, 2 do - -- Grab a 2x3 chunk: - local pattern, totals = {}, {} - - for yy = 1, 3 do - for xx = 1, 2 do - pattern[#pattern + 1] = (image[y + yy] and image[y + yy][x + xx]) and (image[y + yy][x + xx] == 0 and bgCol or image[y + yy][x + xx]) or bgCol - totals[pattern[#pattern]] = totals[pattern[#pattern]] and (totals[pattern[#pattern]] + 1) or 1 - end - end - - cRow[counter], tRow[counter], bRow[counter] = colsToChar(pattern, totals) - counter = counter + 1 - end - - results[1][#results[1] + 1], results[2][#results[2] + 1], results[3][#results[3] + 1] = table.concat(cRow), table.concat(tRow), table.concat(bRow) - end - - results.width, results.height = #results[1][1], #results[1] - - shrinkedImage = results - end + local format = "nfp" local object = { init = function(self) @@ -139,58 +19,41 @@ return function(name) return objectType end; - loadImage = function(self, path) - image = paintutils.loadImage(path) - imageGotShrinked = false + loadImage = function(self, path, f) + image, _format = images.loadImage(path, f) + if(_format~=nil)then + format = _format + end self:updateDraw() return self end; + setImage = function(self, data, _format) + iamge = data + format = _format + end, - shrink = function(self) - shrink() - imageGotShrinked = true - self:updateDraw() - return self - end; + getImageData = function(self) + return image + end, setValuesByXMLData = function(self, data) base.setValuesByXMLData(self, data) - if(xmlValue("shrink", data)~=nil)then if(xmlValue("shrink", data))then self:shrink() end end if(xmlValue("path", data)~=nil)then self:loadImage(xmlValue("path", data)) end return self end, draw = function(self) if (base.draw(self)) then - if (self.parent ~= nil) then - if (image ~= nil) then - local obx, oby = self:getAnchorPosition() - local w,h = self:getSize() - if (imageGotShrinked) then - -- this is copy pasted (and slightly changed) from blittle by Bomb Bloke: http://www.computercraft.info/forums2/index.php?/topic/25354-cc-176-blittle-api/ - local t, tC, bC = shrinkedImage[1], shrinkedImage[2], shrinkedImage[3] - for i = 1, math.min(shrinkedImage.height, h) do - local tI = t[i] - if type(tI) == "string" then - self.parent:setText(obx, oby + i - 1, tI:sub(1,w)) - self.parent:setFG(obx, oby + i - 1, tC[i]:sub(1,w)) - self.parent:setBG(obx, oby + i - 1, bC[i]:sub(1,w)) - elseif type(tI) == "table" then - self.parent:setText(obx, oby + i - 1, tI[2]:sub(1,w)) - self.parent:setFG(obx, oby + i - 1, tC[i]:sub(1,w)) - self.parent:setBG(obx, oby + i - 1, bC[i]:sub(1,w)) - end - end - else - for yPos = 1, math.min(#image, h) do - local line = image[yPos] - for xPos = 1, math.min(#line, w) do - if line[xPos] > 0 then - self.parent:drawBackgroundBox(obx + xPos - 1, oby + yPos - 1, 1, 1, line[xPos]) - end - end - end + if (image ~= nil) then + local obx, oby = self:getAnchorPosition() + local w,h = self:getSize() + if(format=="nfp")then + + elseif(format=="bimg")then + for y,v in ipairs(image[1])do + self.parent:blit(obx, oby+y-1, unpack(v)) + end end end