From cdbb421e7ec739b44279f500665c45540a21a075 Mon Sep 17 00:00:00 2001 From: IgorTimofeev Date: Sun, 8 Oct 2023 19:09:42 +0300 Subject: [PATCH] Rendering support for fucking W I D E characters --- Applications/Settings.app/Main.lua | 2 +- Libraries/GUI.lua | 48 ++--- Libraries/Screen.lua | 319 ++++++++++++++++++++++------- 3 files changed, 271 insertions(+), 98 deletions(-) diff --git a/Applications/Settings.app/Main.lua b/Applications/Settings.app/Main.lua index 215fdc78..7701c1b7 100644 --- a/Applications/Settings.app/Main.lua +++ b/Applications/Settings.app/Main.lua @@ -131,7 +131,7 @@ for i = 1, #modules do object.draw = moduleDraw object.eventHandler = moduleEventHandler - leftPanel.width = math.max(leftPanel.width, unicode.len(result.name) + 14) + leftPanel.width = math.max(leftPanel.width, unicode.wlen(result.name) + 14) else error("Failed to execute module " .. modules[i] .. ": " .. tostring(result)) end diff --git a/Libraries/GUI.lua b/Libraries/GUI.lua index 690ef769..6c755874 100755 --- a/Libraries/GUI.lua +++ b/Libraries/GUI.lua @@ -550,7 +550,7 @@ local function pressableDraw(pressable) screen.drawRectangle(pressable.x, pressable.y, pressable.width, pressable.height, background, text, " ") end - screen.drawText(math.floor(pressable.x + pressable.width / 2 - unicode.len(pressable.text) / 2), math.floor(pressable.y + pressable.height / 2), text, pressable.text) + screen.drawText(math.floor(pressable.x + pressable.width / 2 - unicode.wlen(pressable.text) / 2), math.floor(pressable.y + pressable.height / 2), text, pressable.text) end local function pressableHandlePress(workspace, pressable, ...) @@ -672,7 +672,7 @@ local function buttonGetColors(button) end local function buttonDrawText(button, textColor) - screen.drawText(math.floor(button.x + button.width / 2 - unicode.len(button.text) / 2), math.floor(button.y + button.height / 2), textColor, button.text) + screen.drawText(math.floor(button.x + button.width / 2 - unicode.wlen(button.text) / 2), math.floor(button.y + button.height / 2), textColor, button.text) end local function buttonDraw(button) @@ -741,7 +741,7 @@ local function buttonCreate(x, y, width, height, backgroundColor, textColor, bac end local function adaptiveButtonCreate(x, y, xOffset, yOffset, backgroundColor, textColor, backgroundPressedColor, textPressedColor, text) - return buttonCreate(x, y, unicode.len(text) + xOffset * 2, yOffset * 2 + 1, backgroundColor, textColor, backgroundPressedColor, textPressedColor, text) + return buttonCreate(x, y, unicode.wlen(text) + xOffset * 2, yOffset * 2 + 1, backgroundColor, textColor, backgroundPressedColor, textPressedColor, text) end function GUI.button(...) @@ -848,7 +848,7 @@ local function drawLabel(object) object.height, object.horizontalAlignment, object.verticalAlignment, - unicode.len(object.text), + unicode.wlen(object.text), 1 ) screen.drawText(math.floor(xText), math.floor(yText), object.colors.text, object.text) @@ -910,7 +910,7 @@ local function drawProgressBar(object) if object.showValue then local stringValue = (object.valuePrefix or "") .. object.value .. (object.valuePostfix or "") - screen.drawText(math.floor(object.x + object.width / 2 - unicode.len(stringValue) / 2), object.y + 1, object.colors.value, stringValue) + screen.drawText(math.floor(object.x + object.width / 2 - unicode.wlen(stringValue) / 2), object.y + 1, object.colors.value, stringValue) end return object @@ -1013,7 +1013,7 @@ local function codeViewDraw(codeView) local y, toLine, colorScheme, patterns = codeView.y, codeView.fromLine + codeView.height - 1, codeView.syntaxColorScheme, codeView.syntaxPatterns -- Line numbers bar and code area - codeView.lineNumbersWidth = unicode.len(tostring(toLine)) + 2 + codeView.lineNumbersWidth = unicode.wlen(tostring(toLine)) + 2 codeView.codeAreaPosition = codeView.x + codeView.lineNumbersWidth codeView.codeAreaWidth = codeView.width - codeView.lineNumbersWidth @@ -1033,7 +1033,7 @@ local function codeViewDraw(codeView) screen.drawRectangle(codeView.codeAreaPosition, y, codeView.codeAreaWidth, 1, codeView.highlights[line], colorScheme.text, " ") end - screen.drawText(codeView.codeAreaPosition - unicode.len(text) - 1, y, colorScheme.lineNumbersText, text) + screen.drawText(codeView.codeAreaPosition - unicode.wlen(text) - 1, y, colorScheme.lineNumbersText, text) y = y + 1 else @@ -1295,21 +1295,21 @@ local function drawChart(object) for y = object.y + object.height - 3, object.y + 1, -chartHeight * object.yAxisValueInterval do local stringValue = getAxisValue(value, object.yAxisPostfix, object.roundValues) - yAxisValueMaxWidth = math.max(yAxisValueMaxWidth, unicode.len(stringValue)) + yAxisValueMaxWidth = math.max(yAxisValueMaxWidth, unicode.wlen(stringValue)) table.insert(yAxisValues, {y = math.ceil(y), value = stringValue}) value = value + dy * object.yAxisValueInterval end local stringValue = getAxisValue(yMax, object.yAxisPostfix, object.roundValues) table.insert(yAxisValues, {y = object.y, value = stringValue}) - yAxisValueMaxWidth = math.max(yAxisValueMaxWidth, unicode.len(stringValue)) + yAxisValueMaxWidth = math.max(yAxisValueMaxWidth, unicode.wlen(stringValue)) local chartWidth = object.width - (object.showYAxisValues and yAxisValueMaxWidth + 2 or 0) local chartX = object.x + object.width - chartWidth for i = 1, #yAxisValues do if object.showYAxisValues then - screen.drawText(chartX - unicode.len(yAxisValues[i].value) - 2, yAxisValues[i].y, object.colors.axisValue, yAxisValues[i].value) + screen.drawText(chartX - unicode.wlen(yAxisValues[i].value) - 2, yAxisValues[i].y, object.colors.axisValue, yAxisValues[i].value) end screen.drawText(chartX, yAxisValues[i].y, object.colors.helpers, string.rep("─", chartWidth)) end @@ -1319,11 +1319,11 @@ local function drawChart(object) value = xMin for x = chartX, chartX + chartWidth - 2, chartWidth * object.xAxisValueInterval do local stringValue = getAxisValue(value, object.xAxisPostfix, object.roundValues) - screen.drawText(math.floor(x - unicode.len(stringValue) / 2), object.y + object.height - 1, object.colors.axisValue, stringValue) + screen.drawText(math.floor(x - unicode.wlen(stringValue) / 2), object.y + object.height - 1, object.colors.axisValue, stringValue) value = value + dx * object.xAxisValueInterval end local value = getAxisValue(xMax, object.xAxisPostfix, object.roundValues) - screen.drawText(object.x + object.width - unicode.len(value), object.y + object.height - 1, object.colors.axisValue, value) + screen.drawText(object.x + object.width - unicode.wlen(value), object.y + object.height - 1, object.colors.axisValue, value) end -- Axis lines @@ -1418,13 +1418,13 @@ local function sliderDraw(object) if object.showMaximumAndMinimumValues then local stringMaximumValue, stringMinimumValue = tostring(object.roundValues and math.floor(object.maximumValue) or number.roundToDecimalPlaces(object.maximumValue, 2)), tostring(object.roundValues and math.floor(object.minimumValue) or number.roundToDecimalPlaces(object.minimumValue, 2)) - screen.drawText(object.x - unicode.len(stringMinimumValue) - 1, object.y, object.colors.value, stringMinimumValue) + screen.drawText(object.x - unicode.wlen(stringMinimumValue) - 1, object.y, object.colors.value, stringMinimumValue) screen.drawText(object.x + object.width + 1, object.y, object.colors.value, stringMaximumValue) end if object.currentValuePrefix or object.currentValuePostfix then local stringCurrentValue = (object.currentValuePrefix or "") .. (object.roundValues and math.floor(object.value) or number.roundToDecimalPlaces(object.value, 2)) .. (object.currentValuePostfix or "") - screen.drawText(math.floor(object.x + object.width / 2 - unicode.len(stringCurrentValue) / 2), object.y + 1, object.colors.value, stringCurrentValue) + screen.drawText(math.floor(object.x + object.width / 2 - unicode.wlen(stringCurrentValue) / 2), object.y + 1, object.colors.value, stringCurrentValue) end local activeWidth = number.round((object.value - object.minimumValue) / (object.maximumValue - object.minimumValue) * object.width) @@ -2029,7 +2029,7 @@ end local function filesystemDialogAddExtensionFilter(filesystemDialog, extension) filesystemDialog.extensionComboBox:addItem(extension) - filesystemDialog.extensionComboBox.width = math.max(filesystemDialog.extensionComboBox.width, unicode.len(extension) + 3) + filesystemDialog.extensionComboBox.width = math.max(filesystemDialog.extensionComboBox.width, unicode.wlen(extension) + 3) filesystemDialog.extensionComboBox.localX = filesystemDialog.cancelButton.localX - filesystemDialog.extensionComboBox.width - 2 filesystemDialog.filesystemTree:addExtensionFilter(extension) @@ -2704,7 +2704,7 @@ local function textBoxDraw(object) 1, object.horizontalAlignment, object.verticalAlignment, - unicode.len(line), + unicode.wlen(line), 1 ) @@ -3611,7 +3611,7 @@ end -------------------------------------------------------------------------------- local function textUpdate(object) - object.width = unicode.len(object.text) + object.width = unicode.wlen(object.text) return object end @@ -3684,7 +3684,7 @@ local function listUpdate(list) -- Размеры хуйни if list.cells[1][1].direction == GUI.DIRECTION_HORIZONTAL then if list.offsetMode then - child.width, child.height = list.itemSize * 2 + unicode.len(child.text), list.height + child.width, child.height = list.itemSize * 2 + unicode.wlen(child.text), list.height else child.width, child.height = list.itemSize, list.height end @@ -3819,7 +3819,7 @@ end --------------------------------------------------------------------------------------------------- local function keyAndValueUpdate(object) - object.keyLength, object.valueLength = unicode.len(object.key), unicode.len(object.value) + object.keyLength, object.valueLength = unicode.wlen(object.key), unicode.wlen(object.value) object.width = object.keyLength + object.valueLength end @@ -3931,8 +3931,9 @@ local function dropDownMenuItemDraw(item) end screen.drawText(item.x + 1, yText, textColor, item.text) + if item.shortcut then - screen.drawText(item.x + item.width - unicode.len(item.shortcut) - 1, yText, textColor, item.shortcut) + screen.drawText(item.x + item.width - unicode.wlen(item.shortcut) - 1, yText, textColor, item.shortcut) end else screen.drawText(item.x, yText, item.parent.parent.colors.separator, string.rep("─", item.width)) @@ -4182,9 +4183,10 @@ local function contextMenuUpdate(menu) local widestItem, widestShortcut = 0, 0 for i = 1, #menu.itemsContainer.children do if menu.itemsContainer.children[i].type == 1 then - widestItem = math.max(widestItem, unicode.len(menu.itemsContainer.children[i].text)) + widestItem = math.max(widestItem, unicode.wlen(menu.itemsContainer.children[i].text)) + if menu.itemsContainer.children[i].shortcut then - widestShortcut = math.max(widestShortcut, unicode.len(menu.itemsContainer.children[i].shortcut)) + widestShortcut = math.max(widestShortcut, unicode.wlen(menu.itemsContainer.children[i].shortcut)) end end end @@ -4596,7 +4598,7 @@ local function menuDraw(menu) end local function menuAddItem(menu, text, textColor) - local item = menu:addChild(pressable(1, 1, unicode.len(text) + 2, 1, nil, textColor or menu.colors.default.text, menu.colors.selected.background, menu.colors.selected.text, 0x0, 0x0, text)) + local item = menu:addChild(pressable(1, 1, unicode.wlen(text) + 2, 1, nil, textColor or menu.colors.default.text, menu.colors.selected.background, menu.colors.selected.text, 0x0, 0x0, text)) item.eventHandler = pressableEventHandler return item diff --git a/Libraries/Screen.lua b/Libraries/Screen.lua index ca0af90a..23fa77ba 100755 --- a/Libraries/Screen.lua +++ b/Libraries/Screen.lua @@ -22,16 +22,18 @@ local unicodeLen, unicodeSub, + unicodeWlen, + unicodeWlenCache, bufferWidth, bufferHeight, currentFrameBackgrounds, currentFrameForegrounds, - currentFrameSymbols, + currentFrameChars, newFrameBackgrounds, newFrameForegrounds, - newFrameSymbols, + newFrameChars, drawLimitX1, drawLimitX2, @@ -56,7 +58,9 @@ local color.integerToRGB, unicode.len, - unicode.sub; + unicode.sub, + unicode.wlen, + {}; -------------------------------------------------------------------------------- @@ -65,11 +69,11 @@ local function getIndex(x, y) end local function getCurrentFrameTables() - return currentFrameBackgrounds, currentFrameForegrounds, currentFrameSymbols + return currentFrameBackgrounds, currentFrameForegrounds, currentFrameChars end local function getNewFrameTables() - return newFrameBackgrounds, newFrameForegrounds, newFrameSymbols + return newFrameBackgrounds, newFrameForegrounds, newFrameChars end -------------------------------------------------------------------------------- @@ -93,7 +97,7 @@ local function flush(width, height) width, height = componentInvoke(GPUAddress, "getResolution") end - currentFrameBackgrounds, currentFrameForegrounds, currentFrameSymbols, newFrameBackgrounds, newFrameForegrounds, newFrameSymbols = {}, {}, {}, {}, {}, {} + currentFrameBackgrounds, currentFrameForegrounds, currentFrameChars, newFrameBackgrounds, newFrameForegrounds, newFrameChars = {}, {}, {}, {}, {}, {} bufferWidth = width bufferHeight = height @@ -106,8 +110,8 @@ local function flush(width, height) currentFrameForegrounds[i] = 0xFEFEFE newFrameForegrounds[i] = 0xFEFEFE - currentFrameSymbols[i] = " " - newFrameSymbols[i] = " " + currentFrameChars[i] = " " + newFrameChars[i] = " " end end @@ -199,31 +203,62 @@ end -------------------------------------------------------------------------------- -local function rawSet(index, background, foreground, symbol) - newFrameBackgrounds[index], newFrameForegrounds[index], newFrameSymbols[index] = background, foreground, symbol +local function rawSet(index, background, foreground, char) + newFrameBackgrounds[index], newFrameForegrounds[index], newFrameChars[index] = background, foreground, char end local function rawGet(index) - return newFrameBackgrounds[index], newFrameForegrounds[index], newFrameSymbols[index] + return newFrameBackgrounds[index], newFrameForegrounds[index], newFrameChars[index] end local function get(x, y) if x >= 1 and y >= 1 and x <= bufferWidth and y <= bufferHeight then local index = bufferWidth * (y - 1) + x - return newFrameBackgrounds[index], newFrameForegrounds[index], newFrameSymbols[index] + + return newFrameBackgrounds[index], newFrameForegrounds[index], newFrameChars[index] else return 0x000000, 0x000000, " " end end -local function set(x, y, background, foreground, symbol) - if x >= drawLimitX1 and y >= drawLimitY1 and x <= drawLimitX2 and y <= drawLimitY2 then - local index = bufferWidth * (y - 1) + x - newFrameBackgrounds[index], newFrameForegrounds[index], newFrameSymbols[index] = background, foreground, symbol +local function set(x, y, background, foreground, char) + if x < drawLimitX1 or y < drawLimitY1 or x > drawLimitX2 or y > drawLimitY2 then + return + end + + local + index, + charWlen = + bufferWidth * (y - 1) + x, + unicodeWlenCache[char] + + if not charWlen then + charWlen = unicodeWlen(char) + unicodeWlenCache[char] = charWlen + end + + newFrameBackgrounds[index], + newFrameForegrounds[index], + newFrameChars[index] = + background, + foreground, + char + + index = index + 1 + + for i = 2, charWlen do + newFrameBackgrounds[index], + newFrameForegrounds[index], + newFrameChars[index] = + background, + foreground, + " " + + index = index + 1 end end -local function drawRectangle(x, y, width, height, background, foreground, symbol, transparency) +local function drawRectangle(x, y, width, height, background, foreground, char, transparency) local temp -- Clipping left @@ -272,7 +307,7 @@ local function drawRectangle(x, y, width, height, background, foreground, symbol for i = 1, width do newFrameBackgrounds[temp], newFrameForegrounds[temp], - newFrameSymbols[temp] = background, foreground, symbol + newFrameChars[temp] = background, foreground, char temp = temp + 1 end @@ -361,7 +396,7 @@ local function blur(x, y, width, height, radius, color, transparency) newFrameBackgrounds[screenIndex] = colorRGBToInteger(r, g, b) newFrameForegrounds[screenIndex] = 0x0 - newFrameSymbols[screenIndex] = " " + newFrameChars[screenIndex] = " " screenIndex = screenIndex + 1 end @@ -383,7 +418,7 @@ local function copy(x, y, width, height) index = bufferWidth * (j - 1) + i tableInsert(copyArray, newFrameBackgrounds[index]) tableInsert(copyArray, newFrameForegrounds[index]) - tableInsert(copyArray, newFrameSymbols[index]) + tableInsert(copyArray, newFrameChars[index]) else tableInsert(copyArray, 0x0) tableInsert(copyArray, 0x0) @@ -405,7 +440,7 @@ local function paste(startX, startY, picture) if x >= drawLimitX1 and x <= drawLimitX2 then newFrameBackgrounds[screenIndex] = picture[pictureIndex] newFrameForegrounds[screenIndex] = picture[pictureIndex + 1] - newFrameSymbols[screenIndex] = picture[pictureIndex + 2] + newFrameChars[screenIndex] = picture[pictureIndex + 2] end screenIndex, pictureIndex = screenIndex + 1, pictureIndex + 3 @@ -517,37 +552,56 @@ local function rasterizePolygon(centerX, centerY, startX, startY, countOfEdges, end end -local function drawLine(x1, y1, x2, y2, background, foreground, symbol) +local function drawLine(x1, y1, x2, y2, background, foreground, char) rasterizeLine(x1, y1, x2, y2, function(x, y) - set(x, y, background, foreground, symbol) + set(x, y, background, foreground, char) end) end -local function drawEllipse(centerX, centerY, radiusX, radiusY, background, foreground, symbol) +local function drawEllipse(centerX, centerY, radiusX, radiusY, background, foreground, char) rasterizeEllipse(centerX, centerY, radiusX, radiusY, function(x, y) - set(x, y, background, foreground, symbol) + set(x, y, background, foreground, char) end) end -local function drawPolygon(centerX, centerY, radiusX, radiusY, background, foreground, countOfEdges, symbol) +local function drawPolygon(centerX, centerY, radiusX, radiusY, background, foreground, countOfEdges, char) rasterizePolygon(centerX, centerY, radiusX, radiusY, countOfEdges, function(x, y) - set(x, y, background, foreground, symbol) + set(x, y, background, foreground, char) end) end -local function drawText(x, y, textColor, data, transparency) - if y >= drawLimitY1 and y <= drawLimitY2 then - local charIndex, screenIndex = 1, bufferWidth * (y - 1) + x - - for charIndex = 1, unicodeLen(data) do - if x >= drawLimitX1 and x <= drawLimitX2 then +local function drawText(x, y, textColor, text, transparency) + if y < drawLimitY1 or y > drawLimitY2 then + return + end + + local + charIndex, + screenIndex, + + char, + charWlen = + 1, + bufferWidth * (y - 1) + x + + for charIndex = 1, unicodeLen(text) do + char = unicodeSub(text, charIndex, charIndex) + charWlen = unicodeWlenCache[char] + + if not charWlen then + charWlen = unicodeWlen(char) + unicodeWlenCache[char] = charWlen + end + + for i = 1, charWlen do + if x >= drawLimitX1 and x + charWlen - 1 <= drawLimitX2 then if transparency then newFrameForegrounds[screenIndex] = colorBlend(newFrameBackgrounds[screenIndex], textColor, transparency) else newFrameForegrounds[screenIndex] = textColor end - newFrameSymbols[screenIndex] = unicodeSub(data, charIndex, charIndex) + newFrameChars[screenIndex] = i == 1 and char or " " end x, screenIndex = x + 1, screenIndex + 1 @@ -592,11 +646,11 @@ local function drawImage(x, y, picture, blendForeground) background, foreground, alpha, - symbol = bufferWidth * (y - 1) + x, bufferWidth - clippedImageWidth, (imageWidth - clippedImageWidth) * 4 + char = bufferWidth * (y - 1) + x, bufferWidth - clippedImageWidth, (imageWidth - clippedImageWidth) * 4 for j = 1, clippedImageHeight do for i = 1, clippedImageWidth do - alpha, symbol = picture[pictureIndex + 2], picture[pictureIndex + 3] + alpha, char = picture[pictureIndex + 2], picture[pictureIndex + 3] -- If it's fully transparent pixel if alpha == 0 then @@ -611,11 +665,11 @@ local function drawImage(x, y, picture, blendForeground) newFrameForegrounds[screenIndex] = picture[pictureIndex + 1] end -- If it's not transparent with whitespace - elseif symbol ~= " " then + elseif char ~= " " then newFrameForegrounds[screenIndex] = picture[pictureIndex + 1] end - newFrameSymbols[screenIndex] = symbol + newFrameChars[screenIndex] = char screenIndex, pictureIndex = screenIndex + 1, pictureIndex + 4 end @@ -640,35 +694,35 @@ end local function semiPixelRawSet(index, color, yPercentTwoEqualsZero) local upperPixel, lowerPixel, bothPixel = "▀", "▄", " " - local background, foreground, symbol = newFrameBackgrounds[index], newFrameForegrounds[index], newFrameSymbols[index] + local background, foreground, char = newFrameBackgrounds[index], newFrameForegrounds[index], newFrameChars[index] if yPercentTwoEqualsZero then - if symbol == upperPixel then + if char == upperPixel then if color == foreground then - newFrameBackgrounds[index], newFrameForegrounds[index], newFrameSymbols[index] = color, foreground, bothPixel + newFrameBackgrounds[index], newFrameForegrounds[index], newFrameChars[index] = color, foreground, bothPixel else - newFrameBackgrounds[index], newFrameForegrounds[index], newFrameSymbols[index] = color, foreground, symbol + newFrameBackgrounds[index], newFrameForegrounds[index], newFrameChars[index] = color, foreground, char end - elseif symbol == bothPixel then + elseif char == bothPixel then if color ~= background then - newFrameBackgrounds[index], newFrameForegrounds[index], newFrameSymbols[index] = background, color, lowerPixel + newFrameBackgrounds[index], newFrameForegrounds[index], newFrameChars[index] = background, color, lowerPixel end else - newFrameBackgrounds[index], newFrameForegrounds[index], newFrameSymbols[index] = background, color, lowerPixel + newFrameBackgrounds[index], newFrameForegrounds[index], newFrameChars[index] = background, color, lowerPixel end else - if symbol == lowerPixel then + if char == lowerPixel then if color == foreground then - newFrameBackgrounds[index], newFrameForegrounds[index], newFrameSymbols[index] = color, foreground, bothPixel + newFrameBackgrounds[index], newFrameForegrounds[index], newFrameChars[index] = color, foreground, bothPixel else - newFrameBackgrounds[index], newFrameForegrounds[index], newFrameSymbols[index] = color, foreground, symbol + newFrameBackgrounds[index], newFrameForegrounds[index], newFrameChars[index] = color, foreground, char end - elseif symbol == bothPixel then + elseif char == bothPixel then if color ~= background then - newFrameBackgrounds[index], newFrameForegrounds[index], newFrameSymbols[index] = background, color, upperPixel + newFrameBackgrounds[index], newFrameForegrounds[index], newFrameChars[index] = background, color, upperPixel end else - newFrameBackgrounds[index], newFrameForegrounds[index], newFrameSymbols[index] = background, color, upperPixel + newFrameBackgrounds[index], newFrameForegrounds[index], newFrameChars[index] = background, color, upperPixel end end end @@ -765,51 +819,168 @@ end -------------------------------------------------------------------------------- local function update(force) - local index, indexStepOnEveryLine, changes = bufferWidth * (drawLimitY1 - 1) + drawLimitX1, (bufferWidth - drawLimitX2 + drawLimitX1 - 1), {} - local x, equalChars, equalCharsIndex, charX, charIndex, currentForeground - local currentFrameBackground, currentFrameForeground, currentFrameSymbol, changesCurrentFrameBackground, changesCurrentFrameBackgroundCurrentFrameForeground - local changesCurrentFrameBackgroundCurrentFrameForegroundIndex + local + index, + indexStepOnEveryLine, + changes, + + x, + + charX, + charIndex, + charWlen, + + equalChars, + equalCharsIndex, + + currentFrameBackground, + currentFrameForeground, + currentFrameChar, + newFrameChar, + newFrameForeground, + newFrameBackground, + + changesCurrentFrameBackground, + changesCurrentFrameBackgroundCurrentFrameForeground, + changesCurrentFrameBackgroundCurrentFrameForegroundIndex, + + currentForeground = + bufferWidth * (drawLimitY1 - 1) + drawLimitX1, + (bufferWidth - drawLimitX2 + drawLimitX1 - 1), + {} for y = drawLimitY1, drawLimitY2 do x = drawLimitX1 while x <= drawLimitX2 do -- Determine if some pixel data was changed (or if argument was passed) + currentFrameBackground, + currentFrameForeground, + currentFrameChar = + currentFrameBackgrounds[index], + currentFrameForegrounds[index], + currentFrameChars[index] + + newFrameBackground, + newFrameForeground, + newFrameChar = + newFrameBackgrounds[index], + newFrameForegrounds[index], + newFrameChars[index] + if - currentFrameBackgrounds[index] ~= newFrameBackgrounds[index] or - currentFrameForegrounds[index] ~= newFrameForegrounds[index] or - currentFrameSymbols[index] ~= newFrameSymbols[index] or + currentFrameBackground ~= newFrameBackground or + currentFrameForeground ~= newFrameForeground or + currentFrameChar ~= newFrameChar or force then -- Make pixel at both frames equal - currentFrameBackground, currentFrameForeground, currentFrameSymbol = newFrameBackgrounds[index], newFrameForegrounds[index], newFrameSymbols[index] - currentFrameBackgrounds[index] = currentFrameBackground - currentFrameForegrounds[index] = currentFrameForeground - currentFrameSymbols[index] = currentFrameSymbol + currentFrameBackgrounds[index], + currentFrameForegrounds[index], + currentFrameChars[index], + + currentFrameBackground, + currentFrameForeground, + currentFrameChar = + newFrameBackground, + newFrameForeground, + newFrameChar, + + newFrameBackground, + newFrameForeground, + newFrameChar -- Look for pixels with equal chars from right of current pixel - equalChars, equalCharsIndex, charX, charIndex = {currentFrameSymbol}, 2, x + 1, index + 1 + charWlen = unicodeWlenCache[currentFrameChar] + + if not charWlen then + charWlen = unicodeWlen(currentFrameChar) + unicodeWlenCache[currentFrameChar] = charWlen + end + + charX, + charIndex, + equalChars, + equalCharsIndex = + x + 1, + index + 1, + { currentFrameChar }, + 2 + + for i = 2, charWlen do + currentFrameBackgrounds[charIndex], + currentFrameForegrounds[charIndex], + currentFrameChars[charIndex], + + charX, + charIndex = + newFrameBackground, + newFrameForeground, + " ", + + charX + 1, + charIndex + 1 + end while charX <= drawLimitX2 do + newFrameBackground, + newFrameForeground, + newFrameChar = + newFrameBackgrounds[charIndex], + newFrameForegrounds[charIndex], + newFrameChars[charIndex] + -- Pixels becomes equal only if they have same background and (whitespace char or same foreground) if - currentFrameBackground == newFrameBackgrounds[charIndex] and - ( - newFrameSymbols[charIndex] == " " or - currentFrameForeground == newFrameForegrounds[charIndex] + newFrameBackground == currentFrameBackground + and ( + newFrameForeground == currentFrameForeground + or newFrameChar == " " ) then - -- Make pixel at both frames equal - currentFrameBackgrounds[charIndex] = newFrameBackgrounds[charIndex] - currentFrameForegrounds[charIndex] = newFrameForegrounds[charIndex] - currentFrameSymbols[charIndex] = newFrameSymbols[charIndex] + charWlen = unicodeWlenCache[newFrameChar] + + if not charWlen then + charWlen = unicodeWlen(newFrameChar) + unicodeWlenCache[newFrameChar] = charWlen + end - equalChars[equalCharsIndex], equalCharsIndex = currentFrameSymbols[charIndex], equalCharsIndex + 1 + currentFrameBackgrounds[charIndex], + currentFrameForegrounds[charIndex], + currentFrameChars[charIndex], + + charX, + charIndex, + + equalChars[equalCharsIndex], + equalCharsIndex = + newFrameBackground, + newFrameForeground, + newFrameChar, + + charX + 1, + charIndex + 1, + + newFrameChar, + equalCharsIndex + 1 + + for i = 2, charWlen do + currentFrameBackgrounds[charIndex], + currentFrameForegrounds[charIndex], + currentFrameChars[charIndex], + + charX, + charIndex = + newFrameBackground, + newFrameForeground, + " ", + + charX + 1, + charIndex + 1 + end else break end - - charX, charIndex = charX + 1, charIndex + 1 end -- Group pixels that need to be drawn by background and foreground