mirror of
				https://github.com/SquidDev-CC/CC-Tweaked
				synced 2025-10-30 21:23:00 +00:00 
			
		
		
		
	Use blit to draw boxes, add colors.toBlit (#570)
This commit is contained in:
		| @@ -269,3 +269,9 @@ Fix JSON objects failing to pass | ||||
| Maybe I should run the whole test suite, not just the things I think | ||||
| matter? Nah.... | ||||
| ``` | ||||
|  | ||||
| ```  | ||||
| 741adfa7bb2b950d2851c3f0072d6a4769f22773 | ||||
|  | ||||
| Use blit to draw boxes, add colors.toBlit (#570) | ||||
| ``` | ||||
|   | ||||
| @@ -196,7 +196,7 @@ green = 0x2000 | ||||
| red = 0x4000 | ||||
|  | ||||
| --- Black: Written as `f` in paint files and @{term.blit}, has a default | ||||
| -- terminal colour of #191919. | ||||
| -- terminal colour of #111111. | ||||
| black = 0x8000 | ||||
|  | ||||
| --- Combines a set of colors (or sets of colors) into a larger set. Useful for | ||||
| @@ -248,7 +248,6 @@ end | ||||
| --- Tests whether `color` is contained within `colors`. Useful for Bundled | ||||
| -- Cables. | ||||
| -- | ||||
| -- | ||||
| -- @tparam number colors A color, or color set | ||||
| -- @tparam number color A color or set of colors that `colors` should contain. | ||||
| -- @treturn boolean If `colors` contains all colors within `color`. | ||||
| @@ -279,7 +278,7 @@ function packRGB(r, g, b) | ||||
|     expect(2, g, "number") | ||||
|     expect(3, b, "number") | ||||
|     return | ||||
|         bit32.band(r * 255, 0xFF) * 2 ^ 16 + | ||||
|     bit32.band(r * 255, 0xFF) * 2 ^ 16 + | ||||
|         bit32.band(g * 255, 0xFF) * 2 ^ 8 + | ||||
|         bit32.band(b * 255, 0xFF) | ||||
| end | ||||
| @@ -299,9 +298,9 @@ end | ||||
| function unpackRGB(rgb) | ||||
|     expect(1, rgb, "number") | ||||
|     return | ||||
|         bit32.band(bit32.rshift(rgb, 16), 0xFF) / 255, | ||||
|         bit32.band(bit32.rshift(rgb, 8), 0xFF) / 255, | ||||
|         bit32.band(rgb, 0xFF) / 255 | ||||
|     bit32.band(bit32.rshift(rgb, 16), 0xFF) / 255, | ||||
|     bit32.band(bit32.rshift(rgb, 8), 0xFF) / 255, | ||||
|     bit32.band(rgb, 0xFF) / 255 | ||||
| end | ||||
|  | ||||
| --- Either calls @{colors.packRGB} or @{colors.unpackRGB}, depending on how many | ||||
| @@ -333,3 +332,21 @@ function rgb8(r, g, b) | ||||
|         return packRGB(r, g, b) | ||||
|     end | ||||
| end | ||||
|  | ||||
| -- Colour to hex lookup table for toBlit | ||||
| local color_hex_lookup = {} | ||||
| for i = 0, 15 do | ||||
|     color_hex_lookup[2 ^ i] = string.format("%x", i) | ||||
| end | ||||
|  | ||||
| --- Converts the given color to a paint/blit hex character (0-9a-f). | ||||
| -- | ||||
| -- This is equivalent to converting floor(log_2(color)) to hexadecimal. | ||||
| -- | ||||
| -- @tparam number color The color to convert. | ||||
| -- @treturn string The blit hex code of the color. | ||||
| function toBlit(color) | ||||
|     expect(1, color, "number") | ||||
|     return color_hex_lookup[color] or | ||||
|         string.format("%x", math.floor(math.log(color) / math.log(2))) | ||||
| end | ||||
|   | ||||
| @@ -23,6 +23,25 @@ local function parseLine(tImageArg, sLine) | ||||
|     table.insert(tImageArg, tLine) | ||||
| end | ||||
|  | ||||
| -- Sorts pairs of startX/startY/endX/endY such that the start is always the min | ||||
| local function sortCoords(startX, startY, endX, endY) | ||||
|     local minX, maxX, minY, maxY | ||||
|  | ||||
|     if startX <= endX then | ||||
|         minX, maxX = startX, endX | ||||
|     else | ||||
|         minX, maxX = endX, startX | ||||
|     end | ||||
|  | ||||
|     if startY <= endY then | ||||
|         minY, maxY = startY, endY | ||||
|     else | ||||
|         minY, maxY = endY, startY | ||||
|     end | ||||
|  | ||||
|     return minX, maxX, minY, maxY | ||||
| end | ||||
|  | ||||
| --- Parses an image from a multi-line string | ||||
| -- | ||||
| -- @tparam string image The string containing the raw-image data. | ||||
| @@ -71,9 +90,6 @@ function drawPixel(xPos, yPos, colour) | ||||
|     expect(2, yPos, "number") | ||||
|     expect(3, colour, "number", "nil") | ||||
|  | ||||
|     if type(xPos) ~= "number" then error("bad argument #1 (expected number, got " .. type(xPos) .. ")", 2) end | ||||
|     if type(yPos) ~= "number" then error("bad argument #2 (expected number, got " .. type(yPos) .. ")", 2) end | ||||
|     if colour ~= nil and type(colour) ~= "number" then error("bad argument #3 (expected number, got " .. type(colour) .. ")", 2) end | ||||
|     if colour then | ||||
|         term.setBackgroundColor(colour) | ||||
|     end | ||||
| @@ -111,17 +127,7 @@ function drawLine(startX, startY, endX, endY, colour) | ||||
|         return | ||||
|     end | ||||
|  | ||||
|     local minX = math.min(startX, endX) | ||||
|     local maxX, minY, maxY | ||||
|     if minX == startX then | ||||
|         minY = startY | ||||
|         maxX = endX | ||||
|         maxY = endY | ||||
|     else | ||||
|         minY = endY | ||||
|         maxX = startX | ||||
|         maxY = startY | ||||
|     end | ||||
|     local minX, maxX, minY, maxY = sortCoords(startX, startY, endX, endY) | ||||
|  | ||||
|     -- TODO: clip to screen rectangle? | ||||
|  | ||||
| @@ -177,37 +183,33 @@ function drawBox(startX, startY, endX, endY, nColour) | ||||
|     endY = math.floor(endY) | ||||
|  | ||||
|     if nColour then | ||||
|         term.setBackgroundColor(nColour) | ||||
|         term.setBackgroundColor(nColour) -- Maintain legacy behaviour | ||||
|     else | ||||
|         nColour = term.getBackgroundColour() | ||||
|     end | ||||
|     local colourHex = colours.toBlit(nColour) | ||||
|  | ||||
|     if startX == endX and startY == endY then | ||||
|         drawPixelInternal(startX, startY) | ||||
|         return | ||||
|     end | ||||
|  | ||||
|     local minX = math.min(startX, endX) | ||||
|     local maxX, minY, maxY | ||||
|     if minX == startX then | ||||
|         minY = startY | ||||
|         maxX = endX | ||||
|         maxY = endY | ||||
|     else | ||||
|         minY = endY | ||||
|         maxX = startX | ||||
|         maxY = startY | ||||
|     end | ||||
|     local minX, maxX, minY, maxY = sortCoords(startX, startY, endX, endY) | ||||
|     local width = maxX - minX + 1 | ||||
|  | ||||
|     for x = minX, maxX do | ||||
|         drawPixelInternal(x, minY) | ||||
|         drawPixelInternal(x, maxY) | ||||
|     end | ||||
|  | ||||
|     if maxY - minY >= 2 then | ||||
|         for y = minY + 1, maxY - 1 do | ||||
|             drawPixelInternal(minX, y) | ||||
|             drawPixelInternal(maxX, y) | ||||
|     for y = minY, maxY do | ||||
|         if y == minY or y == maxY then | ||||
|             term.setCursorPos(minX, y) | ||||
|             term.blit((" "):rep(width), colourHex:rep(width), colourHex:rep(width)) | ||||
|         else | ||||
|             term.setCursorPos(minX, y) | ||||
|             term.blit(" ", colourHex, colourHex) | ||||
|             term.setCursorPos(maxX, y) | ||||
|             term.blit(" ", colourHex, colourHex) | ||||
|         end | ||||
|     end | ||||
| end | ||||
|  | ||||
| --- Draws a filled box on the current term from the specified start position to | ||||
| -- the specified end position. | ||||
| -- | ||||
| @@ -233,29 +235,23 @@ function drawFilledBox(startX, startY, endX, endY, nColour) | ||||
|     endY = math.floor(endY) | ||||
|  | ||||
|     if nColour then | ||||
|         term.setBackgroundColor(nColour) | ||||
|         term.setBackgroundColor(nColour) -- Maintain legacy behaviour | ||||
|     else | ||||
|         nColour = term.getBackgroundColour() | ||||
|     end | ||||
|     local colourHex = colours.toBlit(nColour) | ||||
|  | ||||
|     if startX == endX and startY == endY then | ||||
|         drawPixelInternal(startX, startY) | ||||
|         return | ||||
|     end | ||||
|  | ||||
|     local minX = math.min(startX, endX) | ||||
|     local maxX, minY, maxY | ||||
|     if minX == startX then | ||||
|         minY = startY | ||||
|         maxX = endX | ||||
|         maxY = endY | ||||
|     else | ||||
|         minY = endY | ||||
|         maxX = startX | ||||
|         maxY = startY | ||||
|     end | ||||
|     local minX, maxX, minY, maxY = sortCoords(startX, startY, endX, endY) | ||||
|     local width = maxX - minX + 1 | ||||
|  | ||||
|     for x = minX, maxX do | ||||
|         for y = minY, maxY do | ||||
|             drawPixelInternal(x, y) | ||||
|         end | ||||
|     for y = minY, maxY do | ||||
|         term.setCursorPos(minX, y) | ||||
|         term.blit((" "):rep(width), colourHex:rep(width), colourHex:rep(width)) | ||||
|     end | ||||
| end | ||||
|  | ||||
|   | ||||
| @@ -73,4 +73,20 @@ describe("The colors library", function() | ||||
|         expect(colors.rgb8(0.3, 0.5, 0.6)):equals(0x4c7f99) | ||||
|         expect({ colors.rgb8(0x4c7f99) }):same { 0x4c / 0xFF, 0x7f / 0xFF, 0.6 } | ||||
|     end) | ||||
|  | ||||
|     describe("colors.toBlit", function() | ||||
|         it("validates arguments", function() | ||||
|             expect.error(colors.toBlit, nil):eq("bad argument #1 (expected number, got nil)") | ||||
|         end) | ||||
|  | ||||
|         it("converts all colors", function() | ||||
|             for i = 0, 15 do | ||||
|                 expect(colors.toBlit(2 ^ i)):eq(string.format("%x", i)) | ||||
|             end | ||||
|         end) | ||||
|  | ||||
|         it("floors colors", function() | ||||
|             expect(colors.toBlit(16385)):eq("e") | ||||
|         end) | ||||
|     end) | ||||
| end) | ||||
|   | ||||
| @@ -1,4 +1,19 @@ | ||||
| local with_window = require "test_helpers".with_window | ||||
|  | ||||
| describe("The paintutils library", function() | ||||
|     -- Verifies that a window's lines are equal to the given table of blit | ||||
|     -- strings ({{"text", "fg", "bg"}, {"text", "fg", "bg"}...}) | ||||
|     local function window_eq(w, state) | ||||
|         -- Verification of the size isn't really important in the tests, but | ||||
|         -- better safe than sorry. | ||||
|         local _, height = w.getSize() | ||||
|         expect(#state):eq(height) | ||||
|  | ||||
|         for line = 1, height do | ||||
|             expect({ w.getLine(line) }):same(state[line]) | ||||
|         end | ||||
|     end | ||||
|  | ||||
|     describe("paintutils.parseImage", function() | ||||
|         it("validates arguments", function() | ||||
|             paintutils.parseImage("") | ||||
| @@ -28,6 +43,30 @@ describe("The paintutils library", function() | ||||
|             expect.error(paintutils.drawLine, 1, 1, 1, nil):eq("bad argument #4 (expected number, got nil)") | ||||
|             expect.error(paintutils.drawLine, 1, 1, 1, 1, false):eq("bad argument #5 (expected number, got boolean)") | ||||
|         end) | ||||
|  | ||||
|         it("draws a line going across with custom colour", function() | ||||
|             local w = with_window(3, 2, function() | ||||
|                 paintutils.drawLine(1, 1, 3, 1, colours.red) | ||||
|             end) | ||||
|  | ||||
|             window_eq(w, { | ||||
|                 { "   ", "000", "eee" }, | ||||
|                 { "   ", "000", "fff" }, | ||||
|             }) | ||||
|         end) | ||||
|  | ||||
|         it("draws a line going diagonally with term colour", function() | ||||
|             local w = with_window(3, 3, function() | ||||
|                 term.setBackgroundColour(colours.red) | ||||
|                 paintutils.drawLine(1, 1, 3, 3) | ||||
|             end) | ||||
|  | ||||
|             window_eq(w, { | ||||
|                 { "   ", "000", "eff" }, | ||||
|                 { "   ", "000", "fef" }, | ||||
|                 { "   ", "000", "ffe" }, | ||||
|             }) | ||||
|         end) | ||||
|     end) | ||||
|  | ||||
|     describe("paintutils.drawBox", function() | ||||
| @@ -38,6 +77,45 @@ describe("The paintutils library", function() | ||||
|             expect.error(paintutils.drawBox, 1, 1, 1, nil):eq("bad argument #4 (expected number, got nil)") | ||||
|             expect.error(paintutils.drawBox, 1, 1, 1, 1, false):eq("bad argument #5 (expected number, got boolean)") | ||||
|         end) | ||||
|  | ||||
|         it("draws a box with term colour", function() | ||||
|             local w = with_window(3, 3, function() | ||||
|                 term.setBackgroundColour(colours.red) | ||||
|                 paintutils.drawBox(1, 1, 3, 3) | ||||
|             end) | ||||
|  | ||||
|             window_eq(w, { | ||||
|                 { "   ", "eee", "eee" }, | ||||
|                 { "   ", "e0e", "efe" }, | ||||
|                 { "   ", "eee", "eee" }, | ||||
|             }) | ||||
|         end) | ||||
|  | ||||
|         it("draws a box with custom colour", function() | ||||
|             local w = with_window(3, 3, function() | ||||
|                 paintutils.drawBox(1, 1, 3, 3, colours.red) | ||||
|             end) | ||||
|  | ||||
|             window_eq(w, { | ||||
|                 { "   ", "eee", "eee" }, | ||||
|                 { "   ", "e0e", "efe" }, | ||||
|                 { "   ", "eee", "eee" }, | ||||
|             }) | ||||
|         end) | ||||
|  | ||||
|         it("draws a box without overwriting existing content", function() | ||||
|             local w = with_window(3, 3, function() | ||||
|                 term.setCursorPos(2, 2) | ||||
|                 term.write("a") | ||||
|                 paintutils.drawBox(1, 1, 3, 3, colours.red) | ||||
|             end) | ||||
|  | ||||
|             window_eq(w, { | ||||
|                 { "   ", "eee", "eee" }, | ||||
|                 { " a ", "e0e", "efe" }, | ||||
|                 { "   ", "eee", "eee" }, | ||||
|             }) | ||||
|         end) | ||||
|     end) | ||||
|  | ||||
|     describe("paintutils.drawFilledBox", function() | ||||
| @@ -48,6 +126,31 @@ describe("The paintutils library", function() | ||||
|             expect.error(paintutils.drawFilledBox, 1, 1, 1, nil):eq("bad argument #4 (expected number, got nil)") | ||||
|             expect.error(paintutils.drawFilledBox, 1, 1, 1, 1, false):eq("bad argument #5 (expected number, got boolean)") | ||||
|         end) | ||||
|  | ||||
|         it("draws a filled box with term colour", function() | ||||
|             local w = with_window(3, 3, function() | ||||
|                 term.setBackgroundColour(colours.red) | ||||
|                 paintutils.drawFilledBox(1, 1, 3, 3) | ||||
|             end) | ||||
|  | ||||
|             window_eq(w, { | ||||
|                 { "   ", "eee", "eee" }, | ||||
|                 { "   ", "eee", "eee" }, | ||||
|                 { "   ", "eee", "eee" }, | ||||
|             }) | ||||
|         end) | ||||
|  | ||||
|         it("draws a filled box with custom colour", function() | ||||
|             local w = with_window(3, 3, function() | ||||
|                 paintutils.drawFilledBox(1, 1, 3, 3, colours.red) | ||||
|             end) | ||||
|  | ||||
|             window_eq(w, { | ||||
|                 { "   ", "eee", "eee" }, | ||||
|                 { "   ", "eee", "eee" }, | ||||
|                 { "   ", "eee", "eee" }, | ||||
|             }) | ||||
|         end) | ||||
|     end) | ||||
|  | ||||
|     describe("paintutils.drawImage", function() | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Merith-TK
					Merith-TK