Advertisement
Redxone

[WIP] 2BPP Image Viewer/Editor for CC

May 8th, 2018
464
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 27.03 KB | None | 0 0
  1.  
  2. -- ]] First a little documentation about how this format actually works.
  3.  
  4.  
  5. --[[
  6.    
  7.      I find visual illistrations the easiest way to learn so...
  8.  
  9.  
  10.      Lets say we want to render this
  11.  
  12.      XXXX
  13.     X XX X
  14.     XXXXXX
  15.     X XX X
  16.      XXXX
  17.  
  18.     Now to decide the colors (We only have 4: White, Light Grey, Dark Grey, Black)
  19.     We also need to make sure we are using 1 tile of space, or 8x8
  20.  
  21.     00000000
  22.     00000000
  23.     00111100
  24.     01233210
  25.     01333310
  26.     01233210
  27.     00111100
  28.     00000000
  29.  
  30.     Now if you have synesthesia you can already see the image, most people however cannot. So good for you or whatever.
  31.     Now for the harder part, how in the world do we convert this data to 2bpp?
  32.     Well, as the name implies we only need 2 bits per pixel. 1 tile takes up 16 bytes, it takes 2 bits to make 4 colors.
  33.     Meaning, 2 bytes per row.
  34.  
  35.     Lets use a very simple example: 0xFF 0x00 <- These bois are our first row of pixelies.
  36.     Now easily convert to bin for all the juicy bits
  37.  
  38.     1111 1111
  39.     0000 0000
  40.     ^^^^ ^^^^
  41.     1234 5678
  42.     Pixel # ^
  43.  
  44.     Ok, so this is a row of 10, or dark grey (2) colored pixels, yes?
  45.     Woah, woah now, this is the gameboy days where indirect headaches were a thing, so don't forget to
  46.     interpret the data as little indian first.
  47.  
  48.     01 or light grey pixelies.
  49.  
  50. ]] --
  51.  
  52.  
  53. local gbColors =
  54. {
  55.     {
  56.      name = "gray",
  57.      [0] = colors.white,
  58.      [1] = colors.lightGray,
  59.      [2] = colors.gray,
  60.      [3] = colors.black,
  61.     },
  62.     {
  63.      name = "blue",
  64.      [0] = colors.white,
  65.      [1] = colors.lightBlue,
  66.      [2] = colors.blue,
  67.      [3] = colors.black,
  68.     },
  69.     {
  70.      name = "red",
  71.      [0] = colors.white,
  72.      [1] = colors.pink,
  73.      [2] = colors.red,
  74.      [3] = colors.black,
  75.     },
  76.     {
  77.       name = "fire",
  78.       [0] = colors.white,
  79.       [1] = colors.yellow,
  80.       [2] = colors.orange,
  81.       [3] = colors.red,
  82.     },
  83.     {
  84.      name = "green",
  85.      [0] = colors.white,
  86.      [1] = colors.lime,
  87.      [2] = colors.green,
  88.      [3] = colors.black,
  89.     },
  90.     {
  91.      name = "brown",
  92.      [0] = colors.white,
  93.      [1] = colors.orange,
  94.      [2] = colors.brown,
  95.      [3] = colors.black,
  96.     },
  97. }
  98.  
  99. function create_tile(bytes)
  100.     -- A string list of bytes seperated by spaces
  101.     local hexbytes = ""
  102.     -- Remove spaces
  103.     bytes = bytes:gsub("%s+","")
  104.  
  105.     if(#bytes%2 ~=  0)then error("create_tile (Converting to bytecode): Malformed bytes.")          end
  106.     if(#bytes/2 ~= 16)then error("create_tile (Converting to bytecode): Must be exactly 16 bytes!") end
  107.  
  108.     for i = 1, #bytes, 2 do
  109.         hexbytes = hexbytes .. string.char(tonumber(bytes:sub(i,i+1),16))
  110.     end
  111.  
  112.     return hexbytes
  113. end
  114.  
  115. function load_tile(file)
  116.     if(not fs.exists(file))then
  117.         error("load_tile: No such file.")
  118.     end
  119.  
  120.     local tile = {}
  121.  
  122.     local f = fs.open(file,"rb")
  123.     local byteInd = 0
  124.  
  125.     local bytes = ""
  126.     for byte in f.read do
  127.         bytes = bytes .. string.char(byte)
  128.         byteInd = byteInd + 1
  129.         if(byteInd == 16)then
  130.             table.insert(tile,bytes)
  131.             byteInd = 0
  132.             bytes = ""
  133.         end
  134.     end
  135.     f.close()
  136.     return tile
  137. end
  138.  
  139. function pixel_getcolor(one,two,ind)
  140.  
  141.     local checkbit = bit32.lshift(1,ind-1)
  142.     one = bit32.band(one, checkbit) ~= 0
  143.     two = bit32.band(two, checkbit) ~= 0
  144.     if one then one = 1 else one = 0 end
  145.     if two then two = 1 else two = 0 end
  146.  
  147.     return tonumber(two .. one, 2)
  148. end
  149.  
  150. function pixel_setcolor(one,two,ind,col)
  151.     local checkbit = bit32.lshift(1,ind-1)
  152.     if(col == 3)then
  153.         one = bit32.bor(one, checkbit)
  154.         two = bit32.bor(two, checkbit)
  155.     elseif(col == 2)then
  156.         one = bit32.band(one, bit32.bnot(checkbit))
  157.         two = bit32.bor(two, checkbit)
  158.     elseif(col == 1)then
  159.         one = bit32.bor(one, checkbit)
  160.         two = bit32.band(two, bit32.bnot(checkbit))
  161.     elseif(col == 0)then
  162.         one = bit32.band(one, bit32.bnot(checkbit))
  163.         two = bit32.band(two, bit32.bnot(checkbit))
  164.     end
  165.     return one,two
  166. end
  167.  
  168. function draw_tile(sx,sy,tile,scalex,scaley,pal)
  169.     if(pal == nil)then
  170.         pal = "Gray"
  171.     end
  172.     for i = 1, #gbColors do
  173.         if(pal == gbColors[i].name)then pal = i end
  174.     end
  175.     if(type(pal) == "string")then pal = 1 end
  176.      -- I really want this program to be able to draw ACTUAL 2bpp files so, im encoding these tiles
  177.      -- in a string of real bytes.
  178.      if(not scalex)then scalex = 1 end
  179.      if(not scaley)then scaley = 1 end
  180.      if( scalex < 0.5 or  scaley < 0.5 or
  181.        ( scalex < 1 and scalex ~= 0.5) or (scaley < 1 and scaley ~= 0.5)
  182.      )then
  183.             error("draw_tile: Unsupported image scalar, supported formats are as follows: \"0.5,1.0,2.0, ...\"")
  184.      end
  185.      bytes = {}
  186.  
  187.      local twobit = gbColors[pal]
  188.  
  189.      -- Uncompress tile so we can blit it all out quicker
  190.      for i = 1, 16 do
  191.         bytes[i-1] = string.byte(tile:sub(i,i))
  192.      end
  193.  
  194.      local px, py = sx, sy, skip, rowskip
  195.      if(scalex == 0 or scaley == 0)then return end
  196.  
  197.         for row = 0, #bytes, 2 do
  198.             if(scaley < 1)then
  199.                 if(row%(8*scaley) ~= 0)then rowskip = true end
  200.             end
  201.  
  202.             if(not rowskip)then
  203.                 for col = 8, 1, -1 do
  204.                     if(scalex < 1)then
  205.                         if(col%(4*scalex) ~= 0)then skip = true end
  206.                     end
  207.                     if(not skip)then
  208.                         local bit = pixel_getcolor(bytes[row], bytes[row + 1],col)
  209.                         term.setBackgroundColor(twobit[bit])
  210.                         term.setCursorPos(px,py)
  211.                         local bsize = scalex
  212.                         if(scalex < 1)then bsize = 1 end
  213.                         write(string.rep(" ",bsize))
  214.                         if(scaley > 1)then
  215.                             for i = 1, scaley-1 do
  216.                                 term.setCursorPos(px, py+i)
  217.                                 write(string.rep(" ",scalex))
  218.                             end
  219.                         end
  220.                         if(scalex >= 1)then
  221.                             px = px + scalex
  222.                         else
  223.                             px = px + 1
  224.                         end
  225.                     end
  226.                     skip = false
  227.                 end
  228.  
  229.                 px = sx
  230.                 if(scaley >= 1)then
  231.                     py = py + scaley
  232.                 else
  233.                     py = py + 1
  234.                 end
  235.  
  236.             end
  237.             rowskip = false
  238.         end
  239. end
  240.  
  241. function draw_tiles(sx,sy,tilearray,width,mx,my,pal)
  242.     if(not mx)then mx = 1 end
  243.     if(not my)then my = 1 end
  244.     local px, py = sx, sy
  245.     if(width == nil)then width = 3 end
  246.     local tile_line = 0
  247.     for i = 1, #tilearray do
  248.         draw_tile(px,py,tilearray[i],mx,my, pal)
  249.         px = px + (8*mx)
  250.         tile_line = tile_line + 1
  251.         if(tile_line == width)then
  252.             py = py + (8*my)
  253.             px = sx
  254.             tile_line = 0
  255.         end
  256.     end
  257. end
  258.  
  259. function little_draw_tiles(sx,sy,tilearray,width,mx,my,pal)
  260.     if(not fs.exists("blittle"))then
  261.         error ("little_draw_tiles: blittle is required to use this function. ")
  262.     end
  263.  
  264.     os.loadAPI("blittle")
  265.     local little_win = blittle.createWindow()
  266.     local normal_win = term.current()
  267.     term.redirect(little_win)
  268.     draw_tiles(sx,sy,tilearray,width,mx,my, pal)
  269.     term.redirect(normal_win)
  270. end
  271.  
  272.  
  273. function canvas_toBin(canv)
  274.  
  275.     local bytes = ""
  276.     local msb = 0
  277.     local lsb = 0
  278.     local bit = 1
  279.     write("\n")
  280.     for t = 1, #canv.surface do
  281.         local tile = canv.surface[t]
  282.         -- Loop through entire tile, and build colors into bytes.
  283.         for p = 1, 64 do
  284.             lsb, msb = pixel_setcolor(lsb, msb, 8-(bit-1), tonumber(tile:sub(p,p)))
  285.             --write(tile:sub(p,p) )
  286.             --sleep(0.2)
  287.             bit = bit + 1
  288.             if(bit > 8)then
  289.                 --write(": " .. toHex(lsb) .. " " .. toHex(msb) .. "\n")
  290.                 bytes = bytes .. string.char(lsb) .. string.char(msb)
  291.                 lsb = 0
  292.                 msb = 0
  293.                 bit = 1
  294.                 --os.pullEvent("key")
  295.             end
  296.         end
  297.     end
  298.  
  299.     return bytes
  300. end
  301.  
  302. function bin_toCanvas(file)
  303.     if(not fs.exists(file))then
  304.         error("bin_toCanvas: No such file.")
  305.     end
  306.  
  307.     local img = fs.open(file,"rb")
  308.     local tiles = {}
  309.     local msb = 0
  310.     local lsb = 0
  311.     local bytes = ""
  312.  
  313.     write("\n")
  314.     for byte in img.read do
  315.         bytes = bytes .. string.char(byte)
  316.         if(#bytes == 16)then
  317.             -- Convert tile bytes to 64 char string
  318.             local tile = ""
  319.             for b = 1, #bytes, 2 do
  320.                 lsb = string.byte(bytes:sub(b,  b  ))
  321.                 msb = string.byte(bytes:sub(b+1,b+1))
  322.                 for x = 8, 1, -1 do
  323.                     local c = pixel_getcolor(lsb,msb,x)
  324.                     tile = tile .. c
  325.                 end
  326.             end
  327.             table.insert(tiles,tile)
  328.             bytes = ""
  329.         end
  330.     end
  331.  
  332.     return tiles
  333. end
  334.  
  335.  
  336. function save_setBackgroundColor(bg)
  337.     local isvalid = false
  338.     for i = 0, 15 do
  339.         if(bg == 2^i)then isvalid = true end
  340.     end
  341.     if(bg == nil)then bg = "NULL" end
  342.     if(not isvalid)then error("Background color not valid: " .. bg) end
  343.     term.setBackgroundColor(bg)
  344. end
  345.  
  346. function paint_tiles(file)
  347.     local TILE = 8
  348.     local exit_flag = false
  349.     local _W, _H = term.getSize()
  350.     local inpaint = true
  351.     local col = 1
  352.     local workingfile = file
  353.     local pal = 1
  354.     local palnames = {}
  355.     for i = 1, #gbColors do
  356.         table.insert(palnames,gbColors[i].name)
  357.     end
  358.     _H = _H - 1 -- Account for options bar.
  359.  
  360.     canvas =
  361.     {
  362.         ratio = 4,
  363.         tiles = 16,
  364.         offsetx = 0,
  365.         offsety = 0,
  366.         invert  = 1,
  367.         rendergrid = true,
  368.         twobit = gbColors[pal],
  369.  
  370.         surface = {},
  371.         tile_coords = {},
  372.  
  373.         init = function(self)
  374.             -- surface[tile] = 64 chars.
  375.             -- Store white pixels, 8 width * 8 height.
  376.             for i = 1, self.tiles do
  377.                 self.surface[i] = string.rep("0",64)
  378.             end
  379.         end,
  380.  
  381.         draw = function(self,x,y,color)
  382.             x = x - self.offsetx*self.invert
  383.             y = y + self.offsety*self.invert
  384.             local tx = math.floor(x%TILE)
  385.             local ty = math.floor(y%TILE)
  386.             --local tyi = math.ceil( y/TILE )
  387.             --local txi = math.ceil( x/TILE )
  388.             local ti = 0
  389.             if(tx == 0)then tx = 8 end
  390.             if(ty == 0)then ty = 8 end
  391.             local sc = tx + (ty-1) * 8
  392.             for i = 1, self.tiles do
  393.                 if(x >= self.tile_coords[i].x and x < self.tile_coords[i].x+TILE and
  394.                    y >= self.tile_coords[i].y and y < self.tile_coords[i].y+TILE)then
  395.                     ti = i
  396.                 end
  397.             end
  398.             if(ti == 0)then return false end
  399.             --term.setCursorPos(1,15)
  400.             --term.setBackgroundColor(colors.lightBlue)
  401.             --term.setTextColor(colors.black)
  402.             --print("TC: " .. txi .. ", " .. tyi .. " ")
  403.             --print("TI: " .. ti .. "    \nSC: " .. sc .. "   ")
  404.             self.surface[ti] = self.surface[ti]:sub(1,sc-1) .. color .. self.surface[ti]:sub(sc+1,-1)
  405.             term.setCursorPos(x+self.offsetx*self.invert,y-self.offsety*self.invert)
  406.             term.setBackgroundColor(self.twobit[color])
  407.             term.setTextColor(colors.lightGray)
  408.             if(color == 0 and self.rendergrid)then
  409.                 write("\127")
  410.             else
  411.                 write(" ")
  412.             end
  413.         end,
  414.  
  415.         render_center = function(self,cap)
  416.             if(cap==nil)then self.ratio = math.floor(math.sqrt(self.tiles)) end
  417.             self.offsetx = math.floor(_W/2) - math.floor(((self.tiles*TILE)/self.ratio)/2)
  418.             self.offsety = -(math.ceil(_H/2) - math.floor((self.tiles/self.ratio)*TILE)/2)
  419.         end,
  420.  
  421.         load = function(self,surf)
  422.             self.surface = surf
  423.             self.tiles = #surf
  424.             self:render_center()
  425.         end,
  426.  
  427.         render_tile = function(self,tile,sx,sy)
  428.             local indx = sx
  429.             local indy = sy
  430.             local pix = 1
  431.             term.setCursorPos(sx, sy)
  432.             if(#tile ~= 64)then
  433.                 error("Tile is corrupt! (" .. #tile .. ") ")
  434.             end
  435.             for y = 1, 8 do
  436.                 for x = 1, 8 do
  437.                     term.setCursorPos(indx, indy)
  438.                     local c = self.twobit[tonumber(tile:sub(pix,pix))]
  439.                     term.setBackgroundColor(c)
  440.                     term.setTextColor(colors.lightGray)
  441.                     if(indx <= _W and indy <= _H and indx > 0 and indy > 0)then
  442.                         if(tonumber(tile:sub(pix,pix)) == 0 and self.rendergrid)then
  443.                             write("\127")
  444.                         else
  445.                             write(" ")
  446.                         end
  447.                     end
  448.                     indx = indx + 1
  449.                     pix = pix + 1
  450.                 end
  451.                 indy = indy + 1
  452.                 indx = sx
  453.             end
  454.         end,
  455.  
  456.         render = function(self)
  457.             local sx = 1
  458.             local sy = 1
  459.             for t = 1, self.tiles do
  460.                 self.tile_coords[t] = {x = sx, y = sy}
  461.                 if(self.tile_coords.my == nil)then self.tile_coords.my = sy end
  462.                 if(self.tile_coords.mx == nil)then self.tile_coords.mx = sx end
  463.                 if(self.tile_coords.my < sy)then self.tile_coords.my = sy end
  464.                 if(self.tile_coords.mx < sx)then self.tile_coords.mx = sx end
  465.                 self:render_tile(self.surface[t], sx+self.offsetx*self.invert, sy-self.offsety*self.invert)
  466.                 --term.setCursorPos(sx, sy)
  467.                 --term.setBackgroundColor(colors.black)
  468.                 --write(self.tile_coords[t].x .. ", " .. self.tile_coords[t].y)
  469.                 if( (t%self.ratio) == 0)then
  470.                     sy = sy + 8
  471.                     sx = 1
  472.                 else
  473.                     sx = sx + 8
  474.                 end
  475.             end
  476.         end,
  477.  
  478.         drawCharBox = function(sx,sy,ex,ey,tc,bc,ch)
  479.             for y = sy, ey do
  480.                 term.setCursorPos(sx, y)
  481.                 term.setBackgroundColor(colors.black)
  482.                 term.setTextColor(colors.gray)
  483.                 write(string.rep("\127",(ex-sx)+1))
  484.             end
  485.         end,
  486.  
  487.         move_render = function(self,xo,yo,bg,tc,cc)
  488.             local aox = self.offsetx + xo
  489.             local aoy = self.offsety + yo
  490.             --if(aox < 0)then aox = 0 end
  491.             --if(aoy < 0)then aoy = 0 end
  492.             --if(aox > self.tile_coords.mx)then aox = self.tile_coords.mx end
  493.             --if(aoy > self.tile_coords.my)then aoy = self.tile_coords.my end
  494.             local sx = 1+self.offsetx*self.invert
  495.             local sy = 1-self.offsety*self.invert
  496.             local ex = math.min((self.ratio*8)+(1+self.offsetx*self.invert),_W)
  497.             local ey = math.min((((self.tiles/self.ratio)*8)+(1-self.offsety*self.invert)),_H)
  498.             self.drawCharBox(sx,sy,ex,ey,tc,bg,cc)
  499.  
  500.             self.offsetx = aox
  501.             self.offsety = aoy
  502.  
  503.         end,
  504.  
  505.         resize = function(self,tiles)
  506.             tiles = tonumber(tiles)
  507.             if(tiles > self.tiles)then
  508.                 for i = 1, tiles do
  509.                     if(self.surface[i] == nil or self.surface[i] == "")then
  510.                         self.surface[i] = string.rep("0",64)
  511.                     end
  512.                 end
  513.             else
  514.                 for i = self.tiles, tiles+1, -1 do
  515.                     table.remove(self.surface, i)
  516.                 end
  517.             end
  518.             self.tiles = tiles
  519.             self:render_center()
  520.         end,
  521.  
  522.         setRatio = function(self,ratio)
  523.             ratio = tonumber(ratio)
  524.             if(ratio > self.tiles)then ratio = self.tiles end
  525.             self.ratio = ratio
  526.             self:render_center(1)
  527.             self:render()
  528.         end,
  529.     }
  530.  
  531.     local function textbar(c,txt)
  532.         term.setBackgroundColor(colors.gray)
  533.         term.setTextColor(c)
  534.         term.setCursorPos(1,19)
  535.         term.clearLine()
  536.         write(txt)
  537.     end
  538.  
  539.  
  540.     local function openSelectionMenu(items,x,y,tc,bc,w,sind)
  541.         if(sind == nil)then sind = 1 end
  542.         local selected = sind
  543.         local selecting = true
  544.  
  545.         local function drawitems(clr)
  546.             if(clr)then
  547.                 paintutils.drawFilledBox(x,y-1,x+w,y+#items,bc)
  548.             end
  549.             term.setBackgroundColor(bc)
  550.             for i = 1, #items do
  551.                 term.setCursorPos(x,y+i-1)
  552.                 term.setTextColor(gbColors[i][1])
  553.                 if(i == selected)then
  554.                     write("> " .. items[i] .. " <")
  555.                 else
  556.                     write("  " .. items[i] .. "  ")
  557.                 end
  558.             end
  559.         end
  560.  
  561.         drawitems(true)
  562.         while (selecting) do
  563.             local e = {os.pullEvent()}
  564.             if(e[1] == "key")then
  565.                 local key = e[2]
  566.                 if(key == keys.up)then selected = selected - 1 end
  567.                 if(key == keys.down)then selected = selected + 1 end
  568.                 if(selected > #items)then selected = 1 end
  569.                 if(selected <= 0)then selected = #items end
  570.                 drawitems(false)
  571.                 if(key == keys.enter)then selecting = false end
  572.             elseif(e[1] == "mouse_click")then
  573.                 local mx = e[3]
  574.                 local my = e[4]
  575.                 if(mx >= x and mx <= x+w and my > y-1 and my < y+#items)then
  576.                     selected = my-(y-1)
  577.                     drawitems(false)
  578.                     sleep(0.2)
  579.                     selecting = false
  580.                 else
  581.                     selected = 0
  582.                     selecting = false
  583.                 end
  584.             end
  585.         end
  586.  
  587.         return selected
  588.     end
  589.  
  590.     local contexts =
  591.     {
  592.         file = {
  593.             {c=colors.red,text=" Quit",button=1,func = function()
  594.                 exit_flag = true
  595.             end},
  596.             {c=colors.white,text=" Load",button=1,func = function()
  597.                 term.setBackgroundColor(colors.gray)
  598.                 term.setTextColor(colors.white)
  599.                 term.setCursorPos(1,19)
  600.                 term.clearLine()
  601.                 write("Load file: ")
  602.                 local nn = read()
  603.                 if(nn == nil or nn == "")then return end
  604.                 if(not fs.exists(nn))then
  605.                     textbar(colors.red,"File doesn't exist!")
  606.                     sleep(0.5)
  607.                     return
  608.                 end
  609.                 local nsurf = bin_toCanvas(nn)
  610.                 canvas:load(nsurf)
  611.                 textbar(colors.white,"Loaded " .. nn .. ". ")
  612.                 workingfile = nn
  613.                 canvas:render()
  614.                 sleep(0.5)
  615.                 return
  616.             end},
  617.             {c=colors.white,text=" Save As",button=1,func = function()
  618.                 local nn = ""
  619.                 term.setBackgroundColor(colors.gray)
  620.                 term.setTextColor(colors.white)
  621.                 term.setCursorPos(1,19)
  622.                 term.clearLine()
  623.                 write("Save as: ")
  624.                 nn = read()
  625.                 if(nn == nil or nn == "")then return end
  626.                 if(fs.exists(nn))then
  627.                     textbar(colors.red,"File already exists!")
  628.                     sleep(0.5)
  629.                     return
  630.                 else
  631.                     local sav = canvas_toBin(canvas)
  632.                     f = fs.open(workingfile,"w")
  633.                     f.write(sav)
  634.                     f.close()
  635.                     textbar(colors.white,"Saved to: " .. workingfile)
  636.                     sleep(0.5)
  637.                     return
  638.                 end
  639.             end},
  640.             {c=colors.white,text=" Save",button=1,func = function()
  641.                 local nn = ""
  642.                 if(workingfile == "" and workingfile ~= nil)then
  643.                     term.setBackgroundColor(colors.gray)
  644.                     term.setTextColor(colors.white)
  645.                     term.setCursorPos(1,19)
  646.                     term.clearLine()
  647.                     write("Save as: ")
  648.                     nn = read()
  649.                     if(nn == nil or nn == "")then return end
  650.                     if(fs.exists(nn))then
  651.                         textbar(colors.red,"File already exists!")
  652.                         sleep(0.5)
  653.                         return
  654.                     end
  655.                 else
  656.                     local sav = canvas_toBin(canvas)
  657.                     f = fs.open(workingfile,"w")
  658.                     f.write(sav)
  659.                     f.close()
  660.                     textbar(colors.white,"Saved to: " .. workingfile)
  661.                     sleep(0.5)
  662.                     return
  663.                 end
  664.                 if(workingfile == "" and workingfile ~= nil)then
  665.                     workingfile = nn
  666.                     local sav = canvas_toBin(canvas)
  667.                     f = fs.open(nn,"w")
  668.                     f.write(sav)
  669.                     f.close()
  670.                     textbar(colors.white,"Saved to: " .. workingfile)
  671.                     sleep(0.5)
  672.                     return
  673.                 end
  674.             end},
  675.             {c=colors.black,text="",button=0},
  676.         },
  677.         image = {
  678.             {c=colors.white,button=1,text=" Toggle [G]rid",func = function()
  679.                 canvas.rendergrid = not canvas.rendergrid
  680.                 canvas:render()
  681.             end},
  682.             {c=colors.blue,text=" Palette",button=1,func = function()
  683.                 local npal = openSelectionMenu(palnames,7,_H-#palnames,colors.white,colors.gray,8,pal)
  684.                 if(npal ~= 0)then
  685.                     pal = npal
  686.                     canvas.twobit = gbColors[pal]
  687.                 end
  688.             end},
  689.             {c=colors.white,text=" Set Ratio",button=1,func = function()
  690.                     term.setBackgroundColor(colors.gray)
  691.                     term.setTextColor(colors.white)
  692.                     term.setCursorPos(1,19)
  693.                     term.clearLine()
  694.                     write("Tile Aspect Ratio: ")
  695.                     local yy = read()
  696.                     if(yy == "" or yy == nil)then return end
  697.                     term.setBackgroundColor(colors.black)
  698.                     canvas:setRatio(yy)
  699.                     canvas:render()
  700.             end},
  701.             {c=colors.white,text=" Resize",button=1,func = function()
  702.                     term.setBackgroundColor(colors.gray)
  703.                     term.setTextColor(colors.white)
  704.                     term.setCursorPos(1,19)
  705.                     term.clearLine()
  706.                     write("Tiles: ")
  707.                     local xx = read()
  708.                     if(xx == "" or xx == nil)then return end
  709.                     term.setBackgroundColor(colors.black)
  710.                     canvas:resize(xx)
  711.                     canvas:render()
  712.             end},
  713.             {c=colors.black,text="",button=0},
  714.         },
  715.     }
  716.  
  717.     local options =
  718.     {
  719.        {x=1,c=colors.gray,w=8  ,text="File"  ,menu = contexts.file },
  720.        {x=7,c=colors.gray,w=14 ,text="Image" ,menu = contexts.image},
  721.     }
  722.  
  723.     local inmenu = 0
  724.  
  725.     local function drawGUI()
  726.         term.setBackgroundColor(colors.black)
  727.         term.clear()
  728.         term.setCursorPos(1, 1)
  729.         term.setTextColor(colors.gray)
  730.         for i = 1, _H do
  731.             print(string.rep("\127",_W))
  732.         end
  733.         term.setBackgroundColor(colors.gray)
  734.         term.setCursorPos(5,19)
  735.         term.clearLine()
  736.         term.setTextColor(colors.white)
  737.         for i = 1, #options do
  738.             term.setCursorPos(options[i].x,19)
  739.             write(options[i].text)
  740.         end
  741.         canvas:render()
  742.     end
  743.  
  744.     local function drawMenuOpt(opt)
  745.         local sx = options[opt].x
  746.         local sy = _H-#options[opt].menu
  747.         paintutils.drawFilledBox(sx,sy,sx+options[opt].w,sy+#options[opt].menu,options[opt].c)
  748.         for i = 1, #options[opt].menu do
  749.             term.setBackgroundColor(options[inmenu].c)
  750.             term.setTextColor(options[inmenu].menu[i].c)
  751.             term.setCursorPos(options[inmenu].x,18-i)
  752.             write(options[inmenu].menu[i].text)
  753.         end
  754.     end
  755.  
  756.     local function optionBlink(i,t)
  757.         term.setBackgroundColor(colors.white)
  758.         term.setTextColor(colors.gray)
  759.         term.setCursorPos(options[i].x,19)
  760.         write(options[i].text)
  761.         sleep(t)
  762.         term.setBackgroundColor(colors.gray)
  763.         term.setTextColor(colors.white)
  764.         --term.setCursorPos(options[i].x,19)
  765.         --write(options[i].text)
  766.     end
  767.  
  768.     local function menu_optionBlink(i,t)
  769.         term.setBackgroundColor(options[inmenu].menu[i].c)
  770.         term.setTextColor(options[inmenu].c)
  771.         term.setCursorPos(options[inmenu].x,_H-i)
  772.         write(options[inmenu].menu[i].text .. string.rep(" ",options[inmenu].w-#options[inmenu].menu[i].text))
  773.         sleep(t)
  774.         term.setBackgroundColor(options[inmenu].c)
  775.         term.setTextColor(options[inmenu].menu[i].c)
  776.         term.setCursorPos(options[inmenu].x,_H-i)
  777.         write(options[inmenu].menu[i].text .. string.rep(" ",options[inmenu].w-#options[inmenu].menu[i].text))
  778.     end
  779.  
  780.  
  781.     local function updateGUI()
  782.         term.setTextColor(canvas.twobit[3-col])
  783.         term.setCursorPos(45,19)
  784.         term.setBackgroundColor(canvas.twobit[col])
  785.         write(" Color ")
  786.         term.setBackgroundColor(colors.gray)
  787.         term.setCursorPos(33,19)
  788.         term.setTextColor(colors.black)
  789.         write("X:" .. canvas.offsetx .. " ")
  790.         term.setCursorPos(39,19)
  791.         write("Y:" .. canvas.offsety .. " ")
  792.     end
  793.  
  794.     canvas:init()
  795.  
  796.     if(workingfile ~= "" and workingfile ~= nil)then
  797.         if(fs.exists(workingfile))then
  798.             local nsurf = bin_toCanvas(workingfile)
  799.             canvas:load(nsurf)
  800.         end
  801.     end
  802.  
  803.     drawGUI()
  804.     updateGUI()
  805.  
  806.     while inpaint do
  807.  
  808.         if(exit_flag)then
  809.             inpaint = false
  810.             term.setBackgroundColor(colors.black)
  811.             term.setTextColor(colors.white)
  812.             term.clear()
  813.             paintutils.drawFilledBox(1,1,_W,7,colors.blue)
  814.             term.setCursorPos(15,2)
  815.             print("Thank you for using 2BCC!")
  816.             term.setCursorPos(3,4)
  817.             print("If you find any bugs when using 2BCC please be")
  818.             term.setCursorPos(3,5)
  819.             print("sure to post about them on the forums.")
  820.             term.setCursorPos(_W-5,6)
  821.             print("\1672018")
  822.             term.setCursorPos(1, 9)
  823.             return
  824.         end
  825.  
  826.         local e = {os.pullEvent()}
  827.         if(e[1] == "mouse_click" or e[1] == "mouse_drag")then
  828.             local x = e[3]
  829.             local y = e[4]
  830.             if(y ~= _H+1 and inmenu == 0)then
  831.                 canvas:draw(x,y,col)
  832.             end
  833.  
  834.             if(y == _H+1 and inmenu == 0)then
  835.                 for i = 1, #options do
  836.                     if(x >= options[i].x and x < options[i].x+#options[i].text)then
  837.                         optionBlink(i,0.2)
  838.                         inmenu = i
  839.                         drawMenuOpt(i)
  840.                         --drawGUI()
  841.                         --updateGUI()
  842.                     end
  843.                 end
  844.             elseif(inmenu ~= 0)then
  845.                 for i = 1, #options[inmenu].menu do
  846.                     if(x >= options[inmenu].x and x < options[inmenu].x+options[inmenu].w and y == _H-i)then
  847.                         if(options[inmenu].menu[i].button == 1)then
  848.                             menu_optionBlink(i,0.2)
  849.                             drawGUI()
  850.                             updateGUI()
  851.                             options[inmenu].menu[i].func()
  852.                             inmenu = 0
  853.                             drawGUI()
  854.                             updateGUI()
  855.                             break
  856.                         end
  857.                     end
  858.                 end
  859.                 if(inmenu ~= 0)then
  860.                     if(not (
  861.                         x >= options[inmenu].x and x <= options[inmenu].x+options[inmenu].w and
  862.                         y >= _H-#options[inmenu].menu and y <= _H
  863.                         ) )then
  864.                         inmenu = 0
  865.                         drawGUI()
  866.                         updateGUI()
  867.                     end
  868.                 end
  869.             end
  870.  
  871.         elseif(e[1] == "mouse_scroll")then
  872.             local sdir = e[2]
  873.             if(sdir == 1)then
  874.                 col = col + 1
  875.                 if(col > 3)then col = 3 end
  876.                 sleep(0.01)
  877.                 updateGUI()
  878.             end
  879.             if(sdir == -1)then
  880.                 col = col - 1
  881.                 if(col < 0)then col = 0 end
  882.                 sleep(0.01)
  883.                 updateGUI()
  884.             end
  885.         elseif(e[1] == "key")then
  886.             local k = e[2]
  887.  
  888.             if(k == keys.one   )then col = 0 updateGUI() end
  889.             if(k == keys.two   )then col = 1 updateGUI() end
  890.             if(k == keys.three )then col = 2 updateGUI() end
  891.             if(k == keys.four  )then col = 3 updateGUI() end
  892.             if(k == keys.g)then
  893.                 canvas.rendergrid = not canvas.rendergrid
  894.                 canvas:render()
  895.             end
  896.             local vis = term.current().setVisible
  897.             if(vis == nil)then vis = function(tf) return false end end
  898.             if(k == keys.up)then
  899.                 vis(false)
  900.                 canvas:move_render(0,-1,colors.black,colors.gray,"\127")
  901.                 canvas:render()
  902.                 updateGUI()
  903.                 vis(true)
  904.             end
  905.             if(k == keys.down)then
  906.                 vis(false)
  907.                 canvas:move_render(0,1,colors.black,colors.gray,"\127")
  908.                 canvas:render()
  909.                 updateGUI()
  910.                 vis(true)
  911.             end
  912.             if(k == keys.left)then
  913.                 vis(false)
  914.                 canvas:move_render(-1,0,colors.black,colors.gray,"\127")
  915.                 canvas:render()
  916.                 updateGUI()
  917.                 vis(true)
  918.             end
  919.             if(k == keys.right)then
  920.                 vis(false)
  921.                 canvas:move_render(1,0,colors.black,colors.gray,"\127")
  922.                 canvas:render()
  923.                 updateGUI()
  924.                 vis(true)
  925.             end
  926.         end
  927.     end
  928. end
  929.  
  930. --draw_tile(8,5,create_tile("FF 00 7E FF 85 81 89 83 93 85 A5 8B C9 97 7E FF"))
  931.  
  932. -- Here's an example 2bpp from pokemon red; The back sprite of bellsprout.
  933. local bellsprout = {
  934.     create_tile("00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"),
  935.     create_tile("00 00 00 00 00 00 03 07 08 08 10 10 00 20 20 70"),
  936.     create_tile("00 00 00 00 00 00 c0 e0 70 10 38 08 1c 04 18 04"),
  937.     create_tile("00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"),
  938.     create_tile("00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"),
  939.     create_tile("90 88 58 e8 f0 88 20 70 20 c0 80 a0 b0 a0 08 90"),
  940.     create_tile("0c 02 06 02 06 02 16 0e 0a 1e 10 0a 00 04 0c 04"),
  941.     create_tile("00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"),
  942.     create_tile("00 00 00 00 1c 3e 4b 61 87 e0 ed f3 0a 0c 15 18"),
  943.     create_tile("50 58 28 28 14 10 07 0c 8b 8a 8d c5 20 24 14 12"),
  944.     create_tile("0c 04 1c 04 34 0c e8 1c ca 32 bf 61 bf ef 6e 72"),
  945.     create_tile("00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"),
  946.     create_tile("2e 30 55 68 8e f0 87 ff 00 00 00 00 00 00 00 00"),
  947.     create_tile("2a 0a 16 0e 2a 06 19 87 00 00 00 00 00 00 00 00"),
  948.     create_tile("08 1c 00 00 00 00 00 00 00 00 00 00 00 00 00 00"),
  949.     create_tile("00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"),
  950. }
  951.  
  952. local targs = { ... }
  953. if(#targs < 1)then
  954.     term.setTextColor(colors.red)
  955.     print("Usage: " .. shell.getRunningProgram() .. " <function> <args>")
  956.     term.setTextColor(colors.white)
  957.     print(shell.getRunningProgram() .. " functions:\n")
  958.     print("[edit <file>] Opens/Creates a 2BPP file for editing.\n")
  959.     print("[render <file> <ratio> (xscale) (yscale) (palette)] Renders a 2BPP file at the specified tile-ratio.\n")
  960.     print("[renderlittle <file> <ratio> (xscale) (yscale) (palette)] Renders a 2BPP file using blittle.\n")
  961.     print("[demo] Renders a demo 2BPP sprite")
  962.     print("[littledemo] Uses blittle to render a demo 2BPP sprite")
  963. else
  964.     -- I've made so many lists at this point that i'm just going to if/elif this :P
  965.     if(targs[1]:lower() == "edit")then
  966.         if(#targs < 2)then
  967.             error("[2BPP] Usage: edit <file>")
  968.         end
  969.         paint_tiles(targs[2])
  970.     elseif(targs[1]:lower() == "render")then
  971.         if(#targs < 3)then
  972.             error("[2BPP] Usage: render <file> <ratio> (scalex) (scaley) (palette)")
  973.         end
  974.         local scx, scy = tonumber(targs[4]), tonumber(targs[5])
  975.         if(scx == nil)then scx = 2 end
  976.         if(scy == nil)then scy = 2 end
  977.         term.setBackgroundColor(colors.black)
  978.         term.setTextColor(colors.white)
  979.         term.clear()
  980.         draw_tiles(2,1,load_tile(targs[2]),tonumber(targs[3]),scx,scy,targs[6])
  981.         term.setCursorPos(1,1)
  982.     elseif(targs[1]:lower() == "renderlittle")then
  983.         if(#targs < 3)then
  984.             error("[2BPP] Usage: renderlittle <file> <ratio> (scalex) (scaley) (palette)")
  985.         end
  986.         local scx, scy = tonumber(targs[4]), tonumber(targs[5])
  987.         if(scx == nil)then scx = 2 end
  988.         if(scy == nil)then scy = 2 end
  989.         term.setBackgroundColor(colors.black)
  990.         term.setTextColor(colors.white)
  991.         term.clear()
  992.         little_draw_tiles(3,2,load_tile(targs[2]),tonumber(targs[3]),scx,scy,targs[6])
  993.         term.setCursorPos(1,1)
  994.     elseif(targs[1]:lower() == "demo")then
  995.         term.setBackgroundColor(colors.black)
  996.         term.setTextColor(colors.white)
  997.         term.clear()
  998.         draw_tiles(1,-5,bellsprout,4,2,1)
  999.     elseif(targs[1]:lower() == "littledemo")then
  1000.         term.setBackgroundColor(colors.black)
  1001.         term.setTextColor(colors.white)
  1002.         term.clear()
  1003.         little_draw_tiles(5,1,bellsprout,4,2,2)
  1004.         term.setCursorPos(1,1)
  1005.     end
  1006. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement