v0.10.0 - Added text editor (which took me way too long) and too many other tweaks to name.

This commit is contained in:
TheWahlolly
2025-05-04 15:16:54 +03:00
parent 6b8bee249a
commit 673a0b4a75
19 changed files with 997 additions and 384 deletions
+1 -1
View File
@@ -24,6 +24,6 @@ else
if fs.exists(directory) and fs.isDirectory(directory) or fs.exists(shell.workingDirectory .. directory) and fs.isDirectory(shell.workingDirectory .. directory) then if fs.exists(directory) and fs.isDirectory(directory) or fs.exists(shell.workingDirectory .. directory) and fs.isDirectory(shell.workingDirectory .. directory) then
shell.workingDirectory = directory shell.workingDirectory = directory
else else
print("error: no such directory") print("\27[91mNo such directory.")
end end
end end
+321
View File
@@ -0,0 +1,321 @@
local args = {...}
local file = args[1]
args = nil
local fs = import("filesystem")
local event = import("event")
local gpu = component.proxy(component.list("gpu")())
local width, height = gpu.getResolution()
local scrollPosX, scrollPosY = 1, 1
local cursorPosX, cursorPosY = 1, 1
local cursorWhite = true
local changesMade = false
local renderBuffer = gpu.allocateBuffer()
local scrollSpeed = 5
--local ocelot = component.proxy(component.list("ocelot")())
local function rawset(x, y, text)
termlib.cursorPosX = x
termlib.cursorPosY = y
print(text, false, false)
end
local filestring, filepath, handle, data, tmpdata
if file then
if file:sub(1, 1) == "/" then
filepath = file
else
filepath = shell.workingDirectory .. file
end
handle, data, tmpdata = fs.open(filepath, "r"), "", nil
if fs.exists(filepath) then
filestring = filepath
repeat
tmpdata = handle:read(math.huge)
data = data .. (tmpdata or "")
until not tmpdata
tmpdata = {}
if data:gmatch("(.-)\n")() then
for line in data:gmatch("(.-)\n") do
local newLine = line:gsub("\r", "") -- this took me SO LONG TO FIGURE OUT AAAAAAAA I HATE CRLF I HATE CRLF I HATE CRLF
table.insert(tmpdata, newLine)
end
else
tmpdata = {data}
end
else
filepath = shell.workingDirectory .. file
filestring = "[NEW FILE]"
tmpdata = {""}
end
else
filepath = ""
filestring = "[NEW FILE]"
tmpdata = {""}
end
local function render()
gpu.setActiveBuffer(renderBuffer)
clear()
local realCursorX = math.min(cursorPosX, unicode.wlen(tmpdata[cursorPosY]) - scrollPosX + 2)
if realCursorX < 1 then
scrollPosX = scrollPosX + realCursorX - 1
cursorPosX = 1
realCursorX = math.min(cursorPosX, unicode.wlen(tmpdata[cursorPosY]) - scrollPosX + 2)
end
for i = scrollPosY, height + scrollPosY - 3 do
rawset(1, i - scrollPosY + 1, (tmpdata[i] or ""):sub(scrollPosX))
end
rawset(1, height - 1, "\27[107m\27[30m" .. filestring .. string.rep(" ", width))
rawset(1, height, "\27[107m\27[30m^X\27[0m Exit \27[107m\27[30m^S\27[0m Save" .. string.rep(" ", width))
local char = gpu.get(realCursorX, cursorPosY)
if cursorWhite then
rawset(realCursorX, cursorPosY, "\27[107m\27[30m" .. char .. "\27[0m")
else
rawset(realCursorX, cursorPosY, char)
end
gpu.bitblt()
gpu.setActiveBuffer(0)
end
local renderFlag, cursorRenderFlag = false, false
local function scrollUp()
cursorPosY = cursorPosY - 1
cursorRenderFlag = true
cursorWhite = true
if cursorPosY < 1 then
renderFlag = true
scrollPosY = scrollPosY - 1
cursorPosY = 1
end
if scrollPosY < 1 then
renderFlag = false
scrollPosY = 1
end
if math.min(cursorPosX, unicode.wlen(tmpdata[cursorPosY]) - scrollPosX + 2) < 1 then
renderFlag = true
end
end
local function scrollDown()
cursorPosY = cursorPosY + 1
cursorRenderFlag = true
cursorWhite = true
if cursorPosY + scrollPosY - 1 > #tmpdata then
renderFlag = false
cursorPosY = #tmpdata - scrollPosY + 1
end
if cursorPosY > height - 2 then
renderFlag = true
scrollPosY = scrollPosY + 1
cursorPosY = height - 2
end
if math.min(cursorPosX, unicode.wlen(tmpdata[cursorPosY]) - scrollPosX + 2) < 1 then
renderFlag = true
end
end
local function scrollLeft()
cursorRenderFlag = true
cursorWhite = true
if cursorPosX > 1 then
if cursorPosX <= unicode.wlen(tmpdata[cursorPosY]) - scrollPosX + 2 then
cursorPosX = cursorPosX - 1
elseif unicode.wlen(tmpdata[cursorPosY]) - scrollPosX + 1 > 1 then
cursorPosX = unicode.wlen(tmpdata[cursorPosY]) - scrollPosX + 1
end
elseif scrollPosX > 1 then
scrollPosX = scrollPosX - 1
renderFlag = true
end
if math.min(cursorPosX, unicode.wlen(tmpdata[cursorPosY]) - scrollPosX + 2) < 1 then
renderFlag = true
end
end
local function scrollRight()
cursorRenderFlag = true
cursorWhite = true
if cursorPosX <= unicode.wlen(tmpdata[cursorPosY]) - scrollPosX + 1 then
cursorPosX = cursorPosX + 1
end
if cursorPosX > width then
cursorPosX = width
scrollPosX = scrollPosX + 1
renderFlag = true
end
end
local function processEvent(args)
renderFlag, cursorRenderFlag = false, false
if args[1] == "key_down" then
local keycode = args[4]
local key = keyboard.keys[keycode]
if keyboard.ctrlDown then
return false, false, key
end
if key == "down" and cursorPosY < #tmpdata then
scrollDown()
end
if key == "up" then
scrollUp()
end
if key == "left" then
scrollLeft()
end
if key == "right" then
scrollRight()
end
if key == "enter" then
changesMade = true
renderFlag = true
cursorWhite = true
table.insert(tmpdata, cursorPosY + 1, tmpdata[cursorPosY]:sub(cursorPosX))
tmpdata[cursorPosY] = tmpdata[cursorPosY]:sub(1, cursorPosX - 1)
cursorPosX = 1
cursorPosY = cursorPosY + 1
scrollPosX = 1
if cursorPosY > height - 2 then
scrollPosY = scrollPosY + 1
cursorPosY = height - 2
end
end
if key == "back" then
changesMade = true
cursorRenderFlag = true
cursorWhite = true
if cursorPosY + scrollPosY - 1 > 1 then
cursorPosY = cursorPosY - 1
if cursorPosY < 1 then
scrollPosY = scrollPosY - 1
cursorPosY = 1
end
if scrollPosY < 1 then
scrollPosY = 1
end
cursorPosX = unicode.wlen(tmpdata[cursorPosY]) - scrollPosX + 2
if cursorPosX > width then
scrollPosX = cursorPosX - width + 1
cursorPosX = width
end
tmpdata[cursorPosY] = tmpdata[cursorPosY] .. tmpdata[cursorPosY + 1]
table.remove(tmpdata, cursorPosY + 1)
renderFlag = true
else
tmpdata[cursorPosY] = tmpdata[cursorPosY]:sub(1, cursorPosX + scrollPosX - 3) .. tmpdata[cursorPosY]:sub(cursorPosX + scrollPosX - 1)
cursorPosX = math.min(cursorPosX - 1, unicode.wlen(tmpdata[cursorPosY]) + 1)
if cursorPosX < 1 then
cursorPosX = 1
scrollPosX = scrollPosX - 1
renderFlag = true
else
rawset(1, cursorPosY - scrollPosY + 1, tmpdata[cursorPosY]:sub(scrollPosX) .. " ")
end
end
end
if args[3] >= 32 and args[3] <= 126 then
changesMade = true
cursorRenderFlag = true
cursorWhite = true
tmpdata[cursorPosY] = tmpdata[cursorPosY]:sub(1, cursorPosX + scrollPosX - 2) .. unicode.char(args[3]) .. tmpdata[cursorPosY]:sub(cursorPosX + scrollPosX - 1)
cursorPosX = math.min(cursorPosX, unicode.wlen(tmpdata[cursorPosY])) + 1
--ocelot.log(tostring(cursorPosX))
if cursorPosX > width then
cursorPosX = width
scrollPosX = scrollPosX + 1
renderFlag = true
else
rawset(1, cursorPosY - scrollPosY + 1, tmpdata[cursorPosY]:sub(scrollPosX))
end
end
elseif args[1] == "scroll" then
if args[5] == 1 then
for i = 1, scrollSpeed do
scrollUp()
end
elseif args[5] == -1 and cursorPosY < #tmpdata then
for i = 1, scrollSpeed do
scrollDown()
end
end
end
return renderFlag, cursorRenderFlag
end
local function save()
rawset(1, height - 1, "\27[107m\27[30m" .. string.rep(" ", width))
termlib.cursorPosX = 1
termlib.cursorPosY = height - 1
local savepath = read(nil, "\27[107m\27[30mSave location: ", filepath)
if fs.exists(savepath) then
rawset(1, height - 1, "\27[107m\27[30m" .. string.rep(" ", width))
local answer = read(nil, "\27[107m\27[30mFile already exists. Overwrite it? [Y/n] ")
if answer:lower() == "n" then
rawset(1, height - 1, "\27[107m\27[30m" .. filestring .. string.rep(" ", width))
return
end
end
local handle, errorMessage = fs.open(savepath, "w")
if handle then
handle:write(table.concat(tmpdata, "\n"))
handle:close()
rawset(1, height - 1, "\27[107m\27[30m" .. filestring .. string.rep(" ", width))
else
rawset(1, height - 1, "\27[107m\27[30mERROR: " .. errorMessage:gsub("\n", "") .. string.rep(" ", width))
end
changesMade = false
end
render()
while true do
local args = {event.pull(0.5)}
local renderFlag, cursorRenderFlag, specialKey = false, false, nil
local previousCursorX, previousCursorY = math.min(cursorPosX, unicode.wlen(tmpdata[cursorPosY]) - scrollPosX + 2), cursorPosY
if args and args[1] then
cursorWhite = true
renderFlag, cursorRenderFlag, specialKey = processEvent(args)
if specialKey == "x" then
if changesMade then
termlib.cursorPosX = 1
termlib.cursorPosY = height - 1
local response = read(nil, "\27[107m\27[30mWould you like to save changes? [Y/n] ")
if response:lower() ~= "n" then
save()
end
end
gpu.freeAllBuffers()
clear()
return
end
if specialKey == "s" then
save()
end
repeat
args = {event.pull("key_down", 0)}
if args and args[1] then
processEvent(args)
end
until not args or not args[1]
else
cursorWhite = not cursorWhite
cursorRenderFlag = true
end
if cursorRenderFlag then
local char = gpu.get(previousCursorX, previousCursorY)
rawset(previousCursorX, previousCursorY, char)
local realCursorX = math.min(cursorPosX, unicode.wlen(tmpdata[cursorPosY]) - scrollPosX + 2)
if realCursorX < 1 then
scrollPosX = scrollPosX + realCursorX - 1
cursorPosX = 1
realCursorX = math.min(cursorPosX, unicode.wlen(tmpdata[cursorPosY]) - scrollPosX + 2)
end
local char = gpu.get(realCursorX, cursorPosY)
if cursorWhite then
rawset(realCursorX, cursorPosY, "\27[107m\27[30m" .. char .. "\27[0m")
else
rawset(realCursorX, cursorPosY, char)
end
end
if renderFlag then
render()
end
end
+12
View File
@@ -21,6 +21,18 @@ if fs.exists("/halyde/apps/helpdb/" .. command .. ".txt") then
data = data .. (tmpdata or "") data = data .. (tmpdata or "")
until not tmpdata until not tmpdata
print(data) print(data)
local aliases = table.copy(shell.aliases)
if table.find(aliases, command) then
local aliasIndex = table.find(aliases, command)
local aliasString = "Aliases:\n " .. aliasIndex
aliases[aliasIndex] = nil
while table.find(aliases, command) do
aliasIndex = table.find(aliases, command)
aliasString = aliasString .. ", " .. aliasIndex
aliases[aliasIndex] = nil
end
print(aliasString)
end
else else
print("Could not find help file for: " .. command .. ".") print("Could not find help file for: " .. command .. ".")
end end
+2 -2
View File
@@ -2,8 +2,8 @@ Usage: cp [FLAGS] [SOURCE] [DESTINATION]
Copies a file. Copies a file.
-o, --overwrite Allows any file that might be at the destination to be overwritten. -o, --overwrite Allows any file that might be at the destination to be overwritten.
SOURCE Specifies the file to be copied. SOURCE Specifies the file to be copied.
DESTINATION Specifies the path to copy the file to. DESTINATION Specifies the path to copy the file to.
Examples: Examples:
cp /home/a.txt /b.txt Copies the file at /home/a.txt to /b.txt. cp /home/a.txt /b.txt Copies the file at /home/a.txt to /b.txt.
+3
View File
@@ -13,3 +13,6 @@ All current Halyde shell commands:
You can get additional information on any app or command by running: You can get additional information on any app or command by running:
help [COMMAND] help [COMMAND]
In the help documentation, an asterisk (*) next to an argument means it is optional.
This is excluding flags, which are all optional.
+1 -1
View File
@@ -1,7 +1,7 @@
Usage: help [COMMAND] Usage: help [COMMAND]
Displays info on the command specified, or a list of commands if one is not specified. Displays info on the command specified, or a list of commands if one is not specified.
COMMAND Command to display information on. COMMAND* Command to display information on.
Examples: Examples:
help Displays a list of all default commands available. help Displays a list of all default commands available.
+1 -1
View File
@@ -2,7 +2,7 @@ Usage: ls [PATH]
Lists all files and directories in the specified path, or in the shell working directory if the path isn't specified. Lists all files and directories in the specified path, or in the shell working directory if the path isn't specified.
Directories are shown in yellow, executable files are shown in green, and other files are shown in white. Directories are shown in yellow, executable files are shown in green, and other files are shown in white.
PATH Path to the folder to list files and directories from. PATH* Path to the folder to list files and directories from.
Examples: Examples:
ls Lists all files and directories from the current shell working directory. ls Lists all files and directories from the current shell working directory.
+1 -1
View File
@@ -7,4 +7,4 @@ Removes files and directories.
Examples: Examples:
rm a.txt Removes a.txt in the current shell working directory. rm a.txt Removes a.txt in the current shell working directory.
rm -r -f /halyde/core/ Removes everything in /halyde/core forcedly and recursively. Note that trying this on a real machine will remove critical Halyde system files and cause it to stop working. rm -r -f /halyde/core/ Removes everything in /halyde/core/ forcedly and recursively.
+137
View File
@@ -0,0 +1,137 @@
local raster = import("raster")
local event = import("event")
-- Initialize the 3D renderer for a spinning cube
-- Using the raster library for drawing
-- Screen dimensions
local SCREEN_WIDTH, SCREEN_HEIGHT = component.invoke(component.list("gpu")(), "getResolution")
SCREEN_WIDTH, SCREEN_HEIGHT = SCREEN_WIDTH * 2, SCREEN_HEIGHT * 4
local CENTER_X = SCREEN_WIDTH / 2
local CENTER_Y = SCREEN_HEIGHT / 2
-- Cube properties
local CUBE_SIZE = 10
local increment = 0
local WHITE = 0xFFFFFF
local ROTATION_SPEED = 0.1
-- 3D cube vertices (centered at origin)
local vertices = {
{-CUBE_SIZE, -CUBE_SIZE, -CUBE_SIZE}, -- 0: left bottom back
{CUBE_SIZE, -CUBE_SIZE, -CUBE_SIZE}, -- 1: right bottom back
{CUBE_SIZE, CUBE_SIZE, -CUBE_SIZE}, -- 2: right top back
{-CUBE_SIZE, CUBE_SIZE, -CUBE_SIZE}, -- 3: left top back
{-CUBE_SIZE, -CUBE_SIZE, CUBE_SIZE}, -- 4: left bottom front
{CUBE_SIZE, -CUBE_SIZE, CUBE_SIZE}, -- 5: right bottom front
{CUBE_SIZE, CUBE_SIZE, CUBE_SIZE}, -- 6: right top front
{-CUBE_SIZE, CUBE_SIZE, CUBE_SIZE} -- 7: left top front
}
-- Cube edges defined by vertex indices
local edges = {
{0, 1}, {1, 2}, {2, 3}, {3, 0}, -- back face
{4, 5}, {5, 6}, {6, 7}, {7, 4}, -- front face
{0, 4}, {1, 5}, {2, 6}, {3, 7} -- connecting edges
}
-- Projection parameters
local FOV = 256 -- Field of view (distance from camera to screen)
local Z_OFFSET = 300 -- Distance from camera to cube center
-- Initialize rotation angles
local angleX, angleY, angleZ = 0, 0, 0
-- Matrix multiplication function (apply rotation to a 3D point)
local function rotatePoint(x, y, z)
-- Rotation around X axis
local cosX, sinX = math.cos(angleX), math.sin(angleX)
local y1 = y * cosX - z * sinX
local z1 = y * sinX + z * cosX
-- Rotation around Y axis
local cosY, sinY = math.cos(angleY), math.sin(angleY)
local x1 = x * cosY + z1 * sinY
local z2 = -x * sinY + z1 * cosY
-- Rotation around Z axis
local cosZ, sinZ = math.cos(angleZ), math.sin(angleZ)
local x2 = x1 * cosZ - y1 * sinZ
local y2 = x1 * sinZ + y1 * cosZ
return x2, y2, z2
end
-- Perspective projection function (3D to 2D)
local function projectPoint(x, y, z)
-- Apply perspective projection
local scale = FOV / (z + Z_OFFSET)
local x2d = x * scale + CENTER_X
local y2d = y * scale + CENTER_Y
return x2d, y2d
end
-- Render a single frame
local function renderFrame()
increment = increment + 0.05
CUBE_SIZE = (math.sin(increment) + 1) * 25
vertices = {
{-CUBE_SIZE, -CUBE_SIZE, -CUBE_SIZE}, -- 0: left bottom back
{CUBE_SIZE, -CUBE_SIZE, -CUBE_SIZE}, -- 1: right bottom back
{CUBE_SIZE, CUBE_SIZE, -CUBE_SIZE}, -- 2: right top back
{-CUBE_SIZE, CUBE_SIZE, -CUBE_SIZE}, -- 3: left top back
{-CUBE_SIZE, -CUBE_SIZE, CUBE_SIZE}, -- 4: left bottom front
{CUBE_SIZE, -CUBE_SIZE, CUBE_SIZE}, -- 5: right bottom front
{CUBE_SIZE, CUBE_SIZE, CUBE_SIZE}, -- 6: right top front
{-CUBE_SIZE, CUBE_SIZE, CUBE_SIZE} -- 7: left top front
}
-- Update rotation angles
raster.clear()
angleX = angleX + ROTATION_SPEED
angleY = angleY + ROTATION_SPEED * 0.7
angleZ = angleZ + ROTATION_SPEED * 0.5
-- Project all vertices
local projectedPoints = {}
for i, vertex in ipairs(vertices) do
-- Rotate the point
local x, y, z = rotatePoint(vertex[1], vertex[2], vertex[3])
-- Project the point to 2D
local x2d, y2d = projectPoint(x, y, z)
projectedPoints[i] = {x2d, y2d}
end
-- Draw all edges
for _, edge in ipairs(edges) do
local p1 = projectedPoints[edge[1] + 1] -- +1 because Lua indices start at 1
local p2 = projectedPoints[edge[2] + 1]
-- Draw the line
raster.drawLine(p1[1], p1[2], p2[1], p2[2], WHITE)
end
-- Render the frame
raster.update()
end
-- Main program
function main()
-- Initialize raster engine
raster.init()
-- Main loop (assume this is called repeatedly by the host environment)
while true do
renderFrame()
if event.pull("key_down", 0) then
raster.free()
break
end
end
-- Return a reference to renderFrame so it can be called for animation
return renderFrame
end
-- Start the program
return main()
+3
View File
@@ -9,8 +9,11 @@ local shellcfg = {
["rename"] = "mv", ["rename"] = "mv",
["ren"] = "mv", ["ren"] = "mv",
["dir"] = "ls", ["dir"] = "ls",
["list"] = "ls",
["man"] = "help", ["man"] = "help",
["del"] = "rm", ["del"] = "rm",
["delete"] = "rm",
["remove"] = "rm",
[".."] = "cd .." [".."] = "cd .."
}, ["defaultWorkingDirectory"] = "/home/" -- the working directory that gets set when halyde starts }, ["defaultWorkingDirectory"] = "/home/" -- the working directory that gets set when halyde starts
} }
+1 -1
View File
@@ -1,7 +1,7 @@
local loadfile = ... local loadfile = ...
local filesystem = loadfile("/halyde/lib/filesystem.lua")(loadfile) local filesystem = loadfile("/halyde/lib/filesystem.lua")(loadfile)
_G._OSVERSION = "Halyde 0.9.0" _G._OSVERSION = "Halyde 0.10.0"
function _G.import(module, ...) function _G.import(module, ...)
local args = table.pack(...) local args = table.pack(...)
+30 -11
View File
@@ -4,10 +4,25 @@ _G.cormgr.corList = {}
--local ocelot = component.proxy(component.list("ocelot")()) --local ocelot = component.proxy(component.list("ocelot")())
local filesystem = import("filesystem") local filesystem = import("filesystem")
local gpu = component.proxy(component.list("gpu")())
function _G.cormgr.loadCoroutine(path) function _G.cormgr.loadCoroutine(path, ...)
local args = {...}
local cor = coroutine.create(function() local cor = coroutine.create(function()
import(path) local result, errorMessage = xpcall(function(...)
import(...)
end, function(errorMessage)
return errorMessage .. "\n \n" .. debug.traceback()
end, path, table.unpack(args))
if not result then
if print then
gpu.freeAllBuffers()
print("\n\27[91m" .. errorMessage)
else
error(errorMessage)
end
end
--import(path, table.unpack(args))
end) end)
table.insert(_G.cormgr.corList, cor) table.insert(_G.cormgr.corList, cor)
end end
@@ -22,16 +37,20 @@ end
local function runCoroutines() local function runCoroutines()
for i = 1, #_G.cormgr.corList do for i = 1, #_G.cormgr.corList do
local result, errorMessage = coroutine.resume(_G.cormgr.corList[i]) if cormgr.corList[i] then
if not result then local result, errorMessage = coroutine.resume(cormgr.corList[i])
handleError(errorMessage) if cormgr.corList[i] then
if not result then
handleError(errorMessage)
end
if coroutine.status(cormgr.corList[i]) == "dead" then
table.remove(cormgr.corList, i)
i = i - 1
end
--computer.pullSignal(0)
--coroutine.yield()
end
end end
if coroutine.status(_G.cormgr.corList[i]) == "dead" then
table.remove(_G.cormgr.corList, i)
i = i - 1
end
--computer.pullSignal(0)
--coroutine.yield()
end end
end end
+27
View File
@@ -2,6 +2,9 @@ _G.evmgr = {}
_G.evmgr.eventQueue = {} _G.evmgr.eventQueue = {}
local maxEventQueueLength = 10 -- increase if events start getting dropped local maxEventQueueLength = 10 -- increase if events start getting dropped
keyboard.ctrlDown = false
keyboard.altDown = false
--local ocelot = component.proxy(component.list("ocelot")()) --local ocelot = component.proxy(component.list("ocelot")())
while true do while true do
@@ -11,6 +14,30 @@ while true do
if args and args[1] then if args and args[1] then
--ocelot.log("Sending signal "..args..","..computer.uptime()) --ocelot.log("Sending signal "..args..","..computer.uptime())
table.insert(evmgr.eventQueue, args) table.insert(evmgr.eventQueue, args)
if keyboard then
if args[1] == "key_down" then
local keycode = args[4]
local key = keyboard.keys[keycode]
if key == "lcontrol" then
keyboard.ctrlDown = true
elseif key == "lmenu" then
keyboard.altDown = true
elseif key == "c" and keyboard.ctrlDown and keyboard.altDown then
if print then
print("\n\27[91mCoroutine "..tostring(#cormgr.corList).." killed.")
end
cormgr.corList[#cormgr.corList] = nil
end
elseif args[1] == "key_up" then
local keycode = args[4]
local key = keyboard.keys[keycode]
if key == "lcontrol" then
keyboard.ctrlDown = false
elseif key == "lmenu" then
keyboard.altDown = false
end
end
end
while #evmgr.eventQueue > maxEventQueueLength do while #evmgr.eventQueue > maxEventQueueLength do
--ocelot.log("Queue length breach, removing first signal") --ocelot.log("Queue length breach, removing first signal")
table.remove(evmgr.eventQueue, 1) table.remove(evmgr.eventQueue, 1)
+1 -2
View File
@@ -1,5 +1,4 @@
_G.keyboard = {pressedChars = {}, pressedCodes = {}} _G.keyboard = {["keys"] = {}}
_G.keyboard.keys = {}
keyboard.keys["1"] = 0x02 keyboard.keys["1"] = 0x02
keyboard.keys["2"] = 0x03 keyboard.keys["2"] = 0x03
+17 -13
View File
@@ -3,11 +3,22 @@ import("/halyde/core/termlib.lua")
local event = import("event") local event = import("event")
--local ocelot = component.proxy(component.list("ocelot")()) --local ocelot = component.proxy(component.list("ocelot")())
local filesystem = import("filesystem") local filesystem = import("filesystem")
local gpu = component.proxy(component.list("gpu")())
_G.shell = {} _G.shell = {}
_G.shell.workingDirectory = shellcfg["defaultWorkingDirectory"] _G.shell.workingDirectory = shellcfg["defaultWorkingDirectory"]
_G.shell.aliases = shellcfg["aliases"] _G.shell.aliases = shellcfg["aliases"]
local function runAsCoroutine(path, ...)
--ocelot.log("running " .. path .. " as coroutine")
cormgr.loadCoroutine(path, ...)
local corIndex = #cormgr.corList
local cor = cormgr.corList[#cormgr.corList]
repeat
coroutine.yield()
until cormgr.corList[corIndex] ~= cor
end
function _G.shell.run(command) function _G.shell.run(command)
checkArg(1, command, "string") checkArg(1, command, "string")
if shell.aliases[command:match("[^ ]+")] then if shell.aliases[command:match("[^ ]+")] then
@@ -48,14 +59,14 @@ function _G.shell.run(command)
foundfile = true foundfile = true
local path = args[1] local path = args[1]
table.remove(args, 1) table.remove(args, 1)
import(path, table.unpack(args)) runAsCoroutine(path, table.unpack(args))
else else
for _, item in pairs(shellcfg["path"]) do for _, item in pairs(shellcfg["path"]) do
if filesystem.exists(item..args[1]) then if filesystem.exists(item..args[1]) then
foundfile = true foundfile = true
local path = item..args[1] local path = item..args[1]
table.remove(args, 1) table.remove(args, 1)
import(path, table.unpack(args)) runAsCoroutine(path, table.unpack(args))
break break
else -- try to look for it without the file extension else -- try to look for it without the file extension
local files = filesystem.list(item) local files = filesystem.list(item)
@@ -63,15 +74,7 @@ function _G.shell.run(command)
if args[1] == file:match("(.+)%.[^%.]+$") then if args[1] == file:match("(.+)%.[^%.]+$") then
foundfile = true foundfile = true
table.remove(args, 1) table.remove(args, 1)
local function runCommand() runAsCoroutine(item..file, table.unpack(args))
import(item..file, table.unpack(args))
end
local result, reason = xpcall(runCommand, function(errMsg)
return errMsg .. "\n\n" .. debug.traceback()
end)
if not result then
print("\27[91m" .. reason)
end
break break
end end
end end
@@ -87,9 +90,10 @@ print(shellcfg["startupMessage"])
while true do while true do
coroutine.yield() coroutine.yield()
-- print(shell.workingDirectory .. " >") -- print(shell.workingDirectory .. " >")
print(shellcfg["prompt"]:format(shell.workingDirectory),false) --print(shellcfg["prompt"]:format(shell.workingDirectory),false)
-- termlib.cursorPosX = #(shell.workingDirectory .. " > ") -- termlib.cursorPosX = #(shell.workingDirectory .. " > ")
-- termlib.cursorPosY = termlib.cursorPosY - 1 -- termlib.cursorPosY = termlib.cursorPosY - 1
local shellCommand = read("shell") local shellCommand = read("shell", shellcfg["prompt"]:format(shell.workingDirectory))
shell.run(shellCommand) shell.run(shellCommand)
gpu.freeAllBuffers()
end end
+43 -32
View File
@@ -1,6 +1,7 @@
local event = import("event") local event = import("event")
--local keyboard = import("keyboard") --local keyboard = import("keyboard")
--local ocelot = component.proxy(component.list("ocelot")())
local gpu = component.proxy(component.list("gpu")()) -- replace with component.gpu once implemented local gpu = component.proxy(component.list("gpu")()) -- replace with component.gpu once implemented
_G.termlib = {} _G.termlib = {}
termlib.cursorPosX = 1 termlib.cursorPosX = 1
@@ -41,7 +42,7 @@ gpu.setForeground(defaultForegroundColor)
gpu.setBackground(defaultBackgroundColor) gpu.setBackground(defaultBackgroundColor)
local function scrollDown() local function scrollDown()
if gpu.copy(0,1,width,height,0,-1) then if gpu.copy(1,1,width,height,0,-1) then
local prevForeground = gpu.getForeground() local prevForeground = gpu.getForeground()
local prevBackground = gpu.getBackground() local prevBackground = gpu.getBackground()
gpu.setForeground(defaultForegroundColor) gpu.setForeground(defaultForegroundColor)
@@ -61,7 +62,7 @@ local function newLine()
end end
end end
function parseCodeNumbers(code) local function parseCodeNumbers(code)
o = {} o = {}
for num in code:sub(3,-2):gmatch("[^;]+") do for num in code:sub(3,-2):gmatch("[^;]+") do
table.insert(o,tonumber(num)) table.insert(o,tonumber(num))
@@ -69,13 +70,16 @@ function parseCodeNumbers(code)
return o return o
end end
function _G.print(text,endNewLine) function _G.print(text, endNewLine, wordWrap)
-- you don't know how tiring this was just for ANSI escape code support -- you don't know how tiring this was just for ANSI escape code support
if endNewLine==nil then if endNewLine == nil then
endNewLine = true endNewLine = true
end end
if wordWrap == nil then
wordWrap = true
end
if not text or not tostring(text) then if not text or not tostring(text) then
return return
@@ -93,7 +97,7 @@ function _G.print(text,endNewLine)
end end
gpu.set(termlib.cursorPosX,termlib.cursorPosY,section) gpu.set(termlib.cursorPosX,termlib.cursorPosY,section)
termlib.cursorPosX = termlib.cursorPosX+unicode.wlen(section) termlib.cursorPosX = termlib.cursorPosX+unicode.wlen(section)
if termlib.cursorPosX>width then if termlib.cursorPosX>width and wordWrap then
newLine() newLine()
end end
section="" section=""
@@ -162,13 +166,18 @@ end
function _G.clear() function _G.clear()
local xRes, yRes = gpu.getResolution() local xRes, yRes = gpu.getResolution()
gpu.setForeground(defaultForegroundColor)
gpu.setBackground(defaultBackgroundColor)
gpu.fill(1,1,xRes,yRes," ") gpu.fill(1,1,xRes,yRes," ")
termlib.cursorPosX, termlib.cursorPosY = 1, 1 termlib.cursorPosX, termlib.cursorPosY = 1, 1
end end
function _G.read(readHistoryType) function _G.read(readHistoryType, prefix, defaultText)
checkArg(1, readHistoryType, "string", "nil") checkArg(1, readHistoryType, "string", "nil")
local curtext = "" checkArg(2, prefix, "string", "nil")
checkArg(3, defaultText, "string", "nil")
local curtext = defaultText or ""
local prefix = prefix or ""
local RHIndex local RHIndex
if readHistoryType then if readHistoryType then
if not termlib.readHistory[readHistoryType] then if not termlib.readHistory[readHistoryType] then
@@ -179,13 +188,10 @@ function _G.read(readHistoryType)
RHIndex = #termlib.readHistory[readHistoryType] -- read history index RHIndex = #termlib.readHistory[readHistoryType] -- read history index
end end
local cursorPosX, cursorPosY = termlib.cursorPosX, termlib.cursorPosY local cursorPosX, cursorPosY = termlib.cursorPosX, termlib.cursorPosY
print(prefix .. curtext .. "\27[107m ", false)
local cursorWhite = true local cursorWhite = true
while true do while true do
if cursorWhite then --ocelot.log(curtext)
print("\27[107m ", false)
else
print(" ", false)
end
termlib.cursorPosX = termlib.cursorPosX - 1 termlib.cursorPosX = termlib.cursorPosX - 1
local args = {event.pull("key_down", 0.5)} local args = {event.pull("key_down", 0.5)}
if args[4] then if args[4] then
@@ -194,51 +200,56 @@ function _G.read(readHistoryType)
local key = keyboard.keys[keycode] local key = keyboard.keys[keycode]
if key == "up" and readHistoryType then if key == "up" and readHistoryType then
termlib.cursorPosX, termlib.cursorPosY = cursorPosX, cursorPosY termlib.cursorPosX, termlib.cursorPosY = cursorPosX, cursorPosY
print(curtext .. " ", false) print(prefix .. curtext .. " ", false)
RHIndex = RHIndex - 1 RHIndex = RHIndex - 1
if RHIndex <= 0 then if RHIndex <= 0 then
RHIndex = 1 RHIndex = 1
end end
termlib.cursorPosX, termlib.cursorPosY = cursorPosX, cursorPosY termlib.cursorPosX, termlib.cursorPosY = cursorPosX, cursorPosY
print(termlib.readHistory[readHistoryType][RHIndex] .. string.rep(" ", unicode.wlen(curtext) - unicode.wlen(termlib.readHistory[readHistoryType][RHIndex])), false) print(prefix .. termlib.readHistory[readHistoryType][RHIndex] .. string.rep(" ", unicode.wlen(curtext) - unicode.wlen(termlib.readHistory[readHistoryType][RHIndex])), false)
curtext = termlib.readHistory[readHistoryType][RHIndex] curtext = termlib.readHistory[readHistoryType][RHIndex]
end end
if key == "down" and readHistoryType then if key == "down" and readHistoryType then
termlib.cursorPosX, termlib.cursorPosY = cursorPosX, cursorPosY termlib.cursorPosX, termlib.cursorPosY = cursorPosX, cursorPosY
print(curtext .. " ", false) print(prefix .. curtext .. " ", false)
RHIndex = RHIndex + 1 RHIndex = RHIndex + 1
if RHIndex > #termlib.readHistory[readHistoryType] then if RHIndex > #termlib.readHistory[readHistoryType] then
RHIndex = #termlib.readHistory[readHistoryType] RHIndex = #termlib.readHistory[readHistoryType]
end end
termlib.cursorPosX, termlib.cursorPosY = cursorPosX, cursorPosY termlib.cursorPosX, termlib.cursorPosY = cursorPosX, cursorPosY
print(termlib.readHistory[readHistoryType][RHIndex] .. string.rep(" ", unicode.wlen(curtext) - unicode.wlen(termlib.readHistory[readHistoryType][RHIndex])), false) print(prefix .. termlib.readHistory[readHistoryType][RHIndex] .. string.rep(" ", unicode.wlen(curtext) - unicode.wlen(termlib.readHistory[readHistoryType][RHIndex])), false)
curtext = termlib.readHistory[readHistoryType][RHIndex] curtext = termlib.readHistory[readHistoryType][RHIndex]
end end
if key == "back" then
curtext = curtext:sub(1, #curtext-1)
termlib.cursorPosX, termlib.cursorPosY = cursorPosX, cursorPosY
print(prefix .. curtext.." ", false)
end
if key == "enter" then
termlib.cursorPosX, termlib.cursorPosY = cursorPosX, cursorPosY
print(prefix .. curtext .. " ")
if readHistoryType then
while #termlib.readHistory[readHistoryType] > 50 do
table.remove(termlib.readHistory[readHistoryType], 1)
end
end
return curtext
end
if args[3] >= 32 and args[3] <= 126 then if args[3] >= 32 and args[3] <= 126 then
curtext = curtext .. (unicode.char(args[3]) or "") curtext = curtext .. (unicode.char(args[3]) or "")
if readHistoryType then if readHistoryType then
termlib.readHistory[readHistoryType][RHIndex] = curtext termlib.readHistory[readHistoryType][RHIndex] = curtext
end end
else
if key == "back" then
curtext = curtext:sub(1, #curtext-1)
termlib.cursorPosX, termlib.cursorPosY = cursorPosX, cursorPosY
print(curtext.." ", false)
elseif key == "enter" then
termlib.cursorPosX, termlib.cursorPosY = cursorPosX, cursorPosY
print(curtext .. " ")
if readHistoryType then
while #termlib.readHistory[readHistoryType] > 50 do
table.remove(termlib.readHistory[readHistoryType], 1)
end
end
return curtext
end
end end
termlib.cursorPosX, termlib.cursorPosY = cursorPosX, cursorPosY termlib.cursorPosX, termlib.cursorPosY = cursorPosX, cursorPosY
print(curtext, false) print(prefix .. curtext, false)
else else
cursorWhite = not cursorWhite cursorWhite = not cursorWhite
end end
if cursorWhite then
print("\27[107m ", false)
else
print(" ", false)
end
end end
end end
+6 -1
View File
@@ -48,7 +48,12 @@ function filesystem.open(path, mode) -- opens a file and returns its handle
return nil, "invalid handle type" return nil, "invalid handle type"
end end
local address, absPath = filesystem.processPath(path) local address, absPath = filesystem.processPath(path)
local handle = component.invoke(address, "open", absPath, mode) local handleArgs = {component.invoke(address, "open", absPath, mode)}
local handle = handleArgs[1]
if not handle then
return table.unpack(handleArgs)
end
handleArgs = nil
local properHandle = {} local properHandle = {}
properHandle.handle = handle properHandle.handle = handle
properHandle.address = address properHandle.address = address
+298 -293
View File
@@ -1,11 +1,11 @@
local raster = { local raster = {
["units"]={}, ["units"]={},
["defaultBackgroundColor"]=0x000000, ["defaultBackgroundColor"]=0x000000,
["defaultForegroundColor"]=0xFFFFFF, ["defaultForegroundColor"]=0xFFFFFF,
["displayWidth"]=0, ["displayWidth"]=0,
["displayHeight"]=0, ["displayHeight"]=0,
["charWidth"]=0, ["charWidth"]=0,
["charHeight"]=0 ["charHeight"]=0
} }
-- local ocelot = component.proxy(component.list("ocelot")()) -- local ocelot = component.proxy(component.list("ocelot")())
@@ -19,393 +19,398 @@ local renderBuffer = nil
-- braille rendering -- braille rendering
function raster.units.charToBraille(x,y) function raster.units.charToBraille(x,y)
return x*2,y*4 return x*2,y*4
end end
function raster.units.brailleToChar(x,y) function raster.units.brailleToChar(x,y)
return math.ceil(x/2),math.ceil(y/4) return math.ceil(x/2),math.ceil(y/4)
end end
function raster.init(width, height, bgcolor) function raster.init(width, height, bgcolor)
-- NOTE: Width and height are in characters, not pixels in braille. -- NOTE: Width and height are in characters, not pixels in braille.
-- If the width and height are nil, the entire screen will be used. -- If the width and height are nil, the entire screen will be used.
if width==nil and height==nil then if width==nil and height==nil then
width, height = gpu.getResolution() width, height = gpu.getResolution()
end end
for i = 1, width*height do for i = 1, width*height do
chunksAffected[i] = true chunksAffected[i] = true
end end
raster.charWidth = width raster.charWidth = width
raster.charHeight = height raster.charHeight = height
width, height = raster.units.charToBraille(width, height) width, height = raster.units.charToBraille(width, height)
bgcolor = bgcolor or raster.defaultBackgroundColor; bgcolor = bgcolor or raster.defaultBackgroundColor
for i = 1, width*height do raster.displayWidth = width
display[i] = bgcolor raster.displayHeight = height
end
raster.displayWidth = width
raster.displayHeight = height
pcall(function() pcall(function()
renderBuffer = gpu.allocateBuffer() renderBuffer = gpu.allocateBuffer()
end) end)
end end
function raster.set(x, y, color) function raster.set(x, y, color)
if x<1 or x>raster.displayWidth or y<1 or y>raster.displayHeight then if x<1 or x>raster.displayWidth or y<1 or y>raster.displayHeight then
return false return false
end end
color = color or raster.defaultForegroundColor color = color or raster.defaultForegroundColor
local i = x+y*raster.displayWidth local i = x+y*raster.displayWidth
display[i] = color display[i] = color
local ci = math.floor((x-1)/2)+math.floor((y-1)/4)*raster.charWidth+1 local ci = math.floor((x-1)/2)+math.floor((y-1)/4)*raster.charWidth+1
-- ocelot.log(x..","..y..":"..ci) -- ocelot.log(x..","..y..":"..ci)
chunksAffected[ci] = true chunksAffected[ci] = true
return true return true
end end
function raster.get(x, y) function raster.get(x, y)
local i = x+y*raster.displayWidth local i = x+y*raster.displayWidth
return display[i] or 0 return display[i] or 0
end end
local function stats(arr) local function stats(arr)
local out = {} local out = {}
for i=1,#arr do for i=1,#arr do
local v = arr[i] local v = arr[i]
if out[v]==nil then if out[v]==nil then
out[v]=1 out[v]=1
else else
out[v] = out[v] + 1 out[v] = out[v] + 1
end
end end
return out end
return out
end end
local function getKeys(t) local function getKeys(t)
local keys = {} local keys = {}
for key, _ in pairs(t) do for key, _ in pairs(t) do
table.insert(keys, key) table.insert(keys, key)
end end
return keys return keys
end end
local function colorDifference(a,b) local function colorDifference(a,b)
return ((a>>16)&255)-((b>>16)&255)+((a>>8)&255)-((b>>8)&255)+(a&255)-(b&255) return ((a>>16)&255)-((b>>16)&255)+((a>>8)&255)-((b>>8)&255)+(a&255)-(b&255)
end end
local function limitTwoColors(arr) local function limitTwoColors(arr)
local colors = getKeys(stats(arr)) local colors = getKeys(stats(arr))
for i=1,#arr do for i=1,#arr do
local v=arr[i] local v=arr[i]
if v==colors[1] then if v==colors[1] then
arr[i]=0 arr[i]=0
goto continue goto continue
elseif v==colors[2] then elseif v==colors[2] then
arr[i]=1 arr[i]=1
goto continue goto continue
else else
--error("Pixel is not in the two colors (raster.lua:90)") --error("Pixel is not in the two colors (raster.lua:90)")
-- get closest color so atleast it kinda shows -- get closest color so atleast it kinda shows
if colorDifference(v,colors[1])<colorDifference(v,colors[2]) then if colorDifference(v,colors[1])<colorDifference(v,colors[2]) then
arr[i]=0 arr[i]=0
else else
arr[i]=1 arr[i]=1
end end
end
::continue::
end end
return arr,colors[1] or 0,colors[2] or 0 ::continue::
end
return arr,colors[1] or 0,colors[2] or 0
end end
local function arrayToBraille(arr) local function arrayToBraille(arr)
local codePoint = 0x2800 local codePoint = 0x2800
for i=1,8 do for i=1,8 do
codePoint = codePoint | arr[i]<<(i-1) codePoint = codePoint | arr[i]<<(i-1)
end end
return utf8.char(codePoint) return utf8.char(codePoint)
end end
function raster.update() function raster.update()
if renderBuffer~=nil then if renderBuffer~=nil then
gpu.setActiveBuffer(renderBuffer) gpu.setActiveBuffer(renderBuffer)
end end
for y=1,raster.displayHeight,4 do for y=1,raster.displayHeight,4 do
-- gpu.set(0,0,tostring(y)) -- gpu.set(0,0,tostring(y))
for x=1,raster.displayWidth,2 do for x=1,raster.displayWidth,2 do
local ci = math.floor(x/2)+math.floor(y/4)*raster.charWidth+1 local ci = math.floor(x/2)+math.floor(y/4)*raster.charWidth+1
if chunksAffected[ci] then if chunksAffected[ci] then
local chunk = { local chunk = {
raster.get(x,y), raster.get(x,y),
raster.get(x,y+1), raster.get(x,y+1),
raster.get(x,y+2), raster.get(x,y+2),
raster.get(x+1,y), raster.get(x,y+3),
raster.get(x+1,y+1), raster.get(x+1,y),
raster.get(x+1,y+2), raster.get(x+1,y+1),
raster.get(x,y+3), raster.get(x+1,y+2),
raster.get(x+1,y+3) raster.get(x+1,y+3)
} }
local colorA = nil local colorA = nil
local colorB = nil local colorB = nil
chunk,colorA,colorB = limitTwoColors(chunk) chunk,colorA,colorB = limitTwoColors(chunk)
-- print(tostring(colorA)..","..tostring(colorB)) -- print(tostring(colorA)..","..tostring(colorB))
cx,cy=raster.units.brailleToChar(x,y) cx,cy=raster.units.brailleToChar(x,y)
gpu.setBackground(colorA) gpu.setBackground(colorA)
gpu.setForeground(colorB) gpu.setForeground(colorB)
-- gpu.set(cx,cy,tostring(colorB/0xFFFFFF)) -- gpu.set(cx,cy,tostring(colorB/0xFFFFFF))
gpu.set(cx,cy,arrayToBraille(chunk)) gpu.set(cx,cy,arrayToBraille(chunk))
chunksAffected[ci] = false chunksAffected[ci] = false
end end
end
end
if renderBuffer~=nil then
gpu.bitblt()
gpu.setActiveBuffer(0)
end end
end
if renderBuffer~=nil then
gpu.bitblt()
gpu.setActiveBuffer(0)
end
end
function raster.clear()
if renderBuffer~=nil then
gpu.setActiveBuffer(renderBuffer)
end
clear()
display = {}
end end
function raster.free() function raster.free()
if renderBuffer==nil then if renderBuffer==nil then
return true return true
else else
return gpu.freeBuffer(renderBuffer) return gpu.freeBuffer(renderBuffer)
end end
end end
-- advanced rendering -- advanced rendering
function raster.drawLine(x1, y1, x2, y2, color) function raster.drawLine(x1, y1, x2, y2, color)
x1, y1, x2, y2 = math.floor(x1), math.floor(y1), math.floor(x2), math.floor(y2) x1, y1, x2, y2 = math.floor(x1), math.floor(y1), math.floor(x2), math.floor(y2)
local dx = math.abs(x2 - x1) local dx = math.abs(x2 - x1)
local dy = math.abs(y2 - y1) local dy = math.abs(y2 - y1)
local sx = x1 < x2 and 1 or -1 local sx = x1 < x2 and 1 or -1
local sy = y1 < y2 and 1 or -1 local sy = y1 < y2 and 1 or -1
local err = dx - dy local err = dx - dy
while true do while true do
raster.set(x1, y1, color) raster.set(x1, y1, color)
if x1 == x2 and y1 == y2 then if x1 == x2 and y1 == y2 then
break break
end
local e2 = 2 * err
if e2 > -dy then
err = err - dy
x1 = x1 + sx
end
if e2 < dx then
err = err + dx
y1 = y1 + sy
end
end end
local e2 = 2 * err
if e2 > -dy then
err = err - dy
x1 = x1 + sx
end
if e2 < dx then
err = err + dx
y1 = y1 + sy
end
end
end end
function raster.drawRect(x1,y1,x2,y2,col) function raster.drawRect(x1,y1,x2,y2,col)
x1, y1, x2, y2 = math.floor(x1), math.floor(y1), math.floor(x2), math.floor(y2) x1, y1, x2, y2 = math.floor(x1), math.floor(y1), math.floor(x2), math.floor(y2)
if x1 > x2 then x1, x2 = x2, x1 end if x1 > x2 then x1, x2 = x2, x1 end
if y1 > y2 then y1, y2 = y2, y1 end if y1 > y2 then y1, y2 = y2, y1 end
for x=x1,x2 do for x=x1,x2 do
raster.set(x,y1,col) raster.set(x,y1,col)
raster.set(x,y2,col) raster.set(x,y2,col)
end end
for y=y1+1,y2-1 do for y=y1+1,y2-1 do
raster.set(x1,y,col) raster.set(x1,y,col)
raster.set(x2,y,col) raster.set(x2,y,col)
end end
end end
function raster.fillRect(x1,y1,x2,y2,col) function raster.fillRect(x1,y1,x2,y2,col)
x1, y1, x2, y2 = math.floor(x1), math.floor(y1), math.floor(x2), math.floor(y2) x1, y1, x2, y2 = math.floor(x1), math.floor(y1), math.floor(x2), math.floor(y2)
if x1 > x2 then x1, x2 = x2, x1 end if x1 > x2 then x1, x2 = x2, x1 end
if y1 > y2 then y1, y2 = y2, y1 end if y1 > y2 then y1, y2 = y2, y1 end
for x=x1,x2 do for x=x1,x2 do
for y=y1,y2 do for y=y1,y2 do
raster.set(x,y,col) raster.set(x,y,col)
end
end end
end
end end
function raster.drawCircle(xc, yc, radius, color) function raster.drawCircle(xc, yc, radius, color)
xc=math.floor(xc) xc=math.floor(xc)
yc=math.floor(yc) yc=math.floor(yc)
radius=math.floor(radius) radius=math.floor(radius)
local x = 0 local x = 0
local y = radius local y = radius
local d = 3 - 2 * radius local d = 3 - 2 * radius
while y >= x do while y >= x do
-- Draw 8 symmetric points -- Draw 8 symmetric points
raster.set(xc + x, yc + y, color) raster.set(xc + x, yc + y, color)
raster.set(xc - x, yc + y, color) raster.set(xc - x, yc + y, color)
raster.set(xc + x, yc - y, color) raster.set(xc + x, yc - y, color)
raster.set(xc - x, yc - y, color) raster.set(xc - x, yc - y, color)
raster.set(xc + y, yc + x, color) raster.set(xc + y, yc + x, color)
raster.set(xc - y, yc + x, color) raster.set(xc - y, yc + x, color)
raster.set(xc + y, yc - x, color) raster.set(xc + y, yc - x, color)
raster.set(xc - y, yc - x, color) raster.set(xc - y, yc - x, color)
if d < 0 then if d < 0 then
d = d + 4 * x + 6 d = d + 4 * x + 6
else else
d = d + 4 * (x - y) + 10 d = d + 4 * (x - y) + 10
y = y - 1 y = y - 1
end
x = x + 1
end end
x = x + 1
end
end end
function raster.drawEllipse(x1, y1, x2, y2, color) function raster.drawEllipse(x1, y1, x2, y2, color)
if x1 > x2 then x1, x2 = x2, x1 end if x1 > x2 then x1, x2 = x2, x1 end
if y1 > y2 then y1, y2 = y2, y1 end if y1 > y2 then y1, y2 = y2, y1 end
local xc = math.floor((x1 + x2) / 2) local xc = math.floor((x1 + x2) / 2)
local yc = math.floor((y1 + y2) / 2) local yc = math.floor((y1 + y2) / 2)
local a = math.floor((x2 - x1) / 2) local a = math.floor((x2 - x1) / 2)
local b = math.floor((y2 - y1) / 2) local b = math.floor((y2 - y1) / 2)
if a <= 0 or b <= 0 then if a <= 0 or b <= 0 then
return return
end
if a == b then
raster.drawCircle(xc, yc, a, color)
return
end
if a <= 1 and b <= 1 then
raster.set(xc, yc, color)
return
elseif a <= 1 then
for y = yc - b, yc + b do
raster.set(xc, y, color)
end end
return
if a == b then elseif b <= 1 then
raster.drawCircle(xc, yc, a, color) for x = xc - a, xc + a do
return raster.set(x, yc, color)
end end
return
end
if a <= 1 and b <= 1 then local x = 0
raster.set(xc, yc, color) local y = b
return local a2 = a * a
elseif a <= 1 then local b2 = b * b
for y = yc - b, yc + b do
raster.set(xc, y, color) local d1 = b2 - (a2 * b) + (0.25 * a2)
end local dx = 2 * b2 * x
return local dy = 2 * a2 * y
elseif b <= 1 then
for x = xc - a, xc + a do while dx < dy do
raster.set(x, yc, color) raster.set(xc + x, yc + y, color)
end raster.set(xc - x, yc + y, color)
return raster.set(xc + x, yc - y, color)
raster.set(xc - x, yc - y, color)
if d1 < 0 then
x = x + 1
dx = dx + (2 * b2)
d1 = d1 + dx + b2
else
x = x + 1
y = y - 1
dx = dx + (2 * b2)
dy = dy - (2 * a2)
d1 = d1 + dx - dy + b2
end end
end
local x = 0 local d2 = b2 * (x + 0.5) * (x + 0.5) + a2 * (y - 1) * (y - 1) - a2 * b2
local y = b
local a2 = a * a
local b2 = b * b
local d1 = b2 - (a2 * b) + (0.25 * a2) while y >= 0 do
local dx = 2 * b2 * x raster.set(xc + x, yc + y, color)
local dy = 2 * a2 * y raster.set(xc - x, yc + y, color)
raster.set(xc + x, yc - y, color)
raster.set(xc - x, yc - y, color)
while dx < dy do if d2 > 0 then
raster.set(xc + x, yc + y, color) y = y - 1
raster.set(xc - x, yc + y, color) dy = dy - (2 * a2)
raster.set(xc + x, yc - y, color) d2 = d2 - dy + a2
raster.set(xc - x, yc - y, color) else
y = y - 1
if d1 < 0 then x = x + 1
x = x + 1 dx = dx + (2 * b2)
dx = dx + (2 * b2) dy = dy - (2 * a2)
d1 = d1 + dx + b2 d2 = d2 + dx - dy + a2
else
x = x + 1
y = y - 1
dx = dx + (2 * b2)
dy = dy - (2 * a2)
d1 = d1 + dx - dy + b2
end
end
local d2 = b2 * (x + 0.5) * (x + 0.5) + a2 * (y - 1) * (y - 1) - a2 * b2
while y >= 0 do
raster.set(xc + x, yc + y, color)
raster.set(xc - x, yc + y, color)
raster.set(xc + x, yc - y, color)
raster.set(xc - x, yc - y, color)
if d2 > 0 then
y = y - 1
dy = dy - (2 * a2)
d2 = d2 - dy + a2
else
y = y - 1
x = x + 1
dx = dx + (2 * b2)
dy = dy - (2 * a2)
d2 = d2 + dx - dy + a2
end
end end
end
end end
function raster.fillCircle(x, y, r, color) function raster.fillCircle(x, y, r, color)
x, y = math.floor(x + 0.5), math.floor(y + 0.5) x, y = math.floor(x + 0.5), math.floor(y + 0.5)
r = math.floor(r + 0.5) r = math.floor(r + 0.5)
if r <= 0 then return end if r <= 0 then return end
local minX, maxX = x - r, x + r local minX, maxX = x - r, x + r
local minY, maxY = y - r, y + r local minY, maxY = y - r, y + r
for py = minY, maxY do for py = minY, maxY do
for px = minX, maxX do for px = minX, maxX do
local dx, dy = px - x, py - y local dx, dy = px - x, py - y
local distSquared = dx*dx + dy*dy local distSquared = dx*dx + dy*dy
if distSquared <= r*r then if distSquared <= r*r then
raster.set(px, py, color) raster.set(px, py, color)
end end
end
end end
end
end end
function raster.fillEllipse(x1, y1, x2, y2, color) function raster.fillEllipse(x1, y1, x2, y2, color)
local centerX = (x1 + x2) / 2 local centerX = (x1 + x2) / 2
local centerY = (y1 + y2) / 2 local centerY = (y1 + y2) / 2
local a = math.abs(x2 - x1) / 2 local a = math.abs(x2 - x1) / 2
local b = math.abs(y2 - y1) / 2 local b = math.abs(y2 - y1) / 2
centerX = math.floor(centerX + 0.5) centerX = math.floor(centerX + 0.5)
centerY = math.floor(centerY + 0.5) centerY = math.floor(centerY + 0.5)
a = math.floor(a + 0.5) a = math.floor(a + 0.5)
b = math.floor(b + 0.5) b = math.floor(b + 0.5)
if a <= 0 or b <= 0 then return end if a <= 0 or b <= 0 then return end
if a == b then if a == b then
raster.fillCircle(centerX, centerY, a, color) raster.fillCircle(centerX, centerY, a, color)
return return
end end
local minX = centerX - a local minX = centerX - a
local maxX = centerX + a local maxX = centerX + a
local minY = centerY - b local minY = centerY - b
local maxY = centerY + b local maxY = centerY + b
for y = minY, maxY do for y = minY, maxY do
for x = minX, maxX do for x = minX, maxX do
local dx = x - centerX local dx = x - centerX
local dy = y - centerY local dy = y - centerY
local value = (dx*dx)/(a*a) + (dy*dy)/(b*b) local value = (dx*dx)/(a*a) + (dy*dy)/(b*b)
if value <= 1 then if value <= 1 then
raster.set(x, y, color) raster.set(x, y, color)
end end
end
end end
end
end end
return raster return raster
+67
View File
@@ -0,0 +1,67 @@
This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file!
This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file!
This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file!
This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file!
This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file! This is a long file!
This is a long line! This is a long line! This is a long line! This is a long line! This is a long line! This is a long line! This is a long line! This is a long line! This is a long line!
This is a longer line! This is a longer line! This is a longer line! This is a longer line! This is a longer line! This is a longer line! This is a longer line! This is a longer line! This is a longer line! This is a longer line! This is a longer line! This is a longer line! This is a longer line! This is a longer line!
This is a short line!
This is a short line!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This has a lot of lines!
This is the last line!