Posted 18 February 2013 - 06:02 PM
In an attempt to implement a method of recording the screen in frames for easy video playing, rewinding, etc. I built an API which does exactly that.
However, the generated file size is much too large for saving entire recordings this way. Unfortunately, I don't think that I can adapt this API to make the file size smaller and therefore better for recordings.
A practical use for this API that I thought of would be taking screenshots of your terminal. That's exactly what you can do with this API. For any developer who might have a use for this API: a neat feature (actually the whole point of the design) is that it records each point on the screen in following format: character, background color, and text color. So with that said, you can use this API to see what is written to the screen.
Here are the functions that come with this API:
frameEnvironment.getCurrentFrame() - Returns the current frame (whatever is currently in the screen buffer) and the current system time (os.clock()).
frameEnvironment.drawFrame (frame) - Draws the given frame object. No return value (besides nil :P/>)
Global variables:
_G.frameEnvironment - This is where all of the frame related functions and data are stored globally.
_G.frameEnvironment.screenBuffer - This is what is actually recording all of the "cells" on the screen at tables with the indexes of their coordinates on the screen: screenBuffer[y][x] = {text, backgroundColor, textColor}
_G.frameEnvironment.screenBuffer.cursorBlink - The current state of the cursor blinking.
_G.frameEnvironment.screenBuffer.backgroundColor - The current background color of the terminal.
_G.frameEnvironment.screenBuffer.textColor - The current text color of the terminal.
Here's the code:
Pastebin: http://pastebin.com/uCsPTDdi
You have permission to use this in any way that you'd like, but please give credit where it is due. (it would also be nice if you let me know just so I could feel all warm and fuzzy inside ;)/>)
However, the generated file size is much too large for saving entire recordings this way. Unfortunately, I don't think that I can adapt this API to make the file size smaller and therefore better for recordings.
A practical use for this API that I thought of would be taking screenshots of your terminal. That's exactly what you can do with this API. For any developer who might have a use for this API: a neat feature (actually the whole point of the design) is that it records each point on the screen in following format: character, background color, and text color. So with that said, you can use this API to see what is written to the screen.
Here are the functions that come with this API:
Spoiler
initFrameEnvironment() - Inititalizes the _G.frameEnvironment table.frameEnvironment.getCurrentFrame() - Returns the current frame (whatever is currently in the screen buffer) and the current system time (os.clock()).
frameEnvironment.drawFrame (frame) - Draws the given frame object. No return value (besides nil :P/>)
Global variables:
_G.frameEnvironment - This is where all of the frame related functions and data are stored globally.
_G.frameEnvironment.screenBuffer - This is what is actually recording all of the "cells" on the screen at tables with the indexes of their coordinates on the screen: screenBuffer[y][x] = {text, backgroundColor, textColor}
_G.frameEnvironment.screenBuffer.cursorBlink - The current state of the cursor blinking.
_G.frameEnvironment.screenBuffer.backgroundColor - The current background color of the terminal.
_G.frameEnvironment.screenBuffer.textColor - The current text color of the terminal.
Here's the code:
Pastebin: http://pastebin.com/uCsPTDdi
Spoiler
--[[
Frames Trystan Cannon
12 February 2013
This is a redesign of an API
which I had written and didn't
function properly because of the
faulty design.
This API implements a method of recording
the screen in frames. However, saving
an entire recording isn't practical because
of how large the file size would be.
A decent use for this API is to take
screenshots in game.
]]--
-- Returns the true size of a table using pairs().
local function getTableSize (myTable)
local size = 0
for _, __ in pairs (myTable) do
size = size + 1
end
return size
end
-- Hooks the given screen buffer to the current terminal API.
function hookTerminal (screenBuffer)
local hookedTerminal = {}
for index, item in pairs (term.native) do
hookedTerminal[index] = item
end
-- TODO: Implement this function!
hookedTerminal["scroll"] = function (linesToScroll)
local lines = {}
for line = linesToScroll + 1, screenBuffer.screenHeight do
lines[#lines + 1] = screenBuffer[line]
end
-- Fill in any remaining lines with empty space.
for line = (getTableSize (lines) == 1 and getTableSize (lines) or 1), screenBuffer.screenHeight do
lines[#lines + 1] = {}
for xPos = 1, screenBuffer.screenWidth do
lines[#lines][xPos] = {text = ' ', backgroundColor = colors.black, textColor = colors.white}
end
end
-- Insert the lines table as the current screen buffer lines.
for line = 1, screenBuffer.screenHeight do
screenBuffer[line] = lines[line]
end
return term.native.scroll (linesToScroll)
end
hookedTerminal["clearLine"] = function()
local _, line = term.native.getCursorPos()
-- Clear the line by replacing every cell in it with spaces.
for xPos = 1, screenBuffer.screenWidth do
screenBuffer[line][xPos] = {text = ' ', backgroundColor = screenBuffer.backgroundColor, textColor = screenBuffer.textColor}
end
return term.native.clearLine()
end
hookedTerminal["clear"] = function()
-- Clear the screen buffer by, instead of dumping it, replace every line with spaces.
for line = 1, screenBuffer.screenHeight do
for xPos = 1, screenBuffer.screenWidth do
screenBuffer[line][xPos] = {text = ' ', backgroundColor = screenBuffer.backgroundColor, textColor = screenBuffer.textColor}
end
end
return term.native.clear()
end
hookedTerminal["setTextColor"] = function (textColor)
screenBuffer.textColor = textColor
return term.native.setTextColor (textColor)
end
hookedTerminal["setBackgroundColor"] = function (backgroundColor)
screenBuffer.backgroundColor = backgroundColor
return term.native.setBackgroundColor (backgroundColor)
end
hookedTerminal["setCursorBlink"] = function (cursorBlink)
screenBuffer.cursorBlink = cursorBlink
return term.native.setCursorBlink (cursorBlink)
end
hookedTerminal["write"] = function (text)
local currentX, currentY = term.native.getCursorPos()
local currentX_offset = currentX
local backgroundColor = screenBuffer.backgroundColor
local textColor = screenBuffer.textColor
local subOffset = 1
while currentX < currentX_offset + text:len() do
screenBuffer[currentY][currentX] = {text = text:sub (subOffset, subOffset), backgroundColor = backgroundColor, textColor = textColor}
subOffset = subOffset + 1
currentX = currentX + 1
end
return term.native.write (text)
end
term.redirect (hookedTerminal)
end
-- Initializes the frame environment.
function initFrameEnvironment()
local screenWidth, screenHeight = term.getSize()
_G.frameEnvironment = {}
_G.frameEnvironment.screenBuffer = {
cursorBlink = true,
backgroundColor = colors.black,
textColor = colors.white,
screenWidth = screenWidth,
screenHeight = screenHeight
}
-- Initialize the screen buffer by adding all of the cell tables.
for line = 1, _G.frameEnvironment.screenBuffer.screenHeight do
_G.frameEnvironment.screenBuffer[line] = {}
for xPos = 1, _G.frameEnvironment.screenBuffer.screenWidth do
_G.frameEnvironment.screenBuffer[line][xPos] = {text = ' ', backgroundColor = _G.frameEnvironment.screenBuffer.backgroundColor, textColor = _G.frameEnvironment.screenBuffer.textColor}
end
end
-- Returns a copy of the screen buffer and the current os.clock() time. This is a frame.
-- NOTE: A frame object always has a 'cursorBlink' field too!
_G.frameEnvironment.getCurrentFrame = function()
local currentX, currentY = term.native.getCursorPos()
local currentFrame = {
cursorBlink = _G.frameEnvironment.screenBuffer.cursorBlink,
cursorPos = {x = currentX, y = currentY}
}
for line = 1, _G.frameEnvironment.screenBuffer.screenHeight do
currentFrame[line] = {}
for xPos = 1, _G.frameEnvironment.screenBuffer.screenWidth do
currentFrame[line][xPos] = {}
for index, item in pairs (_G.frameEnvironment.screenBuffer[line][xPos]) do
currentFrame[line][xPos][index] = item
end
end
end
return currentFrame, os.clock()
end
-- Draws the given frame.
-- NOTE: This function does not return the cursor position, blink, or screen colors to their original state!
_G.frameEnvironment.drawFrame = function (frame)
term.native.setCursorBlink (false)
for line = 1, _G.frameEnvironment.screenBuffer.screenHeight do
for xPos = 1, _G.frameEnvironment.screenBuffer.screenWidth do
local cell = frame[line][xPos]
if getTableSize (cell) > 0 then
term.native.setCursorPos (xPos, line)
term.native.setBackgroundColor (cell.backgroundColor)
term.native.setTextColor (cell.textColor)
term.write (cell.text)
end
end
end
term.native.setCursorBlink (frame.cursorBlink)
term.native.setCursorPos (frame.cursorPos.x, frame.cursorPos.y)
end
-- Ensure that the terminal API is writing to the screen buffer by hooking the screen buffer to the terminal API.
hookTerminal (_G.frameEnvironment.screenBuffer)
end
You have permission to use this in any way that you'd like, but please give credit where it is due. (it would also be nice if you let me know just so I could feel all warm and fuzzy inside ;)/>)