nonogamer9

ezsqdfg

Feb 27th, 2026 (edited)
137
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.31 KB | None | 0 0
  1. local originalTerm = term.native()
  2.  
  3. local GraphicsEmulator = {
  4. mode = 0,
  5. pixelBuffer = {},
  6. bankedPalette = {},
  7. SCALE_X = 6,
  8. SCALE_Y = 9,
  9. width = 0,
  10. height = 0
  11. }
  12.  
  13. -- Initialize dimensions and buffer
  14. function GraphicsEmulator:init()
  15. local tw, th = originalTerm.getSize()
  16. self.width = tw
  17. self.height = th
  18.  
  19. -- Initialize the 256-color pixel buffer (0-indexed coordinates)
  20. local pw, ph = tw * self.SCALE_X, th * self.SCALE_Y
  21. for y = 0, ph - 1 do
  22. self.pixelBuffer[y] = {}
  23. for x = 0, pw - 1 do
  24. self.pixelBuffer[y][x] = 0
  25. end
  26. end
  27. end
  28.  
  29. -- 1. Banking: Save current text-mode palette
  30. function GraphicsEmulator:bankPalette()
  31. for i = 0, 15 do
  32. local color = 2^i
  33. local r, g, b = originalTerm.getPaletteColor(color)
  34. self.bankedPalette[color] = {r, g, b}
  35. end
  36. end
  37.  
  38. -- 2. Restore: Put back the original text-mode palette
  39. function GraphicsEmulator:restorePalette()
  40. for color, rgb in pairs(self.bankedPalette) do
  41. originalTerm.setPaletteColor(color, table.unpack(rgb))
  42. end
  43. end
  44.  
  45. -- 3. Dynamic Palette: Scan the 256-color buffer to find the best 16 colors
  46. function GraphicsEmulator:refreshDynamicPalette()
  47. if self.mode ~= 2 then return end
  48.  
  49. -- Divide the 256 colors into 16 "blocks" of 16 colors each
  50. for block = 0, 15 do
  51. local freq = {}
  52. local startIdx = block * 16
  53. local endIdx = startIdx + 15
  54.  
  55. -- Analyze current pixel buffer for this specific block
  56. for y = 0, (self.height * self.SCALE_Y) - 1 do
  57. local row = self.pixelBuffer[y]
  58. for x = 0, (self.width * self.SCALE_X) - 1 do
  59. local c = row[x]
  60. if c >= startIdx and c <= endIdx then
  61. freq[c] = (freq[c] or 0) + 1
  62. end
  63. end
  64. end
  65.  
  66. -- Find the most frequent color in this range
  67. local winner = startIdx
  68. local maxCount = -1
  69. for c = startIdx, endIdx do
  70. if (freq[c] or 0) > maxCount then
  71. maxCount = freq[c] or 0
  72. winner = c
  73. end
  74. end
  75.  
  76. -- Map this representative color to the hardware's 16-color slot
  77. -- Note: term.getPaletteColor(winner) works because we are in mode 2
  78. local r, g, b = term.getPaletteColor(winner)
  79. originalTerm.setPaletteColor(2^block, r, g, b)
  80. end
  81. end
  82.  
  83. -- 4. Mode Switcher: Handles the transition and banking automatically
  84. function GraphicsEmulator:setMode(newMode)
  85. -- Entering Graphics Mode from Text Mode
  86. if newMode ~= 0 and self.mode == 0 then
  87. self:bankPalette()
  88. -- Returning to Text Mode
  89. elseif newMode == 0 and self.mode ~= 0 then
  90. self:restorePalette()
  91. end
  92.  
  93. self.mode = newMode
  94. term.setGraphicsMode(newMode)
  95. end
  96.  
  97. -- 5. Cell Updater: Converts a 6x9 pixel block into a single blit character
  98. function GraphicsEmulator:updateCell(cellX, cellY)
  99. local subPixels = {}
  100. local colorFreq = {}
  101.  
  102. -- Downsample 6x9 logical area into 2x3 visual sub-pixels
  103. for zy = 0, 2 do
  104. for zx = 0, 1 do
  105. local x = cellX * self.SCALE_X + (zx * 3)
  106. local y = cellY * self.SCALE_Y + (zy * 3)
  107.  
  108. -- Simple sampling: take the top-left pixel of each 3x3 zone
  109. local zoneColor = (self.pixelBuffer[y] and self.pixelBuffer[y][x]) or 0
  110.  
  111. table.insert(subPixels, zoneColor)
  112. colorFreq[zoneColor] = (colorFreq[zoneColor] or 0) + 1
  113. end
  114. end
  115.  
  116. -- Background is the most frequent color in the 6 zones
  117. local bgColor = subPixels[1]
  118. local maxC = -1
  119. for c, count in pairs(colorFreq) do
  120. if count > maxC then maxC = count; bgColor = c end
  121. end
  122.  
  123. -- Foreground is the first color that isn't the background
  124. local fgColor = bgColor
  125. for i = 1, 6 do
  126. if subPixels[i] ~= bgColor then
  127. fgColor = subPixels[i]
  128. break
  129. end
  130. end
  131.  
  132. -- Construct the character code (128-159)
  133. local charCode = 128
  134. local bitValues = {1, 2, 4, 8, 16, 32}
  135.  
  136. for i = 1, 6 do
  137. if subPixels[i] ~= bgColor then
  138. charCode = charCode + bitValues[i]
  139. end
  140. end
  141. if charCode > 159 then charCode = 159 end
  142.  
  143. -- Map 256-colors to the 0-F hex range for blit
  144. local fIdx = math.floor(fgColor / 16)
  145. local bIdx = math.floor(bgColor / 16)
  146.  
  147. local fChar = string.format("%x", fIdx)
  148. local bChar = string.format("%x", bIdx)
  149.  
  150. originalTerm.setCursorPos(cellX + 1, cellY + 1)
  151. if fChar == bChar or charCode == 128 then
  152. originalTerm.blit(" ", bChar, bChar)
  153. else
  154. originalTerm.blit(string.char(charCode), fChar, bChar)
  155. end
  156. end
  157.  
  158. -- 6. Render Frame: Refreshes the whole screen
  159. function GraphicsEmulator:renderFrame()
  160. -- First, freeze to prevent flickering
  161. if term.setFrozen then term.setFrozen(true) end
  162.  
  163. -- Recalculate which 16 colors represent the frame best
  164. self:refreshDynamicPalette()
  165.  
  166. -- Update every text cell
  167. for y = 0, self.height - 1 do
  168. for x = 0, self.width - 1 do
  169. self:updateCell(x, y)
  170. end
  171. end
  172.  
  173. if term.setFrozen then term.setFrozen(false) end
  174. end
Advertisement
Add Comment
Please, Sign In to add comment