ElementalAura

surface.lua

Apr 17th, 2025 (edited)
33
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 42.92 KB | None | 0 0
  1. local surface = { } do
  2.  
  3. local surf = { }
  4. surface.surf = surf
  5.  
  6. local table_concat, math_floor, math_atan2 = table.concat, math.floor, math.atan2
  7.  
  8. local _cc_color_to_hex, _cc_hex_to_color = { }, { }
  9. for i = 0, 15 do
  10.     _cc_color_to_hex[2 ^ i] = string.format("%01x", i)
  11.     _cc_hex_to_color[string.format("%01x", i)] = 2 ^ i
  12. end
  13.  
  14. local _chars = { }
  15. for i = 0, 255 do
  16.     _chars[i] = string.char(i)
  17. end
  18. local _numstr = { }
  19. for i = 0, 1023 do
  20.     _numstr[i] = tostring(i)
  21. end
  22.  
  23. local _eprc, _esin, _ecos = 20, { }, { }
  24. for i = 0, _eprc - 1 do
  25.     _esin[i + 1] = (1 - math.sin(i / _eprc * math.pi * 2)) / 2
  26.     _ecos[i + 1] = (1 + math.cos(i / _eprc * math.pi * 2)) / 2
  27. end
  28.  
  29. local _steps, _palette, _rgbpal, _palr, _palg, _palb = 16
  30.  
  31. local function calcStack(stack, width, height)
  32.     local ox, oy, cx, cy, cwidth, cheight = 0, 0, 0, 0, width, height
  33.     for i = 1, #stack do
  34.         ox = ox + stack[i].ox
  35.         oy = oy + stack[i].oy
  36.         cx = cx + stack[i].x
  37.         cy = cy + stack[i].y
  38.         cwidth = stack[i].width
  39.         cheight = stack[i].height
  40.     end
  41.     return ox, oy, cx, cy, cwidth, cheight
  42. end
  43.  
  44. local function clipRect(x, y, width, height, cx, cy, cwidth, cheight)
  45.     if x < cx then
  46.         width = width + x - cx
  47.         x = cx
  48.     end
  49.     if y < cy then
  50.         height = height + y - cy
  51.         y = cy
  52.     end
  53.     if x + width > cx + cwidth then
  54.         width = cwidth + cx - x
  55.     end
  56.     if y + height > cy + cheight then
  57.         height = cheight + cy - y
  58.     end
  59.     return x, y, width, height
  60. end
  61.  
  62.  
  63.  
  64. function surface.create(width, height, b, t, c)
  65.     local surface = setmetatable({ }, {__index = surface.surf})
  66.     surface.width = width
  67.     surface.height = height
  68.     surface.buffer = { }
  69.     surface.overwrite = false
  70.     surface.stack = { }
  71.     surface.ox, surface.oy, surface.cx, surface.cy, surface.cwidth, surface.cheight = calcStack(surface.stack, width, height)
  72.     -- force array indeces instead of hashed indices
  73.  
  74.     local buffer = surface.buffer
  75.     for i = 1, width * height * 3, 3 do
  76.         buffer[i] = b or false
  77.         buffer[i + 1] = t or false
  78.         buffer[i + 2] = c or false
  79.     end
  80.     buffer[width * height * 3 + 1] = false
  81.     if not b then
  82.         for i = 1, width * height * 3, 3 do
  83.             buffer[i] = b
  84.         end
  85.     end
  86.     if not t then
  87.         for i = 2, width * height * 3, 3 do
  88.             buffer[i] = t
  89.         end
  90.     end
  91.     if not c then
  92.         for i = 3, width * height * 3, 3 do
  93.             buffer[i] = c
  94.         end
  95.     end
  96.  
  97.     return surface
  98. end
  99.  
  100. function surface.getPlatformOutput(output)
  101.     output = output or (term or gpu or (love and love.graphics) or io)
  102.  
  103.     if output.blit and output.setCursorPos then
  104.         return "cc", output, output.getSize()
  105.     elseif output.write and output.setCursorPos and output.setTextColor and output.setBackgroundColor then
  106.         return "cc-old", output, output.getSize()
  107.     elseif output.blitPixels then
  108.         return "riko-4", output, 320, 200
  109.     elseif output.points and output.setColor then
  110.         return "love2d", output, output.getWidth(), output.getHeight()
  111.     elseif output.drawPixel then
  112.         return "redirection", output, 64, 64
  113.     elseif output.setForeground and output.setBackground and output.set then
  114.         return "oc", output, output.getResolution()
  115.     elseif output.write then
  116.         return "ansi", output, (os.getenv and (os.getenv("COLUMNS"))) or 80, (os.getenv and (os.getenv("LINES"))) or 43
  117.     else
  118.         error("unsupported platform/output object")
  119.     end
  120. end
  121.  
  122. function surf:output(output, x, y, sx, sy, swidth, sheight)
  123.     local platform, output, owidth, oheight = surface.getPlatformOutput(output)
  124.  
  125.     x = x or 0
  126.     y = y or 0
  127.     sx = sx or 0
  128.     sy = sy or 0
  129.     swidth = swidth or self.width
  130.     sheight = sheight or self.height
  131.     sx, sy, swidth, sheight = clipRect(sx, sy, swidth, sheight, 0, 0, self.width, self.height)
  132.  
  133.     local buffer = self.buffer
  134.     local bwidth = self.width
  135.     local xoffset, yoffset, idx
  136.  
  137.     if platform == "cc" then
  138.         -- CC
  139.         local str, text, back = { }, { }, { }
  140.         for j = 0, sheight - 1 do
  141.             yoffset = (j + sy) * bwidth + sx
  142.             for i = 0, swidth - 1 do
  143.                 xoffset = (yoffset + i) * 3
  144.                 idx = i + 1
  145.                 str[idx] = buffer[xoffset + 3] or " "
  146.                 text[idx] = _cc_color_to_hex[buffer[xoffset + 2] or 1]
  147.                 back[idx] = _cc_color_to_hex[buffer[xoffset + 1] or 32768]
  148.             end
  149.             output.setCursorPos(x + 1, y + j + 1)
  150.             output.blit(table_concat(str), table_concat(text), table_concat(back))
  151.         end
  152.  
  153.     elseif platform == "cc-old" then
  154.         -- CC pre-1.76
  155.         local str, b, t, pb, pt = { }
  156.         for j = 0, sheight - 1 do
  157.             output.setCursorPos(x + 1, y + j + 1)
  158.             yoffset = (j + sy) * bwidth + sx
  159.             for i = 0, swidth - 1 do
  160.                 xoffset = (yoffset + i) * 3
  161.                 pb = buffer[xoffset + 1] or 32768
  162.                 pt = buffer[xoffset + 2] or 1
  163.                 if pb ~= b then
  164.                     if #str ~= 0 then
  165.                         output.write(table_concat(str))
  166.                         str = { }
  167.                     end
  168.                     b = pb
  169.                     output.setBackgroundColor(b)
  170.                 end
  171.                 if pt ~= t then
  172.                     if #str ~= 0 then
  173.                         output.write(table_concat(str))
  174.                         str = { }
  175.                     end
  176.                     t = pt
  177.                     output.setTextColor(t)
  178.                 end
  179.                 str[#str + 1] = buffer[xoffset + 3] or " "
  180.             end
  181.             output.write(table_concat(str))
  182.             str = { }
  183.         end
  184.  
  185.     elseif platform == "riko-4" then
  186.         -- Riko 4
  187.         local pixels = { }
  188.         for j = 0, sheight - 1 do
  189.             yoffset = (j + sy) * bwidth + sx
  190.             for i = 0, swidth - 1 do
  191.                 pixels[j * swidth + i + 1] = buffer[(yoffset + i) * 3 + 1] or 0
  192.             end
  193.         end
  194.         output.blitPixels(x, y, swidth, sheight, pixels)
  195.  
  196.     elseif platform == "love2d" then
  197.         -- Love2D
  198.         local pos, r, g, b, pr, pg, pb = { }
  199.         for j = 0, sheight - 1 do
  200.             yoffset = (j + sy) * bwidth + sx
  201.             for i = 0, swidth - 1 do
  202.                 xoffset = (yoffset + i) * 3
  203.                 pr = buffer[xoffset + 1]
  204.                 pg = buffer[xoffset + 2]
  205.                 pb = buffer[xoffset + 3]
  206.                 if pr ~= r or pg ~= g or pb ~= b then
  207.                     if #pos ~= 0 then
  208.                         output.setColor((r or 0) * 255, (g or 0) * 255, (b or 0) * 255, (r or g or b) and 255 or 0)
  209.                         output.points(pos)
  210.                     end
  211.                     r, g, b = pr, pg, pb
  212.                     pos = { }
  213.                 end
  214.                 pos[#pos + 1] = i + x + 1
  215.                 pos[#pos + 1] = j + y + 1
  216.             end
  217.         end
  218.         output.setColor((r or 0) * 255, (g or 0) * 255, (b or 0) * 255, (r or g or b) and 255 or 0)
  219.         output.points(pos)
  220.  
  221.     elseif platform == "redirection" then
  222.         -- Redirection arcade (gpu)
  223.         -- todo: add image:write support for extra performance
  224.         local px = output.drawPixel
  225.         for j = 0, sheight - 1 do
  226.             for i = 0, swidth - 1 do
  227.                 px(x + i, y + j, buffer[((j + sy) * bwidth + (i + sx)) * 3 + 1] or 0)
  228.             end
  229.         end
  230.  
  231.     elseif platform == "oc" then
  232.         -- OpenComputers
  233.         local str, lx, b, t, pb, pt = { }
  234.         for j = 0, sheight - 1 do
  235.             lx = x
  236.             yoffset = (j + sy) * bwidth + sx
  237.             for i = 0, swidth - 1 do
  238.                 xoffset = (yoffset + i) * 3
  239.                 pb = buffer[xoffset + 1] or 0x000000
  240.                 pt = buffer[xoffset + 2] or 0xFFFFFF
  241.                 if pb ~= b then
  242.                     if #str ~= 0 then
  243.                         output.set(lx + 1, j + y + 1, table_concat(str))
  244.                         lx = i + x
  245.                         str = { }
  246.                     end
  247.                     b = pb
  248.                     output.setBackground(b)
  249.                 end
  250.                 if pt ~= t then
  251.                     if #str ~= 0 then
  252.                         output.set(lx + 1, j + y + 1, table_concat(str))
  253.                         lx = i + x
  254.                         str = { }
  255.                     end
  256.                     t = pt
  257.                     output.setForeground(t)
  258.                 end
  259.                 str[#str + 1] = buffer[xoffset + 3] or " "
  260.             end
  261.             output.set(lx + 1, j + y + 1, table_concat(str))
  262.             str = { }
  263.         end
  264.  
  265.     elseif platform == "ansi" then
  266.         -- ANSI terminal
  267.         local str, b, t, pb, pt = { }
  268.         for j = 0, sheight - 1 do
  269.             str[#str + 1] = "\x1b[".._numstr[y + j + 1]..";".._numstr[x + 1].."H"
  270.             yoffset = (j + sy) * bwidth + sx
  271.             for i = 0, swidth - 1 do
  272.                 xoffset = (yoffset + i) * 3
  273.                 pb = buffer[xoffset + 1] or 0
  274.                 pt = buffer[xoffset + 2] or 7
  275.                 if pb ~= b then
  276.                     b = pb
  277.                     if b < 8 then
  278.                         str[#str + 1] = "\x1b[".._numstr[40 + b].."m"
  279.                     elseif b < 16 then
  280.                         str[#str + 1] = "\x1b[".._numstr[92 + b].."m"
  281.                     elseif b < 232 then
  282.                         str[#str + 1] = "\x1b[48;2;".._numstr[math_floor((b - 16) / 36 * 85 / 2)]..";".._numstr[math_floor((b - 16) / 6 % 6 * 85 / 2)]..";".._numstr[math_floor((b - 16) % 6 * 85 / 2)].."m"
  283.                     else
  284.                         local gr = _numstr[b * 10 - 2312]
  285.                         str[#str + 1] = "\x1b[48;2;"..gr..";"..gr..";"..gr.."m"
  286.                     end
  287.                 end
  288.                 if pt ~= t then
  289.                     t = pt
  290.                     if t < 8 then
  291.                         str[#str + 1] = "\x1b[".._numstr[30 + t].."m"
  292.                     elseif t < 16 then
  293.                         str[#str + 1] = "\x1b[".._numstr[82 + t].."m"
  294.                     elseif t < 232 then
  295.                         str[#str + 1] = "\x1b[38;2;".._numstr[math_floor((t - 16) / 36 * 85 / 2)]..";".._numstr[math_floor((t - 16) / 6 % 6 * 85 / 2)]..";".._numstr[math_floor((t - 16) % 6 * 85 / 2)].."m"
  296.                     else
  297.                         local gr = _numstr[t * 10 - 2312]
  298.                         str[#str + 1] = "\x1b[38;2;"..gr..";"..gr..";"..gr.."m"
  299.                     end
  300.                 end
  301.                 str[#str + 1] = buffer[xoffset + 3] or " "
  302.             end
  303.         end
  304.         output.write(table_concat(str))
  305.     end
  306. end
  307.  
  308. function surf:push(x, y, width, height, nooffset)
  309.     x, y = x + self.ox, y + self.oy
  310.  
  311.     local ox, oy = nooffset and self.ox or x, nooffset and self.oy or y
  312.     x, y, width, height = clipRect(x, y, width, height, self.cx, self.cy, self.cwidth, self.cheight)
  313.     self.stack[#self.stack + 1] = {ox = ox - self.ox, oy = oy - self.oy, x = x - self.cx, y = y - self.cy, width = width, height = height}
  314.  
  315.     self.ox, self.oy, self.cx, self.cy, self.cwidth, self.cheight = calcStack(self.stack, self.width, self.height)
  316. end
  317.  
  318. function surf:pop()
  319.     if #self.stack == 0 then
  320.         error("no stencil to pop")
  321.     end
  322.     self.stack[#self.stack] = nil
  323.     self.ox, self.oy, self.cx, self.cy, self.cwidth, self.cheight = calcStack(self.stack, self.width, self.height)
  324. end
  325.  
  326. function surf:copy()
  327.     local surface = setmetatable({ }, {__index = surface.surf})
  328.  
  329.     for k, v in pairs(self) do
  330.         surface[k] = v
  331.     end
  332.  
  333.     surface.buffer = { }
  334.     for i = 1, self.width * self.height * 3 + 1 do
  335.         surface.buffer[i] = false
  336.     end
  337.     for i = 1, self.width * self.height * 3 do
  338.         surface.buffer[i] = self.buffer[i]
  339.     end
  340.  
  341.     surface.stack = { }
  342.     for i = 1, #self.stack do
  343.         surface.stack[i] = self.stack[i]
  344.     end
  345.  
  346.     return surface
  347. end
  348.  
  349. function surf:clear(b, t, c)
  350.     local xoffset, yoffset
  351.  
  352.     for j = 0, self.cheight - 1 do
  353.         yoffset = (j + self.cy) * self.width + self.cx
  354.         for i = 0, self.cwidth - 1 do
  355.             xoffset = (yoffset + i) * 3
  356.             self.buffer[xoffset + 1] = b
  357.             self.buffer[xoffset + 2] = t
  358.             self.buffer[xoffset + 3] = c
  359.         end
  360.     end
  361. end
  362.  
  363. function surf:drawPixel(x, y, b, t, c)
  364.     x, y = x + self.ox, y + self.oy
  365.  
  366.     local idx
  367.     if x >= self.cx and x < self.cx + self.cwidth and y >= self.cy and y < self.cy + self.cheight then
  368.         idx = (y * self.width + x) * 3
  369.         if b or self.overwrite then
  370.             self.buffer[idx + 1] = b
  371.         end
  372.         if t or self.overwrite then
  373.             self.buffer[idx + 2] = t
  374.         end
  375.         if c or self.overwrite then
  376.             self.buffer[idx + 3] = c
  377.         end
  378.     end
  379. end
  380.  
  381. function surf:drawString(str, x, y, b, t)
  382.     x, y = x + self.ox, y + self.oy
  383.  
  384.     local sx = x
  385.     local insidey = y >= self.cy and y < self.cy + self.cheight
  386.     local idx
  387.     local lowerxlim = self.cx
  388.     local upperxlim = self.cx + self.cwidth
  389.     local writeb = b or self.overwrite
  390.     local writet = t or self.overwrite
  391.  
  392.     for i = 1, #str do
  393.         local c = str:sub(i, i)
  394.         if c == "\n" then
  395.             x = sx
  396.             y = y + 1
  397.             if insidey then
  398.                 if y >= self.cy + self.cheight then
  399.                     return
  400.                 end
  401.             else
  402.                 insidey = y >= self.cy
  403.             end
  404.         else
  405.             idx = (y * self.width + x) * 3
  406.             if x >= lowerxlim and x < upperxlim and insidey then
  407.                 if writeb then
  408.                     self.buffer[idx + 1] = b
  409.                 end
  410.                 if writet then
  411.                     self.buffer[idx + 2] = t
  412.                 end
  413.                 self.buffer[idx + 3] = c
  414.             end
  415.             x = x + 1
  416.         end
  417.     end
  418. end
  419.  
  420. -- You can remove any of these components
  421. function surface.load(strpath, isstr)
  422.     local data = strpath
  423.     if not isstr then
  424.         local handle = io.open(strpath, "rb")
  425.         if not handle then return end
  426.         local chars = { }
  427.         local byte = handle:read(1)
  428.         if type(byte) == "number" then -- cc doesn't conform to standards
  429.             while byte do
  430.                 chars[#chars + 1] = _chars[byte]
  431.                 byte = handle:read(1)
  432.             end
  433.         else
  434.             while byte do
  435.                 chars[#chars + 1] = byte
  436.                 byte = handle:read(1)
  437.             end
  438.         end
  439.         handle:close()
  440.         data = table_concat(chars)
  441.     end
  442.    
  443.     if data:sub(1, 3) == "RIF" then
  444.         -- Riko 4 image format
  445.         local width, height = data:byte(4) * 256 + data:byte(5), data:byte(6) * 256 + data:byte(7)
  446.         local surf = surface.create(width, height)
  447.         local buffer = surf.buffer
  448.         local upper, byte = 8, false
  449.         local byte = data:byte(index)
  450.  
  451.         for j = 0, height - 1 do
  452.             for i = 0, height - 1 do
  453.                 if not upper then
  454.                     buffer[(j * width + i) * 3 + 1] = math_floor(byte / 16)
  455.                 else
  456.                     buffer[(j * width + i) * 3 + 1] = byte % 16
  457.                     index = index + 1
  458.                     data = data:byte(index)
  459.                 end
  460.                 upper = not upper
  461.             end
  462.         end
  463.         return surf
  464.  
  465.     elseif data:sub(1, 2) == "BM" then
  466.         -- BMP format
  467.         local width = data:byte(0x13) + data:byte(0x14) * 256
  468.         local height = data:byte(0x17) + data:byte(0x18) * 256
  469.         if data:byte(0xF) ~= 0x28 or data:byte(0x1B) ~= 1 or data:byte(0x1D) ~= 0x18 then
  470.             error("unsupported bmp format, only uncompressed 24-bit rgb is supported.")
  471.         end
  472.         local offset, linesize = 0x36, math.ceil((width * 3) / 4) * 4
  473.        
  474.         local surf = surface.create(width, height)
  475.         local buffer = surf.buffer
  476.         for j = 0, height - 1 do
  477.             for i = 0, width - 1 do
  478.                 buffer[(j * width + i) * 3 + 1] = data:byte((height - j - 1) * linesize + i * 3 + offset + 3) / 255
  479.                 buffer[(j * width + i) * 3 + 2] = data:byte((height - j - 1) * linesize + i * 3 + offset + 2) / 255
  480.                 buffer[(j * width + i) * 3 + 3] = data:byte((height - j - 1) * linesize + i * 3 + offset + 1) / 255
  481.             end
  482.         end
  483.         return surf
  484.  
  485.     elseif data:find("\30") then
  486.         -- NFT format
  487.         local width, height, lwidth = 0, 1, 0
  488.         for i = 1, #data do
  489.             if data:byte(i) == 10 then -- newline
  490.                 height = height + 1
  491.                 if lwidth > width then
  492.                     width = lwidth
  493.                 end
  494.                 lwidth = 0
  495.             elseif data:byte(i) == 30 or data:byte(i) == 31 then -- color control
  496.                 lwidth = lwidth - 1
  497.             elseif data:byte(i) ~= 13 then -- not carriage return
  498.                 lwidth = lwidth + 1
  499.             end
  500.         end
  501.         if data:byte(#data) == 10 then
  502.             height = height - 1
  503.         end
  504.  
  505.         local surf = surface.create(width, height)
  506.         local buffer = surf.buffer
  507.         local index, x, y, b, t = 1, 0, 0
  508.  
  509.         while index <= #data do
  510.             if data:byte(index) == 10 then
  511.                 x, y = 0, y + 1
  512.             elseif data:byte(index) == 30 then
  513.                 index = index + 1
  514.                 b = _cc_hex_to_color[data:sub(index, index)]
  515.             elseif data:byte(index) == 31 then
  516.                 index = index + 1
  517.                 t = _cc_hex_to_color[data:sub(index, index)]
  518.             elseif data:byte(index) ~= 13 then
  519.                 buffer[(y * width + x) * 3 + 1] = b
  520.                 buffer[(y * width + x) * 3 + 2] = t
  521.                 if b or t then
  522.                     buffer[(y * width + x) * 3 + 3] = data:sub(index, index)
  523.                 elseif data:sub(index, index) ~= " " then
  524.                     buffer[(y * width + x) * 3 + 3] = data:sub(index, index)
  525.                 end
  526.                 x = x + 1
  527.             end
  528.             index = index + 1
  529.         end
  530.  
  531.         return surf
  532.     else
  533.         -- NFP format
  534.         local width, height, lwidth = 0, 1, 0
  535.         for i = 1, #data do
  536.             if data:byte(i) == 10 then -- newline
  537.                 height = height + 1
  538.                 if lwidth > width then
  539.                     width = lwidth
  540.                 end
  541.                 lwidth = 0
  542.             elseif data:byte(i) ~= 13 then -- not carriage return
  543.                 lwidth = lwidth + 1
  544.             end
  545.         end
  546.         if data:byte(#data) == 10 then
  547.             height = height - 1
  548.         end
  549.  
  550.         local surf = surface.create(width, height)
  551.         local buffer = surf.buffer
  552.         local x, y = 0, 0
  553.         for i = 1, #data do
  554.             if data:byte(i) == 10 then
  555.                 x, y = 0, y + 1
  556.             elseif data:byte(i) ~= 13 then
  557.                 buffer[(y * width + x) * 3 + 1] = _cc_hex_to_color[data:sub(i, i)]
  558.                 x = x + 1
  559.             end
  560.         end
  561.  
  562.         return surf
  563.     end
  564. end
  565.  
  566. function surf:save(file, format)
  567.     format = format or "nfp"
  568.     local data = { }
  569.     if format == "nfp" then
  570.         for j = 0, self.height - 1 do
  571.             for i = 0, self.width - 1 do
  572.                 data[#data + 1] = _cc_color_to_hex[self.buffer[(j * self.width + i) * 3 + 1]] or " "
  573.             end
  574.             data[#data + 1] = "\n"
  575.         end
  576.  
  577.     elseif format == "nft" then
  578.         for j = 0, self.height - 1 do
  579.             local b, t, pb, pt
  580.             for i = 0, self.width - 1 do
  581.                 pb = self.buffer[(j * self.width + i) * 3 + 1]
  582.                 pt = self.buffer[(j * self.width + i) * 3 + 2]
  583.                 if pb ~= b then
  584.                     data[#data + 1] = "\30"..(_cc_color_to_hex[pb] or " ")
  585.                     b = pb
  586.                 end
  587.                 if pt ~= t then
  588.                     data[#data + 1] = "\31"..(_cc_color_to_hex[pt] or " ")
  589.                     t = pt
  590.                 end
  591.                 data[#data + 1] = self.buffer[(j * self.width + i) * 3 + 3] or " "
  592.             end
  593.             data[#data + 1] = "\n"
  594.         end
  595.  
  596.     elseif format == "rif" then
  597.         data[1] = "RIF"
  598.         data[2] = string.char(math_floor(self.width / 256), self.width % 256)
  599.         data[3] = string.char(math_floor(self.height / 256), self.height % 256)
  600.         local byte, upper, c = 0, false
  601.         for j = 0, self.width - 1 do
  602.             for i = 0, self.height - 1 do
  603.                 c = self.buffer[(j * self.width + i) * 3 + 1] or 0
  604.                 if not upper then
  605.                     byte = c * 16
  606.                 else
  607.                     byte = byte + c
  608.                     data[#data + 1] = string.char(byte)
  609.                 end
  610.                 upper = not upper
  611.             end
  612.         end
  613.         if upper then
  614.             data[#data + 1] = string.char(byte)
  615.         end
  616.  
  617.     elseif format == "bmp" then
  618.         data[1] = "BM"
  619.         data[2] = string.char(0, 0, 0, 0) -- file size, change later
  620.         data[3] = string.char(0, 0, 0, 0, 0x36, 0, 0, 0, 0x28, 0, 0, 0)
  621.         data[4] = string.char(self.width % 256, math_floor(self.width / 256), 0, 0)
  622.         data[5] = string.char(self.height % 256, math_floor(self.height / 256), 0, 0)
  623.         data[6] = string.char(1, 0, 0x18, 0, 0, 0, 0, 0)
  624.         data[7] = string.char(0, 0, 0, 0) -- pixel data size, change later
  625.         data[8] = string.char(0x13, 0x0B, 0, 0, 0x13, 0x0B, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
  626.  
  627.         local padchars = math.ceil((self.width * 3) / 4) * 4 - self.width * 3
  628.         for j = self.height - 1, 0, -1 do
  629.             for i = 0, self.width - 1 do
  630.                 data[#data + 1] = string.char((self.buffer[(j * self.width + i) * 3 + 1] or 0) * 255)
  631.                 data[#data + 1] = string.char((self.buffer[(j * self.width + i) * 3 + 2] or 0) * 255)
  632.                 data[#data + 1] = string.char((self.buffer[(j * self.width + i) * 3 + 3] or 0) * 255)
  633.             end
  634.             data[#data + 1] = ("\0"):rep(padchars)
  635.         end
  636.         local size = #table_concat(data)
  637.         data[2] = string.char(size % 256, math_floor(size / 256) % 256, math_floor(size / 65536), 0)
  638.         size = size - 54
  639.         data[7] = string.char(size % 256, math_floor(size / 256) % 256, math_floor(size / 65536), 0)
  640.          
  641.     else
  642.         error("format not supported")
  643.     end
  644.  
  645.     data = table_concat(data)
  646.     if file then
  647.         local handle = io.open(file, "wb")
  648.         for i = 1, #data do
  649.             handle:write(data:byte(i))
  650.         end
  651.         handle:close()
  652.     end
  653.     return data
  654. end
  655. function surf:drawLine(x1, y1, x2, y2, b, t, c)
  656.     if x1 == x2 then
  657.         x1, y1, x2, y2 = x1 + self.ox, y1 + self.oy, x2 + self.ox, y2 + self.oy
  658.         if x1 < self.cx or x1 >= self.cx + self.cwidth then return end
  659.         if y2 < y1 then
  660.             local temp = y1
  661.             y1 = y2
  662.             y2 = temp
  663.         end
  664.         if y1 < self.cy then y1 = self.cy end
  665.         if y2 >= self.cy + self.cheight then y2 = self.cy + self.cheight - 1 end
  666.         if b or self.overwrite then
  667.             for j = y1, y2 do
  668.                 self.buffer[(j * self.width + x1) * 3 + 1] = b
  669.             end
  670.         end
  671.         if t or self.overwrite then
  672.             for j = y1, y2 do
  673.                 self.buffer[(j * self.width + x1) * 3 + 2] = t
  674.             end
  675.         end
  676.         if c or self.overwrite then
  677.             for j = y1, y2 do
  678.                 self.buffer[(j * self.width + x1) * 3 + 3] = c
  679.             end
  680.         end
  681.     elseif y1 == y2 then
  682.         x1, y1, x2, y2 = x1 + self.ox, y1 + self.oy, x2 + self.ox, y2 + self.oy
  683.         if y1 < self.cy or y1 >= self.cy + self.cheight then return end
  684.         if x2 < x1 then
  685.             local temp = x1
  686.             x1 = x2
  687.             x2 = temp
  688.         end
  689.         if x1 < self.cx then x1 = self.cx end
  690.         if x2 >= self.cx + self.cwidth then x2 = self.cx + self.cwidth - 1 end
  691.         if b or self.overwrite then
  692.             for i = x1, x2 do
  693.                 self.buffer[(y1 * self.width + i) * 3 + 1] = b
  694.             end
  695.         end
  696.         if t or self.overwrite then
  697.             for i = x1, x2 do
  698.                 self.buffer[(y1 * self.width + i) * 3 + 2] = t
  699.             end
  700.         end
  701.         if c or self.overwrite then
  702.             for i = x1, x2 do
  703.                 self.buffer[(y1 * self.width + i) * 3 + 3] = c
  704.             end
  705.         end
  706.     else
  707.         local delta_x = x2 - x1
  708.         local ix = delta_x > 0 and 1 or -1
  709.         delta_x = 2 * math.abs(delta_x)
  710.         local delta_y = y2 - y1
  711.         local iy = delta_y > 0 and 1 or -1
  712.         delta_y = 2 * math.abs(delta_y)
  713.         self:drawPixel(x1, y1, b, t, c)
  714.         if delta_x >= delta_y then
  715.             local error = delta_y - delta_x / 2
  716.             while x1 ~= x2 do
  717.                 if (error >= 0) and ((error ~= 0) or (ix > 0)) then
  718.                     error = error - delta_x
  719.                     y1 = y1 + iy
  720.                 end
  721.                 error = error + delta_y
  722.                 x1 = x1 + ix
  723.                 self:drawPixel(x1, y1, b, t, c)
  724.             end
  725.         else
  726.             local error = delta_x - delta_y / 2
  727.             while y1 ~= y2 do
  728.                 if (error >= 0) and ((error ~= 0) or (iy > 0)) then
  729.                     error = error - delta_y
  730.                     x1 = x1 + ix
  731.                 end
  732.                 error = error + delta_x
  733.                 y1 = y1 + iy
  734.                 self:drawPixel(x1, y1, b, t, c)
  735.             end
  736.         end
  737.     end
  738. end
  739.  
  740. function surf:drawRect(x, y, width, height, b, t, c)
  741.     self:drawLine(x, y, x + width - 1, y, b, t, c)
  742.     self:drawLine(x, y, x, y + height - 1, b, t, c)
  743.     self:drawLine(x + width - 1, y, x + width - 1, y + height - 1, b, t, c)
  744.     self:drawLine(x, y + height - 1, x + width - 1, y + height - 1, b, t, c)
  745. end
  746.  
  747. function surf:fillRect(x, y, width, height, b, t, c)
  748.     x, y, width, height = clipRect(x + self.ox, y + self.oy, width, height, self.cx, self.cy, self.cwidth, self.cheight)
  749.  
  750.     if b or self.overwrite then
  751.         for j = 0, height - 1 do
  752.             for i = 0, width - 1 do
  753.                 self.buffer[((j + y) * self.width + i + x) * 3 + 1] = b
  754.             end
  755.         end
  756.     end
  757.     if t or self.overwrite then
  758.         for j = 0, height - 1 do
  759.             for i = 0, width - 1 do
  760.                 self.buffer[((j + y) * self.width + i + x) * 3 + 2] = t
  761.             end
  762.         end
  763.     end
  764.     if c or self.overwrite then
  765.         for j = 0, height - 1 do
  766.             for i = 0, width - 1 do
  767.                 self.buffer[((j + y) * self.width + i + x) * 3 + 3] = c
  768.             end
  769.         end
  770.     end
  771. end
  772.  
  773. function surf:drawTriangle(x1, y1, x2, y2, x3, y3, b, t, c)
  774.     self:drawLine(x1, y1, x2, y2, b, t, c)
  775.     self:drawLine(x2, y2, x3, y3, b, t, c)
  776.     self:drawLine(x3, y3, x1, y1, b, t, c)
  777. end
  778.  
  779. function surf:fillTriangle(x1, y1, x2, y2, x3, y3, b, t, c)
  780.     if y1 > y2 then
  781.         local tempx, tempy = x1, y1
  782.         x1, y1 = x2, y2
  783.         x2, y2 = tempx, tempy
  784.     end
  785.     if y1 > y3 then
  786.         local tempx, tempy = x1, y1
  787.         x1, y1 = x3, y3
  788.         x3, y3 = tempx, tempy
  789.     end
  790.     if y2 > y3 then
  791.         local tempx, tempy = x2, y2
  792.         x2, y2 = x3, y3
  793.         x3, y3 = tempx, tempy
  794.     end
  795.     if y1 == y2 and x1 > x2 then
  796.         local temp = x1
  797.         x1 = x2
  798.         x2 = temp
  799.     end
  800.     if y2 == y3 and x2 > x3 then
  801.         local temp = x2
  802.         x2 = x3
  803.         x3 = temp
  804.     end
  805.  
  806.     local x4, y4
  807.     if x1 <= x2 then
  808.         x4 = x1 + (y2 - y1) / (y3 - y1) * (x3 - x1)
  809.         y4 = y2
  810.         local tempx, tempy = x2, y2
  811.         x2, y2 = x4, y4
  812.         x4, y4 = tempx, tempy
  813.     else
  814.         x4 = x1 + (y2 - y1) / (y3 - y1) * (x3 - x1)
  815.         y4 = y2
  816.     end
  817.  
  818.     local finvslope1 = (x2 - x1) / (y2 - y1)
  819.     local finvslope2 = (x4 - x1) / (y4 - y1)
  820.     local linvslope1 = (x3 - x2) / (y3 - y2)
  821.     local linvslope2 = (x3 - x4) / (y3 - y4)
  822.  
  823.     local xstart, xend, dxstart, dxend
  824.     for y = math.ceil(y1 + 0.5) - 0.5, math.floor(y3 - 0.5) + 0.5, 1 do
  825.         if y <= y2 then -- first half
  826.             xstart = x1 + finvslope1 * (y - y1)
  827.             xend = x1 + finvslope2 * (y - y1)
  828.         else -- second half
  829.             xstart = x3 - linvslope1 * (y3 - y)
  830.             xend = x3 - linvslope2 * (y3 - y)
  831.         end
  832.  
  833.         dxstart, dxend = math.ceil(xstart - 0.5), math.floor(xend - 0.5)
  834.         if dxstart <= dxend then
  835.             self:drawLine(dxstart, y - 0.5, dxend, y - 0.5, b, t, c)
  836.         end
  837.     end
  838. end
  839.  
  840. function surf:drawEllipse(x, y, width, height, b, t, c)
  841.     for i = 0, _eprc - 1 do
  842.         self:drawLine(math_floor(x + _ecos[i + 1] * (width - 1) + 0.5), math_floor(y + _esin[i + 1] * (height - 1) + 0.5), math_floor(x + _ecos[(i + 1) % _eprc + 1] * (width - 1) + 0.5), math_floor(y + _esin[(i + 1) % _eprc + 1] * (height - 1) + 0.5), b, t, c)
  843.     end
  844. end
  845.  
  846. function surf:fillEllipse(x, y, width, height, b, t, c)
  847.     x, y = x + self.ox, y + self.oy
  848.  
  849.     local sx, sy
  850.     for j = 0, height - 1 do
  851.         for i = 0, width - 1 do
  852.             sx, sy = i + x, j + y
  853.             if ((i + 0.5) / width * 2 - 1) ^ 2 + ((j + 0.5) / height * 2 - 1) ^ 2 <= 1 and sx >= self.cx and sx < self.cx + self.cwidth and sy >= self.cy and sy < self.cy + self.cheight then
  854.                 if b or self.overwrite then
  855.                     self.buffer[(sy * self.width + sx) * 3 + 1] = b
  856.                 end
  857.                 if t or self.overwrite then
  858.                     self.buffer[(sy * self.width + sx) * 3 + 2] = t
  859.                 end
  860.                 if c or self.overwrite then
  861.                     self.buffer[(sy * self.width + sx) * 3 + 3] = c
  862.                 end
  863.             end
  864.         end
  865.     end
  866. end
  867.  
  868. function surf:drawArc(x, y, width, height, fromangle, toangle, b, t, c)
  869.     if fromangle > toangle then
  870.         local temp = fromangle
  871.         fromangle = toangle
  872.         temp = toangle
  873.     end
  874.     fromangle = math_floor(fromangle / math.pi / 2 * _eprc + 0.5)
  875.     toangle = math_floor(toangle / math.pi / 2 * _eprc + 0.5) - 1
  876.    
  877.     for j = fromangle, toangle do
  878.         local i = j % _eprc
  879.         self:drawLine(math_floor(x + _ecos[i + 1] * (width - 1) + 0.5), math_floor(y + _esin[i + 1] * (height - 1) + 0.5), math_floor(x + _ecos[(i + 1) % _eprc + 1] * (width - 1) + 0.5), math_floor(y + _esin[(i + 1) % _eprc + 1] * (height - 1) + 0.5), b, t, c)
  880.     end
  881. end
  882.  
  883. function surf:fillArc(x, y, width, height, fromangle, toangle, b, t, c)
  884.     x, y = x + self.ox, y + self.oy
  885.  
  886.     if fromangle > toangle then
  887.         local temp = fromangle
  888.         fromangle = toangle
  889.         temp = toangle
  890.     end
  891.     local diff = toangle - fromangle
  892.     fromangle = fromangle % (math.pi * 2)
  893.  
  894.     local fx, fy, sx, sy, dir
  895.     for j = 0, height - 1 do
  896.         for i = 0, width - 1 do
  897.             fx, fy = (i + 0.5) / width * 2 - 1, (j + 0.5) / height * 2 - 1
  898.             sx, sy = i + x, j + y
  899.             dir = math_atan2(-fy, fx) % (math.pi * 2)
  900.             if fx ^ 2 + fy ^ 2 <= 1 and ((dir >= fromangle and dir - fromangle <= diff) or (dir <= (fromangle + diff) % (math.pi * 2))) and sx >= self.cx and sx < self.cx + self.cwidth and sy >= self.cy and sy < self.cy + self.cheight then
  901.                 if b or self.overwrite then
  902.                     self.buffer[(sy * self.width + sx) * 3 + 1] = b
  903.                 end
  904.                 if t or self.overwrite then
  905.                     self.buffer[(sy * self.width + sx) * 3 + 2] = t
  906.                 end
  907.                 if c or self.overwrite then
  908.                     self.buffer[(sy * self.width + sx) * 3 + 3] = c
  909.                 end
  910.             end
  911.         end
  912.     end
  913. end
  914. function surf:drawSurface(surf2, x, y, width, height, sx, sy, swidth, sheight)
  915.     x, y, width, height, sx, sy, swidth, sheight = x + self.ox, y + self.oy, width or surf2.width, height or surf2.height, sx or 0, sy or 0, swidth or surf2.width, sheight or surf2.height
  916.  
  917.     if width == swidth and height == sheight then
  918.         local nx, ny
  919.         nx, ny, width, height = clipRect(x, y, width, height, self.cx, self.cy, self.cwidth, self.cheight)
  920.         swidth, sheight = width, height
  921.         if nx > x then
  922.             sx = sx + nx - x
  923.             x = nx
  924.         end
  925.         if ny > y then
  926.             sy = sy + ny - y
  927.             y = ny
  928.         end
  929.         nx, ny, swidth, sheight = clipRect(sx, sy, swidth, sheight, 0, 0, surf2.width, surf2.height)
  930.         width, height = swidth, sheight
  931.         if nx > sx then
  932.             x = x + nx - sx
  933.             sx = nx
  934.         end
  935.         if ny > sy then
  936.             y = y + ny - sy
  937.             sy = ny
  938.         end
  939.  
  940.         local b, t, c
  941.         for j = 0, height - 1 do
  942.             for i = 0, width - 1 do
  943.                 b = surf2.buffer[((j + sy) * surf2.width + i + sx) * 3 + 1]
  944.                 t = surf2.buffer[((j + sy) * surf2.width + i + sx) * 3 + 2]
  945.                 c = surf2.buffer[((j + sy) * surf2.width + i + sx) * 3 + 3]
  946.                 if b or self.overwrite then
  947.                     self.buffer[((j + y) * self.width + i + x) * 3 + 1] = b
  948.                 end
  949.                 if t or self.overwrite then
  950.                     self.buffer[((j + y) * self.width + i + x) * 3 + 2] = t
  951.                 end
  952.                 if c or self.overwrite then
  953.                     self.buffer[((j + y) * self.width + i + x) * 3 + 3] = c
  954.                 end
  955.             end
  956.         end
  957.     else
  958.         local hmirror, vmirror = false, false
  959.         if width < 0 then
  960.             hmirror = true
  961.             x = x + width
  962.         end
  963.         if height < 0 then
  964.             vmirror = true
  965.             y = y + height
  966.         end
  967.         if swidth < 0 then
  968.             hmirror = not hmirror
  969.             sx = sx + swidth
  970.         end
  971.         if sheight < 0 then
  972.             vmirror = not vmirror
  973.             sy = sy + sheight
  974.         end
  975.         width, height, swidth, sheight = math.abs(width), math.abs(height), math.abs(swidth), math.abs(sheight)
  976.        
  977.         local xscale, yscale, px, py, ssx, ssy, b, t, c = swidth / width, sheight / height
  978.         for j = 0, height - 1 do
  979.             for i = 0, width - 1 do
  980.                 px, py = math_floor((i + 0.5) * xscale), math_floor((j + 0.5) * yscale)
  981.                 if hmirror then
  982.                     ssx = x + width - i - 1
  983.                 else
  984.                     ssx = i + x
  985.                 end
  986.                 if vmirror then
  987.                     ssy = y + height - j - 1
  988.                 else
  989.                     ssy = j + y
  990.                 end
  991.  
  992.                 if ssx >= self.cx and ssx < self.cx + self.cwidth and ssy >= self.cy and ssy < self.cy + self.cheight and px >= 0 and px < surf2.width and py >= 0 and py < surf2.height then
  993.                     b = surf2.buffer[(py * surf2.width + px) * 3 + 1]
  994.                     t = surf2.buffer[(py * surf2.width + px) * 3 + 2]
  995.                     c = surf2.buffer[(py * surf2.width + px) * 3 + 3]
  996.                     if b or self.overwrite then
  997.                         self.buffer[(ssy * self.width + ssx) * 3 + 1] = b
  998.                     end
  999.                     if t or self.overwrite then
  1000.                         self.buffer[(ssy * self.width + ssx) * 3 + 2] = t
  1001.                     end
  1002.                     if c or self.overwrite then
  1003.                         self.buffer[(ssy * self.width + ssx) * 3 + 3] = c
  1004.                     end
  1005.                 end
  1006.             end
  1007.         end
  1008.     end
  1009. end
  1010.  
  1011. function surf:drawSurfaceRotated(surf2, x, y, ox, oy, angle)
  1012.     local sin, cos, sx, sy, px, py = math.sin(angle), math.cos(angle)
  1013.     for j = math.floor(-surf2.height * 0.75), math.ceil(surf2.height * 0.75) do
  1014.         for i = math.floor(-surf2.width * 0.75), math.ceil(surf2.width * 0.75) do
  1015.             sx, sy, px, py = x + i, y + j, math_floor(cos * (i + 0.5) - sin * (j + 0.5) + ox), math_floor(sin * (i + 0.5) + cos * (j + 0.5) + oy)
  1016.             if sx >= self.cx and sx < self.cx + self.cwidth and sy >= self.cy and sy < self.cy + self.cheight and px >= 0 and px < surf2.width and py >= 0 and py < surf2.height then
  1017.                 b = surf2.buffer[(py * surf2.width + px) * 3 + 1]
  1018.                 t = surf2.buffer[(py * surf2.width + px) * 3 + 2]
  1019.                 c = surf2.buffer[(py * surf2.width + px) * 3 + 3]
  1020.                 if b or self.overwrite then
  1021.                     self.buffer[(sy * self.width + sx) * 3 + 1] = b
  1022.                 end
  1023.                 if t or self.overwrite then
  1024.                     self.buffer[(sy * self.width + sx) * 3 + 2] = t
  1025.                 end
  1026.                 if c or self.overwrite then
  1027.                     self.buffer[(sy * self.width + sx) * 3 + 3] = c
  1028.                 end
  1029.             end
  1030.         end
  1031.     end
  1032. end
  1033.  
  1034. function surf:drawSurfacesInterlaced(surfs, x, y, step)
  1035.     x, y, step = x + self.ox, y + self.oy, step or 0
  1036.     local width, height = surfs[1].width, surfs[1].height
  1037.     for i = 2, #surfs do
  1038.         if surfs[i].width ~= width or surfs[i].height ~= height then
  1039.             error("surfaces should be the same size")
  1040.         end
  1041.     end
  1042.    
  1043.     local sx, sy, swidth, sheight, index, b, t, c = clipRect(x, y, width, height, self.cx, self.cy, self.cwidth, self.cheight)
  1044.     for j = sy, sy + sheight - 1 do
  1045.         for i = sx, sx + swidth - 1 do
  1046.             index = (i + j + step) % #surfs + 1
  1047.             b = surfs[index].buffer[((j - sy) * surfs[index].width + i - sx) * 3 + 1]
  1048.             t = surfs[index].buffer[((j - sy) * surfs[index].width + i - sx) * 3 + 2]
  1049.             c = surfs[index].buffer[((j - sy) * surfs[index].width + i - sx) * 3 + 3]
  1050.             if b or self.overwrite then
  1051.                 self.buffer[(j * self.width + i) * 3 + 1] = b
  1052.             end
  1053.             if t or self.overwrite then
  1054.                 self.buffer[(j * self.width + i) * 3 + 2] = t
  1055.             end
  1056.             if c or self.overwrite then
  1057.                 self.buffer[(j * self.width + i) * 3 + 3] = c
  1058.             end
  1059.         end
  1060.     end
  1061. end
  1062.  
  1063. function surf:drawSurfaceSmall(surf2, x, y)
  1064.     x, y = x + self.ox, y + self.oy
  1065.     if surf2.width % 2 ~= 0 or surf2.height % 3 ~= 0 then
  1066.         error("surface width must be a multiple of 2 and surface height a multiple of 3")
  1067.     end
  1068.  
  1069.     local sub, char, c1, c2, c3, c4, c5, c6 = 32768
  1070.     for j = 0, surf2.height / 3 - 1 do
  1071.         for i = 0, surf2.width / 2 - 1 do
  1072.             if i + x >= self.cx and i + x < self.cx + self.cwidth and j + y >= self.cy and j + y < self.cy + self.cheight then
  1073.                 char, c1, c2, c3, c4, c5, c6 = 0,
  1074.                 surf2.buffer[((j * 3) * surf2.width + i * 2) * 3 + 1],
  1075.                 surf2.buffer[((j * 3) * surf2.width + i * 2 + 1) * 3 + 1],
  1076.                 surf2.buffer[((j * 3 + 1) * surf2.width + i * 2) * 3 + 1],
  1077.                 surf2.buffer[((j * 3 + 1) * surf2.width + i * 2 + 1) * 3 + 1],
  1078.                 surf2.buffer[((j * 3 + 2) * surf2.width + i * 2) * 3 + 1],
  1079.                 surf2.buffer[((j * 3 + 2) * surf2.width + i * 2 + 1) * 3 + 1]
  1080.                 if c1 ~= c6 then
  1081.                     sub = c1
  1082.                     char = 1
  1083.                 end
  1084.                 if c2 ~= c6 then
  1085.                     sub = c2
  1086.                     char = char + 2
  1087.                 end
  1088.                 if c3 ~= c6 then
  1089.                     sub = c3
  1090.                     char = char + 4
  1091.                 end
  1092.                 if c4 ~= c6 then
  1093.                     sub = c4
  1094.                     char = char + 8
  1095.                 end
  1096.                 if c5 ~= c6 then
  1097.                     sub = c5
  1098.                     char = char + 16
  1099.                 end
  1100.                 self.buffer[((j + y) * self.width + i + x) * 3 + 1] = c6
  1101.                 self.buffer[((j + y) * self.width + i + x) * 3 + 2] = sub
  1102.                 self.buffer[((j + y) * self.width + i + x) * 3 + 3] = _chars[128 + char]
  1103.             end
  1104.         end
  1105.     end
  1106. end
  1107. function surf:flip(horizontal, vertical)
  1108.     local ox, oy, nx, ny, tb, tt, tc
  1109.     if horizontal then
  1110.         for i = 0, math.ceil(self.cwidth / 2) - 1 do
  1111.             for j = 0, self.cheight - 1 do
  1112.                 ox, oy, nx, ny = i + self.cx, j + self.cy, self.cx + self.cwidth - i - 1, j + self.cy
  1113.                 tb = self.buffer[(oy * self.width + ox) * 3 + 1]
  1114.                 tt = self.buffer[(oy * self.width + ox) * 3 + 2]
  1115.                 tc = self.buffer[(oy * self.width + ox) * 3 + 3]
  1116.                 self.buffer[(oy * self.width + ox) * 3 + 1] = self.buffer[(ny * self.width + nx) * 3 + 1]
  1117.                 self.buffer[(oy * self.width + ox) * 3 + 2] = self.buffer[(ny * self.width + nx) * 3 + 2]
  1118.                 self.buffer[(oy * self.width + ox) * 3 + 3] = self.buffer[(ny * self.width + nx) * 3 + 3]
  1119.                 self.buffer[(ny * self.width + nx) * 3 + 1] = tb
  1120.                 self.buffer[(ny * self.width + nx) * 3 + 2] = tt
  1121.                 self.buffer[(ny * self.width + nx) * 3 + 3] = tc
  1122.             end
  1123.         end
  1124.     end
  1125.     if vertical then
  1126.         for j = 0, math.ceil(self.cheight / 2) - 1 do
  1127.             for i = 0, self.cwidth - 1 do
  1128.                 ox, oy, nx, ny = i + self.cx, j + self.cy, i + self.cx, self.cy + self.cheight - j - 1
  1129.                 tb = self.buffer[(oy * self.width + ox) * 3 + 1]
  1130.                 tt = self.buffer[(oy * self.width + ox) * 3 + 2]
  1131.                 tc = self.buffer[(oy * self.width + ox) * 3 + 3]
  1132.                 self.buffer[(oy * self.width + ox) * 3 + 1] = self.buffer[(ny * self.width + nx) * 3 + 1]
  1133.                 self.buffer[(oy * self.width + ox) * 3 + 2] = self.buffer[(ny * self.width + nx) * 3 + 2]
  1134.                 self.buffer[(oy * self.width + ox) * 3 + 3] = self.buffer[(ny * self.width + nx) * 3 + 3]
  1135.                 self.buffer[(ny * self.width + nx) * 3 + 1] = tb
  1136.                 self.buffer[(ny * self.width + nx) * 3 + 2] = tt
  1137.                 self.buffer[(ny * self.width + nx) * 3 + 3] = tc
  1138.             end
  1139.         end
  1140.     end
  1141. end
  1142.  
  1143. function surf:shift(x, y, b, t, c)
  1144.     local hdir, vdir = x < 0, y < 0
  1145.     local xstart, xend = self.cx, self.cx + self.cwidth - 1
  1146.     local ystart, yend = self.cy, self.cy + self.cheight - 1
  1147.     local nx, ny
  1148.     for j = vdir and ystart or yend, vdir and yend or ystart, vdir and 1 or -1 do
  1149.         for i = hdir and xstart or xend, hdir and xend or xstart, hdir and 1 or -1 do
  1150.             nx, ny = i - x, j - y
  1151.             if nx >= 0 and nx < self.width and ny >= 0 and ny < self.height then
  1152.                 self.buffer[(j * self.width + i) * 3 + 1] = self.buffer[(ny * self.width + nx) * 3 + 1]
  1153.                 self.buffer[(j * self.width + i) * 3 + 2] = self.buffer[(ny * self.width + nx) * 3 + 2]
  1154.                 self.buffer[(j * self.width + i) * 3 + 3] = self.buffer[(ny * self.width + nx) * 3 + 3]
  1155.             else
  1156.                 self.buffer[(j * self.width + i) * 3 + 1] = b
  1157.                 self.buffer[(j * self.width + i) * 3 + 2] = t
  1158.                 self.buffer[(j * self.width + i) * 3 + 3] = c
  1159.             end
  1160.         end
  1161.     end
  1162. end
  1163.  
  1164. function surf:map(colors)
  1165.     local c
  1166.     for j = self.cy, self.cy + self.cheight - 1 do
  1167.         for i = self.cx, self.cx + self.cwidth - 1 do
  1168.             c = colors[self.buffer[(j * self.width + i) * 3 + 1]]
  1169.             if c or self.overwrite then
  1170.                 self.buffer[(j * self.width + i) * 3 + 1] = c
  1171.             end
  1172.         end
  1173.     end
  1174. end
  1175. surface.palette = { }
  1176. surface.palette.cc = {[1]="F0F0F0",[2]="F2B233",[4]="E57FD8",[8]="99B2F2",[16]="DEDE6C",[32]="7FCC19",[64]="F2B2CC",[128]="4C4C4C",[256]="999999",[512]="4C99B2",[1024]="B266E5",[2048]="3366CC",[4096]="7F664C",[8192]="57A64E",[16384]="CC4C4C",[32768]="191919"}
  1177. surface.palette.riko4 = {"181818","1D2B52","7E2553","008651","AB5136","5F564F","7D7F82","FF004C","FFA300","FFF023","00E755","29ADFF","82769C","FF77A9","FECCA9","ECECEC"}
  1178. surface.palette.redirection = {[0]="040404",[1]="FFFFFF"}
  1179.  
  1180. local function setPalette(palette)
  1181.     if palette == _palette then return end
  1182.     _palette = palette
  1183.     _rgbpal, _palr, _palg, _palb = { }, { }, { }, { }
  1184.  
  1185.     local indices = { }
  1186.     for k, v in pairs(_palette) do
  1187.         if type(v) == "string" then
  1188.             _palr[k] = tonumber(v:sub(1, 2), 16) / 255
  1189.             _palg[k] = tonumber(v:sub(3, 4), 16) / 255
  1190.             _palb[k] = tonumber(v:sub(5, 6), 16) / 255
  1191.         elseif type(v) == "number" then
  1192.             _palr[k] = math.floor(v / 65536) / 255
  1193.             _palg[k] = (math.floor(v / 256) % 256) / 255
  1194.             _palb[k] = (v % 256) / 255
  1195.         end
  1196.         indices[#indices + 1] = k
  1197.     end
  1198.  
  1199.     local pr, pg, pb, dist, d, id
  1200.     for i = 0, _steps - 1 do
  1201.         for j = 0, _steps - 1 do
  1202.             for k = 0, _steps - 1 do
  1203.                 pr = (i + 0.5) / _steps
  1204.                 pg = (j + 0.5) / _steps
  1205.                 pb = (k + 0.5) / _steps
  1206.  
  1207.                 dist = 1e10
  1208.                 for l = 1, #indices do
  1209.                     d = (pr - _palr[indices[l]]) ^ 2 + (pg - _palg[indices[l]]) ^ 2 + (pb - _palb[indices[l]]) ^ 2
  1210.                     if d < dist then
  1211.                         dist = d
  1212.                         id = l
  1213.                     end
  1214.                 end
  1215.                 _rgbpal[i * _steps * _steps + j * _steps + k + 1] = indices[id]
  1216.             end
  1217.         end
  1218.     end
  1219. end
  1220.  
  1221.  
  1222.  
  1223. function surf:toRGB(palette)
  1224.     setPalette(palette)
  1225.     local c
  1226.     for j = 0, self.height - 1 do
  1227.         for i = 0, self.width - 1 do
  1228.             c = self.buffer[(j * self.width + i) * 3 + 1]
  1229.             self.buffer[(j * self.width + i) * 3 + 1] = _palr[c]
  1230.             self.buffer[(j * self.width + i) * 3 + 2] = _palg[c]
  1231.             self.buffer[(j * self.width + i) * 3 + 3] = _palb[c]
  1232.         end
  1233.     end
  1234. end
  1235.  
  1236. function surf:toPalette(palette, dither)
  1237.     setPalette(palette)
  1238.     local scale, r, g, b, nr, ng, nb, c, dr, dg, db = _steps - 1
  1239.     for j = 0, self.height - 1 do
  1240.         for i = 0, self.width - 1 do
  1241.             r = self.buffer[(j * self.width + i) * 3 + 1]
  1242.             g = self.buffer[(j * self.width + i) * 3 + 2]
  1243.             b = self.buffer[(j * self.width + i) * 3 + 3]
  1244.             r = (r > 1) and 1 or r
  1245.             r = (r < 0) and 0 or r
  1246.             g = (g > 1) and 1 or g
  1247.             g = (g < 0) and 0 or g
  1248.             b = (b > 1) and 1 or b
  1249.             b = (b < 0) and 0 or b
  1250.            
  1251.             nr = (r == 1) and scale or math_floor(r * _steps)
  1252.             ng = (g == 1) and scale or math_floor(g * _steps)
  1253.             nb = (b == 1) and scale or math_floor(b * _steps)
  1254.             c = _rgbpal[nr * _steps * _steps + ng * _steps + nb + 1]
  1255.             if dither then
  1256.                 dr = (r - _palr[c]) / 16
  1257.                 dg = (g - _palg[c]) / 16
  1258.                 db = (b - _palb[c]) / 16
  1259.  
  1260.                 if i < self.width - 1 then
  1261.                     self.buffer[(j * self.width + i + 1) * 3 + 1] = self.buffer[(j * self.width + i + 1) * 3 + 1] + dr * 7
  1262.                     self.buffer[(j * self.width + i + 1) * 3 + 2] = self.buffer[(j * self.width + i + 1) * 3 + 2] + dg * 7
  1263.                     self.buffer[(j * self.width + i + 1) * 3 + 3] = self.buffer[(j * self.width + i + 1) * 3 + 3] + db * 7
  1264.                 end
  1265.                 if j < self.height - 1 then
  1266.                     if i > 0 then
  1267.                         self.buffer[((j + 1) * self.width + i - 1) * 3 + 1] = self.buffer[((j + 1) * self.width + i - 1) * 3 + 1] + dr * 3
  1268.                         self.buffer[((j + 1) * self.width + i - 1) * 3 + 2] = self.buffer[((j + 1) * self.width + i - 1) * 3 + 2] + dg * 3
  1269.                         self.buffer[((j + 1) * self.width + i - 1) * 3 + 3] = self.buffer[((j + 1) * self.width + i - 1) * 3 + 3] + db * 3
  1270.                     end
  1271.                     self.buffer[((j + 1) * self.width + i) * 3 + 1] = self.buffer[((j + 1) * self.width + i) * 3 + 1] + dr * 5
  1272.                     self.buffer[((j + 1) * self.width + i) * 3 + 2] = self.buffer[((j + 1) * self.width + i) * 3 + 2] + dg * 5
  1273.                     self.buffer[((j + 1) * self.width + i) * 3 + 3] = self.buffer[((j + 1) * self.width + i) * 3 + 3] + db * 5
  1274.                     if i < self.width - 1 then
  1275.                         self.buffer[((j + 1) * self.width + i + 1) * 3 + 1] = self.buffer[((j + 1) * self.width + i + 1) * 3 + 1] + dr * 1
  1276.                         self.buffer[((j + 1) * self.width + i + 1) * 3 + 2] = self.buffer[((j + 1) * self.width + i + 1) * 3 + 2] + dg * 1
  1277.                         self.buffer[((j + 1) * self.width + i + 1) * 3 + 3] = self.buffer[((j + 1) * self.width + i + 1) * 3 + 3] + db * 1
  1278.                     end
  1279.                 end
  1280.             end
  1281.             self.buffer[(j * self.width + i) * 3 + 1] = c
  1282.             self.buffer[(j * self.width + i) * 3 + 2] = nil
  1283.             self.buffer[(j * self.width + i) * 3 + 3] = nil
  1284.         end
  1285.     end
  1286. end
  1287. function surface.loadFont(surf)
  1288.     local font = {width = surf.width, height = surf.height - 1}
  1289.     font.buffer =  { }
  1290.     font.indices = {0}
  1291.     font.widths = { }
  1292.  
  1293.     local startc, hitc, curc = surf.buffer[((surf.height - 1) * surf.width) * 3 + 1]
  1294.     for i = 0, surf.width - 1 do
  1295.         curc = surf.buffer[((surf.height - 1) * surf.width + i) * 3 + 1]
  1296.         if curc ~= startc then
  1297.             hitc = curc
  1298.             break
  1299.         end
  1300.     end
  1301.  
  1302.     for j = 0, surf.height - 2 do
  1303.         for i = 0, surf.width - 1 do
  1304.             font.buffer[j * font.width + i + 1] = surf.buffer[(j * surf.width + i) * 3 + 1] == hitc
  1305.         end
  1306.     end
  1307.  
  1308.     local curchar = 1
  1309.     for i = 0, surf.width - 1 do
  1310.         if surf.buffer[((surf.height - 1) * surf.width + i) * 3 + 1] == hitc then
  1311.             font.widths[curchar] = i - font.indices[curchar]
  1312.             curchar = curchar + 1
  1313.             font.indices[curchar] = i + 1
  1314.         end
  1315.     end
  1316.     font.widths[curchar] = font.width - font.indices[curchar]
  1317.  
  1318.     return font
  1319. end
  1320.  
  1321. function surface.getTextSize(str, font)
  1322.     local cx, cy, maxx = 0, 0, 0
  1323.     local ox, char = cx
  1324.  
  1325.     for i = 1, #str do
  1326.         char = str:byte(i) - 31
  1327.  
  1328.         if char + 31 == 10 then -- newline
  1329.             cx = ox
  1330.             cy = cy + font.height + 1
  1331.         elseif font.indices[char] then
  1332.             cx = cx + font.widths[char] + 1
  1333.         else
  1334.             cx = cx + font.widths[1]
  1335.         end
  1336.         if cx > maxx then
  1337.             maxx = cx
  1338.         end
  1339.     end
  1340.  
  1341.     return maxx - 1, cy + font.height
  1342. end
  1343.  
  1344. function surf:drawText(str, font, x, y, b, t, c)
  1345.     local cx, cy = x + self.ox, y + self.oy
  1346.     local ox, char, idx = cx
  1347.  
  1348.     for i = 1, #str do
  1349.         char = str:byte(i) - 31
  1350.  
  1351.         if char + 31 == 10 then -- newline
  1352.             cx = ox
  1353.             cy = cy + font.height + 1
  1354.         elseif font.indices[char] then
  1355.             for i = 0, font.widths[char] - 1 do
  1356.                 for j = 0, font.height - 1 do
  1357.                     x, y = cx + i, cy + j
  1358.                     if font.buffer[j * font.width + i + font.indices[char] + 1] then
  1359.                         if x >= self.cx and x < self.cx + self.cwidth and y >= self.cy and y < self.cy + self.cheight then
  1360.                             idx = (y * self.width + x) * 3
  1361.                             if b or self.overwrite then
  1362.                                 self.buffer[idx + 1] = b
  1363.                             end
  1364.                             if t or self.overwrite then
  1365.                                 self.buffer[idx + 2] = t
  1366.                             end
  1367.                             if c or self.overwrite then
  1368.                                 self.buffer[idx + 3] = c
  1369.                             end
  1370.                         end
  1371.                     end
  1372.                 end
  1373.             end
  1374.             cx = cx + font.widths[char] + 1
  1375.         else
  1376.             cx = cx + font.widths[1]
  1377.         end
  1378.     end
  1379. end
  1380. local smap = { }
  1381. surface.smap = smap
  1382.  
  1383. function surface.loadSpriteMap(surf, spwidth, spheight, sprites)
  1384.     if surf.width % spwidth ~= 0 or surf.height % spheight ~= 0 then
  1385.         error("sprite width/height does not match smap width/height")
  1386.     end
  1387.  
  1388.     local smap = setmetatable({ }, {__index = surface.smap})
  1389.     smap.surf = surf
  1390.     smap.spwidth = spwidth
  1391.     smap.spheight = spheight
  1392.     smap.sprites = sprites or ((surf.width / spwidth) * (surf.height / spheight))
  1393.     smap.perline = surf.width / spwidth
  1394.  
  1395.     return smap
  1396. end
  1397.  
  1398. function smap:pos(index, scale)
  1399.     if index < 0 or index >= self.sprites then
  1400.         error("sprite index out of bounds")
  1401.     end
  1402.  
  1403.     return (index % self.perline) * self.spwidth, math.floor(index / self.perline) * self.spheight
  1404. end
  1405.  
  1406. function smap:sprite(index, x, y, width, height)
  1407.     local sx, sy = self:pos(index)
  1408.     return self.surf, x, y, width or self.spwidth, height or self.spheight, sx, sy, self.spwidth, self.spheight
  1409. end
  1410. end return surface
Add Comment
Please, Sign In to add comment