Whiskas1

Untitled

Dec 25th, 2015
63
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1.  
  2. -- Адаптивная загрузка необходимых библиотек и компонентов
  3. local libraries = {
  4. ["component"] = "component",
  5. ["unicode"] = "unicode",
  6. ["image"] = "image",
  7. ["colorlib"] = "colorlib",
  8. }
  9.  
  10. local components = {
  11. ["gpu"] = "gpu",
  12. }
  13.  
  14. for library in pairs(libraries) do if not _G[library] then _G[library] = require(libraries[library]) end end
  15. for comp in pairs(components) do if not _G[comp] then _G[comp] = _G.component[components[comp]] end end
  16. libraries, components = nil, nil
  17.  
  18. local buffer = {}
  19. local debug = false
  20. local sizeOfPixelData = 3
  21.  
  22. ------------------------------------------------------------------------------------------------------
  23.  
  24. --Формула конвертации индекса массива изображения в абсолютные координаты пикселя изображения
  25. local function convertIndexToCoords(index)
  26. --Приводим индекс к корректному виду (1 = 1, 4 = 2, 7 = 3, 10 = 4, 13 = 5, ...)
  27. index = (index + sizeOfPixelData - 1) / sizeOfPixelData
  28. --Получаем остаток от деления индекса на ширину изображения
  29. local ostatok = index % buffer.screen.width
  30. --Если остаток равен 0, то х равен ширине изображения, а если нет, то х равен остатку
  31. local x = (ostatok == 0) and buffer.screen.width or ostatok
  32. --А теперь как два пальца получаем координату по Y
  33. local y = math.ceil(index / buffer.screen.width)
  34. --Очищаем остаток из оперативки
  35. ostatok = nil
  36. --Возвращаем координаты
  37. return x, y
  38. end
  39.  
  40. --Формула конвертации абсолютных координат пикселя изображения в индекс для массива изображения
  41. local function convertCoordsToIndex(x, y)
  42. return (buffer.screen.width * (y - 1) + x) * sizeOfPixelData - sizeOfPixelData + 1
  43. end
  44.  
  45. local function printDebug(line, text)
  46. if debug then
  47. ecs.square(1, line, buffer.screen.width, 1, 0x262626)
  48. ecs.colorText(2, line, 0xFFFFFF, text)
  49. end
  50. end
  51.  
  52. function buffer.createArray()
  53. buffer.screen.current = {}
  54. buffer.screen.new = {}
  55.  
  56. for y = 1, buffer.screen.height do
  57. for x = 1, buffer.screen.width do
  58. table.insert(buffer.screen.current, 0x010101)
  59. table.insert(buffer.screen.current, 0xFEFEFE)
  60. table.insert(buffer.screen.current, " ")
  61.  
  62. table.insert(buffer.screen.new, 0x010101)
  63. table.insert(buffer.screen.new, 0xFEFEFE)
  64. table.insert(buffer.screen.new, " ")
  65. end
  66. end
  67. end
  68.  
  69. function buffer.start()
  70. buffer.totalCountOfGPUOperations = 0
  71. buffer.localCountOfGPUOperations = 0
  72.  
  73. buffer.screen = {
  74. current = {},
  75. new = {},
  76. }
  77.  
  78. buffer.screen.width, buffer.screen.height = gpu.getResolution()
  79. buffer.createArray()
  80. end
  81.  
  82. function buffer.get(x, y)
  83. local index = convertCoordsToIndex(x, y)
  84. if x >= 1 and y >= 1 and x <= buffer.screen.width and y <= buffer.screen.height then
  85. return buffer.screen.current[index], buffer.screen.current[index + 1], buffer.screen.current[index + 2]
  86. else
  87. error("Невозможно получить указанные значения, так как указанные координаты лежат за пределами экрана.\n")
  88. end
  89. end
  90.  
  91. function buffer.set(x, y, background, foreground, symbol)
  92. local index = convertCoordsToIndex(x, y)
  93. if x >= 1 and y >= 1 and x <= buffer.screen.width and y <= buffer.screen.height then
  94. buffer.screen.new[index] = background
  95. buffer.screen.new[index + 1] = foreground
  96. buffer.screen.new[index + 2] = symbol
  97. end
  98. end
  99.  
  100. --Нарисовать квадрат
  101. function buffer.square(x, y, width, height, background, foreground, symbol, transparency)
  102. local index
  103. if transparency then transparency = transparency * 2.55 end
  104. for j = y, (y + height - 1) do
  105. for i = x, (x + width - 1) do
  106. if i >= 1 and j >= 1 and i <= buffer.screen.width and j <= buffer.screen.height then
  107. index = convertCoordsToIndex(i, j)
  108. if transparency then
  109. buffer.screen.new[index] = colorlib.alphaBlend(buffer.screen.new[index], background, transparency)
  110. buffer.screen.new[index + 1] = colorlib.alphaBlend(buffer.screen.new[index + 1], background, transparency)
  111. else
  112. buffer.screen.new[index] = background
  113. buffer.screen.new[index + 1] = foreground
  114. buffer.screen.new[index + 2] = symbol
  115. end
  116. end
  117. end
  118. end
  119. end
  120.  
  121. --Заливка области изображения (рекурсивная, говно-метод)
  122. function buffer.fill(x, y, background, foreground, symbol)
  123.  
  124. local startBackground, startForeground, startSymbol
  125.  
  126. local function doFill(xStart, yStart)
  127. local index = convertCoordsToIndex(xStart, yStart)
  128.  
  129. if
  130. buffer.screen.new[index] ~= startBackground or
  131. -- buffer.screen.new[index + 1] ~= startForeground or
  132. -- buffer.screen.new[index + 2] ~= startSymbol or
  133. buffer.screen.new[index] == background
  134. -- buffer.screen.new[index + 1] == foreground or
  135. -- buffer.screen.new[index + 2] == symbol
  136. then
  137. return
  138. end
  139.  
  140. --Заливаем в память
  141. buffer.screen.new[index] = background
  142. buffer.screen.new[index + 1] = foreground
  143. buffer.screen.new[index + 2] = symbol
  144.  
  145. doFill(xStart + 1, yStart)
  146. doFill(xStart - 1, yStart)
  147. doFill(xStart, yStart + 1)
  148. doFill(xStart, yStart - 1)
  149.  
  150. iterator = nil
  151. end
  152.  
  153. local startIndex = convertCoordsToIndex(x, y)
  154. startBackground = buffer.screen.new[startIndex]
  155. startForeground = buffer.screen.new[startIndex + 1]
  156. startSymbol = buffer.screen.new[startIndex + 2]
  157.  
  158. doFill(x, y)
  159. end
  160.  
  161. --Нарисовать окружность, алгоритм спизжен с вики
  162. function buffer.circle(xCenter, yCenter, radius, background, foreground, symbol)
  163. --Подфункция вставки точек
  164. local function insertPoints(x, y)
  165. buffer.set(xCenter + x * 2, yCenter + y, background, foreground, symbol)
  166. buffer.set(xCenter + x * 2, yCenter - y, background, foreground, symbol)
  167. buffer.set(xCenter - x * 2, yCenter + y, background, foreground, symbol)
  168. buffer.set(xCenter - x * 2, yCenter - y, background, foreground, symbol)
  169.  
  170. buffer.set(xCenter + x * 2 + 1, yCenter + y, background, foreground, symbol)
  171. buffer.set(xCenter + x * 2 + 1, yCenter - y, background, foreground, symbol)
  172. buffer.set(xCenter - x * 2 + 1, yCenter + y, background, foreground, symbol)
  173. buffer.set(xCenter - x * 2 + 1, yCenter - y, background, foreground, symbol)
  174. end
  175.  
  176. local x = 0
  177. local y = radius
  178. local delta = 3 - 2 * radius;
  179. while (x < y) do
  180. insertPoints(x, y);
  181. insertPoints(y, x);
  182. if (delta < 0) then
  183. delta = delta + (4 * x + 6)
  184. else
  185. delta = delta + (4 * (x - y) + 10)
  186. y = y - 1
  187. end
  188. x = x + 1
  189. end
  190.  
  191. if x == y then insertPoints(x, y) end
  192. end
  193.  
  194. --Скопировать область изображения и вернуть ее в виде массива
  195. function buffer.copy(x, y, width, height)
  196. local copyArray = {
  197. ["width"] = width,
  198. ["height"] = height,
  199. }
  200.  
  201. if x < 1 or y < 1 or x + width - 1 > buffer.screen.width or y + height - 1 > buffer.screen.height then
  202. errror("Область копирования выходит за пределы экрана.")
  203. end
  204.  
  205. local index
  206. for j = y, (y + height - 1) do
  207. for i = x, (x + width - 1) do
  208. index = convertCoordsToIndex(i, j)
  209. table.insert(copyArray, buffer.screen.new[index])
  210. table.insert(copyArray, buffer.screen.new[index + 1])
  211. table.insert(copyArray, buffer.screen.new[index + 2])
  212. end
  213. end
  214.  
  215. return copyArray
  216. end
  217.  
  218. --Вставить скопированную ранее область изображения
  219. function buffer.paste(x, y, copyArray)
  220. local index, arrayIndex
  221. if not copyArray or #copyArray == 0 then error("Массив области экрана пуст.") end
  222.  
  223. for j = y, (y + copyArray.height - 1) do
  224. for i = x, (x + copyArray.width - 1) do
  225. if i >= 1 and j >= 1 and i <= buffer.screen.width and j <= buffer.screen.height then
  226. --Рассчитываем индекс массива основного изображения
  227. index = convertCoordsToIndex(i, j)
  228. --Копипаст формулы, аккуратнее!
  229. --Рассчитываем индекс массива вставочного изображения
  230. arrayIndex = (copyArray.width * ((j - y + 1) - 1) + (i - x + 1)) * sizeOfPixelData - sizeOfPixelData + 1
  231. --Вставляем данные
  232. buffer.screen.new[index] = copyArray[arrayIndex]
  233. buffer.screen.new[index + 1] = copyArray[arrayIndex + 1]
  234. buffer.screen.new[index + 2] = copyArray[arrayIndex + 2]
  235. end
  236. end
  237. end
  238. end
  239.  
  240. --Нарисовать линию, алгоритм спизжен с вики
  241. function buffer.line(x1, y1, x2, y2, background, foreground, symbol)
  242. local deltaX = math.abs(x2 - x1)
  243. local deltaY = math.abs(y2 - y1)
  244. local signX = (x1 < x2) and 1 or -1
  245. local signY = (y1 < y2) and 1 or -1
  246.  
  247. local errorCyka = deltaX - deltaY
  248. local errorCyka2
  249.  
  250. buffer.set(x2, y2, background, foreground, symbol)
  251.  
  252. while(x1 ~= x2 or y1 ~= y2) do
  253. buffer.set(x1, y1, background, foreground, symbol)
  254.  
  255. errorCyka2 = errorCyka * 2
  256.  
  257. if (errorCyka2 > -deltaY) then
  258. errorCyka = errorCyka - deltaY
  259. x1 = x1 + signX
  260. end
  261.  
  262. if (errorCyka2 < deltaX) then
  263. errorCyka = errorCyka + deltaX
  264. y1 = y1 + signY
  265. end
  266. end
  267. end
  268.  
  269. function buffer.text(x, y, color, text)
  270. local index
  271. local sText = unicode.len(text)
  272. for i = 1, sText do
  273. if (x + i - 1) >= 1 and y >= 1 and (x + i - 1) <= buffer.screen.width and y <= buffer.screen.height then
  274. index = convertCoordsToIndex(x + i - 1, y)
  275. buffer.screen.new[index + 1] = color
  276. buffer.screen.new[index + 2] = unicode.sub(text, i, i)
  277. end
  278. end
  279. end
  280.  
  281. function buffer.image(x, y, picture)
  282. if not image then image = require("image") end
  283. local index, imageIndex
  284. for j = y, (y + picture.height - 1) do
  285. for i = x, (x + picture.width - 1) do
  286. if i >= 1 and j >= 1 and i <= buffer.screen.width and j <= buffer.screen.height then
  287. index = convertCoordsToIndex(i, j)
  288. --Копипаст формулы!
  289. imageIndex = (picture.width * ((j - y + 1) - 1) + (i - x + 1)) * 4 - 4 + 1
  290.  
  291. if picture[imageIndex + 2] ~= 0x00 then
  292. buffer.screen.new[index] = colorlib.alphaBlend(buffer.screen.new[index], picture[imageIndex], picture[imageIndex + 2])
  293. else
  294. buffer.screen.new[index] = picture[imageIndex]
  295. end
  296. buffer.screen.new[index + 1] = picture[imageIndex + 1]
  297. buffer.screen.new[index + 2] = picture[imageIndex + 3]
  298. end
  299. end
  300. end
  301. end
  302.  
  303. function buffer.button(x, y, width, height, background, foreground, text)
  304. local textPosX = math.floor(x + width / 2 - unicode.len(text) / 2)
  305. local textPosY = math.floor(y + height / 2)
  306. buffer.square(x, y, width, height, background, 0xFFFFFF, " ")
  307. buffer.text(textPosX, textPosY, foreground, text)
  308.  
  309. return x, y, (x + width - 1), (y + height - 1)
  310. end
  311.  
  312. function buffer.adaptiveButton(x, y, xOffset, yOffset, background, foreground, text)
  313. local width = xOffset * 2 + unicode.len(text)
  314. local height = yOffset * 2 + 1
  315.  
  316. buffer.square(x, y, width, height, background, 0xFFFFFF, " ")
  317. buffer.text(x + xOffset, y + yOffset, foreground, text)
  318.  
  319. return x, y, (x + width - 1), (y + height - 1)
  320. end
  321.  
  322. function buffer.scrollBar(x, y, width, height, countOfAllElements, currentElement, backColor, frontColor)
  323. local sizeOfScrollBar = math.ceil(1 / countOfAllElements * height)
  324. local displayBarFrom = math.floor(y + height * ((currentElement - 1) / countOfAllElements))
  325.  
  326. buffer.square(x, y, width, height, backColor, 0xFFFFFF, " ")
  327. buffer.square(x, displayBarFrom, width, sizeOfScrollBar, frontColor, 0xFFFFFF, " ")
  328.  
  329. sizeOfScrollBar, displayBarFrom = nil, nil
  330. end
  331.  
  332. function buffer.calculateDifference(x, y)
  333. local index = convertCoordsToIndex(x, y)
  334. local backgroundIsChanged, foregroundIsChanged, symbolIsChanged = false, false, false
  335.  
  336. --Если цвет фона на новом экране отличается от цвета фона на текущем, то
  337. if buffer.screen.new[index] ~= buffer.screen.current[index] then
  338. --Присваиваем цвету фона на текущем экране значение цвета фона на новом экране
  339. buffer.screen.current[index] = buffer.screen.new[index]
  340.  
  341. --Говорим системе, что что фон изменился
  342. backgroundIsChanged = true
  343. end
  344.  
  345. index = index + 1
  346.  
  347. --Аналогично для цвета текста
  348. if buffer.screen.new[index] ~= buffer.screen.current[index] then
  349. buffer.screen.current[index] = buffer.screen.new[index]
  350. foregroundIsChanged = true
  351. --if _G.cyka then ecs.error("new = \"" .. ecs.HEXtoString(buffer.screen.new[index], 6) .."\", current = \"" .. ecs.HEXtoString(buffer.screen.current[index], 6) .."\"") end
  352. end
  353.  
  354. index = index + 1
  355.  
  356. --И для символа
  357. if buffer.screen.new[index] ~= buffer.screen.current[index] then
  358. buffer.screen.current[index] = buffer.screen.new[index]
  359. symbolIsChanged = true
  360. end
  361.  
  362. return backgroundIsChanged, foregroundIsChanged, symbolIsChanged
  363. end
  364.  
  365. function buffer.draw(force)
  366. local currentBackground, currentForeground = -math.huge, -math.huge
  367. local backgroundIsChanged, foregroundIsChanged, symbolIsChanged
  368. local index
  369. local massiv
  370. buffer.localCountOfGPUOperations = 0
  371.  
  372. for y = 1, buffer.screen.height do
  373. local x = 1
  374. while x <= buffer.screen.width do
  375.  
  376. index = convertCoordsToIndex(x, y)
  377.  
  378. backgroundIsChanged, foregroundIsChanged, symbolIsChanged = buffer.calculateDifference(x, y)
  379.  
  380. --Оптимизация by me
  381. --Ну, скорее, жесткий багфикс
  382. --Но "оптимизация" звучит красивее
  383. --Если были найдены какие-то отличия нового экрана от старого, то корректируем эти отличия через gpu.set()
  384. if backgroundIsChanged or foregroundIsChanged or symbolIsChanged or force then
  385.  
  386. if currentBackground ~= buffer.screen.current[index] then
  387. gpu.setBackground(buffer.screen.current[index])
  388. currentBackground = buffer.screen.current[index]
  389. buffer.localCountOfGPUOperations = buffer.localCountOfGPUOperations + 1
  390. end
  391.  
  392. index = index + 1
  393.  
  394. if currentForeground ~= buffer.screen.current[index] then
  395. gpu.setForeground(buffer.screen.current[index])
  396. currentForeground = buffer.screen.current[index]
  397. buffer.localCountOfGPUOperations = buffer.localCountOfGPUOperations + 1
  398. end
  399.  
  400. index = index - 1
  401.  
  402. --Оптимизация by Krutoy
  403. massiv = { buffer.screen.current[index + 2] }
  404.  
  405. --Отрисовка линиями. Не трожь, сука!
  406. local iIndex
  407. for i = (x + 1), buffer.screen.width do
  408. iIndex = convertCoordsToIndex(i, y)
  409. if
  410. buffer.screen.current[index] == buffer.screen.new[iIndex] and
  411. (
  412. buffer.screen.new[iIndex + 2] == " "
  413. or
  414. buffer.screen.current[index + 1] == buffer.screen.new[iIndex + 1]
  415. )
  416. then
  417. buffer.calculateDifference(i, y)
  418. table.insert(massiv, buffer.screen.current[iIndex + 2])
  419. else
  420. break
  421. end
  422. end
  423.  
  424. --os.sleep(0.2)
  425. gpu.set(x, y, table.concat(massiv))
  426.  
  427. x = x + #massiv - 1
  428.  
  429. buffer.localCountOfGPUOperations = buffer.localCountOfGPUOperations + 1
  430. end
  431.  
  432. x = x + 1
  433. end
  434. end
  435.  
  436. buffer.totalCountOfGPUOperations = buffer.totalCountOfGPUOperations + buffer.localCountOfGPUOperations
  437. printDebug(50, "Общее число GPU-операций: " .. buffer.totalCountOfGPUOperations .. ", число операций при последнем рендере: " .. buffer.localCountOfGPUOperations)
  438. end
  439.  
  440. ------------------------------------------------------------------------------------------------------
  441.  
  442. buffer.start()
  443.  
  444. ------------------------------------------------------------------------------------------------------
  445.  
  446. return buffer
RAW Paste Data