fontsize:
result:
| --------------------------------------------------------------------------- | |
| -- vector | |
| local vector = (function() | |
| local mt = {} | |
| mt.__index = mt | |
| local vector | |
| vector = function(x, y, z) | |
| if type(x) == 'table' then | |
| return setmetatable(x, mt) | |
| end | |
| x = x or 0 | |
| y = y or x | |
| z = z or y | |
| return vector{x, y, z} | |
| end | |
| local map = function(f, a, b) | |
| a = vector(a) | |
| b = vector(b) | |
| return vector{ f(a[1], b[1]), f(a[2], b[2]), f(a[3], b[3]) } | |
| end | |
| local sqrt = math.sqrt | |
| mt.__add = function(a, b) return map(function(x, y) return x+y end, a, b) end | |
| mt.__sub = function(a, b) return map(function(x, y) return x-y end, a, b) end | |
| mt.__mul = function(a, b) return map(function(x, y) return x*y end, a, b) end | |
| mt.__div = function(a, b) return map(function(x, y) return x/y end, a, b) end | |
| mt.__neg = function(a ) return map(function(x ) return -x end, a ) end | |
| mt.__concat = function(a, b) return a[1]*b[1] + a[2]*b[2] + a[3]*b[3] end | |
| mt.__len = function(a) return sqrt(a .. a) end | |
| mt.norm = function(a) return a / #a end | |
| return vector | |
| end)() | |
| --------------------------------------------------------------------------- | |
| -- distance field renderer | |
| local renderer = (function(max_step, max_radius) | |
| local lerp = function(x, xf, xt, df, dt) | |
| if x < xf then return df end | |
| if x > xt then return dt end | |
| return (x-xf) / (xt-xf) * (dt-df) + df | |
| end | |
| local raymarch = function(est, origin, dir) | |
| local dist = 0 | |
| for i=1,max_step do | |
| local d = est(dir * dist + origin) | |
| if d < 1e-5 then return lerp(i, 1, max_step, 0, 1) end | |
| dist = dist + d | |
| if dist > max_radius then break end | |
| end | |
| end | |
| local rad, cos, sin, pow = math.rad, math.cos, math.sin, math.pow | |
| local write = io.write | |
| local aa = function(x) | |
| local grays = [==[ .'`^",:;Il!i><~+_-?][}{1)(|\/tfjrxnuvczXYUJCLQ0OZmwqpdbkhao*#MW&8%B@$]==] | |
| x = math.floor(lerp(x, 0, 1, 1, grays:len())) | |
| return grays:sub(x, x) | |
| end | |
| return function(estimator, size, fov, eye) | |
| for y=1,size.h do | |
| for x=1,size.w do | |
| local cx = rad( lerp(x, 1, size.w, -fov.x/2, fov.x/2)) | |
| local cy = rad(-lerp(y, 1, size.h, -fov.y/2, fov.y/2)) | |
| local dir = vector(cos(cy)*sin(cx), sin(cy), -cos(cy)*cos(cx)) | |
| local x = raymarch(estimator, vector(eye), dir) | |
| if x then x = pow(1-x, 10) else x = 0 end | |
| write(aa(x)) | |
| end | |
| write '\n' | |
| end | |
| end | |
| end)(100, 50) | |
| --------------------------------------------------------------------------- | |
| -- main | |
| local estimator = (function() | |
| local s2p = vector(2, 0, 0) | |
| local min, max = math.min, math.max | |
| return function(p) | |
| local ns1 = 1 - #p | |
| local s2 = #(p-s2p) - 2 | |
| local p = p[2] + 1 | |
| return max(min(s2, p), ns1) | |
| end | |
| end)() | |
| local scale=1.4 | |
| renderer(estimator, {w=60*1.7*scale, h=30*scale}, {x=160, y=90}, {-0.5, 0, 2}) |
| --------------------------------------------------------------------------- | |
| -- vector | |
| local vector = (function() | |
| local mt = {} | |
| mt.__index = mt | |
| local vector | |
| vector = function(x, y, z) | |
| if type(x) == 'table' then | |
| return setmetatable(x, mt) | |
| end | |
| x = x or 0 | |
| y = y or x | |
| z = z or y | |
| return vector{x, y, z} | |
| end | |
| local map = function(f, a, b) | |
| a = vector(a) | |
| b = vector(b) | |
| return vector{ f(a[1], b[1]), f(a[2], b[2]), f(a[3], b[3]) } | |
| end | |
| local sqrt = math.sqrt | |
| mt.__add = function(a, b) return map(function(x, y) return x+y end, a, b) end | |
| mt.__sub = function(a, b) return map(function(x, y) return x-y end, a, b) end | |
| mt.__mul = function(a, b) return map(function(x, y) return x*y end, a, b) end | |
| mt.__div = function(a, b) return map(function(x, y) return x/y end, a, b) end | |
| mt.__neg = function(a ) return map(function(x ) return -x end, a ) end | |
| mt.__concat = function(a, b) return a[1]*b[1] + a[2]*b[2] + a[3]*b[3] end | |
| mt.__len = function(a) return sqrt(a .. a) end | |
| mt.norm = function(a) return a / #a end | |
| return vector | |
| end)() | |
| --------------------------------------------------------------------------- | |
| -- distance field renderer | |
| local renderer = (function(max_step, max_radius) | |
| local lerp = function(x, xf, xt, df, dt) | |
| if x < xf then return df end | |
| if x > xt then return dt end | |
| return (x-xf) / (xt-xf) * (dt-df) + df | |
| end | |
| local raymarch = function(est, origin, dir) | |
| local dist = 0 | |
| for i=1,max_step do | |
| local d = est(dir * dist + origin) | |
| if d < 1e-5 then return lerp(i, 1, max_step, 0, 1) end | |
| dist = dist + d | |
| if dist > max_radius then break end | |
| end | |
| end | |
| local rad, cos, sin, pow, floor = math.rad, math.cos, math.sin, math.pow, math.floor | |
| local fmt = string.format | |
| local write = io.write | |
| local aa = function(x) | |
| return fmt("\x1b[48;5;%dm \x1b[0m", floor(lerp(x, 0, 1, 232, 255))) | |
| end | |
| return function(estimator, size, fov, eye) | |
| for y=1,size.h do | |
| for x=1,size.w do | |
| local cx = rad( lerp(x, 1, size.w, -fov.x/2, fov.x/2)) | |
| local cy = rad(-lerp(y, 1, size.h, -fov.y/2, fov.y/2)) | |
| local dir = vector(cos(cy)*sin(cx), sin(cy), -cos(cy)*cos(cx)) | |
| local x = raymarch(estimator, vector(eye), dir) | |
| if x then x = pow(1-x, 10) else x = 0 end | |
| write(aa(x)) | |
| end | |
| write '\n' | |
| end | |
| end | |
| end)(100, 50) | |
| --------------------------------------------------------------------------- | |
| -- main | |
| local estimator = (function() | |
| local s2p = vector(2, 0, 0) | |
| local min, max = math.min, math.max | |
| return function(p) | |
| local ns1 = 1 - #p | |
| local s2 = #(p-s2p) - 2 | |
| local p = p[2] + 1 | |
| return max(min(s2, p), ns1) | |
| end | |
| end)() | |
| local scale=1.4 | |
| renderer(estimator, {w=60*1.7*scale, h=30*scale}, {x=160, y=90}, {-0.5, 0, 2}) |
| ...'''`````''''.. | |
| .'`^^",::;;;IIII;;;::,"^^`'. | |
| .'^",;;Il!!!>>>>>>>>>>>>!!llI;:,"^'. | |
| .`^,:Il!!>~~~++++--------++++~~>>!!lI:"^'. | |
| '^":Il!>~~++---[[[[[[[[[[[[[[[[---++~~>!lI:"`. | |
| `''. !>~~+--[[[{{{{{(((((((((({{{{{[[[--+~~>!I:"`. | |
| ;:,"^`'. --[[{{{((((((//////////((((({{{[[[-++~>!I:^ | |
| >!!llI;:"^'. [{{((((//////rrrrrrrr//////(((({{[[-++~!l; | |
| ~~~>>!lI;:"^' (((////rrrrrrrrrrrrrrrrrr////((({{[[-+~>! | |
| ---++~~>!lI;,^'(///rrrrruuuuuuuuuuuuuurrrrr///((({{[-+~> | |
| [[[[---++~>!lI:^'/rrrruuuuuuuuYYYYuuuuuuuurrrr///(({{[-+~ | |
| {{{{[[[--+~>!lI:^rrruuuuuYYYYYYYYYYYYYYuuuuurrrr//(({{[-+ | |
| (((({{[[[-+~~!l;,'uuuuuYYYYYYYYYYYYYYYYYYuuuuurrr//(({{[- | |
| ///(((({{[[-+~>!I:^uuuYYYYYYLLLLLLLLLLYYYYYYuuuurrr//(({[[ | |
| r////((({{[--+~>l;"uuYYYYYLLLLLLLLLLLLLLYYYYYuuurrr//(({{[ | |
| rrrr//((({[[-+~>!I,uYYYYYLLLLLmmmmmLLLLLLYYYYuuuurrr//(({[ | |
| uurr///(({{[-++>!I,uYYYYLLLLLmmmmmmmmLLLLYYYYYuuurrr//(({[ | |
| uurr///(({{[-++>!I,uYYYYLLLLLmmmmmmmmLLLLYYYYYuuurrr//(({[ | |
| rrrr//((({[[-+~>!I,uYYYYYLLLLLmmmmmLLLLLLYYYYuuuurrr//(({[ | |
| r////((({{[--+~>l;"uuYYYYYLLLLLLLLLLLLLLYYYYYuuurrr//(({{[ | |
| ///(((({{[[-+~>!I:^uuuYYYYYYLLLLLLLLLLYYYYYYuuuurrr//(({[[ | |
| (((({{[[[-+~~!l;,'uuuuuYYYYYYYYYYYYYYYYYYuuuuurrr//(({{[- | |
| {{{{[[[--+~>!lI:^rrruuuuuYYYYYYYYYYYYYYuuuuurrrr//(({{[-+ | |
| [[[[---++~>!lI:^'/rrrruuuuuuuuYYYYuuuuuuuurrrr///(({{[-+~ | |
| ---++~~>!lI;,^'(///rrrrruuuuuuuuuuuuuurrrrr///((({{[-+~> | |
| ..................................................................................... ~~~>>!lI;:"^' (((////rrrrrrrrrrrrrrrrrr////((({{[[-+~>! | |
| ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''.>!!llI;:"^'. [{{((((//////rrrrrrrr//////(((({{[[-++~!l; | |
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^``` ;:,"^`'. --[[{{{((((((//////////((((({{{[[[-++~>!I:^ | |
| ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,""^``''. !>~~+--[[[{{{{{(((((((((({{{{{[[[--+~~>!I:"`. | |
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::^ '^":Il!>~~++---[[[[[[[[[[[[[[[[---++~~>!lI:"`. " | |
| llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllII.`^,:Il!!>~~~++++--------++++~~>>!!lI:"^'.IIll | |
| !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!:",;;Il!!!>>>>>>>>>>>>!!llI;:,"l!!!!!!!!! | |
| >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>;;;IIII;;;>>>>>>>>>>>>>>>>>>>> | |
| ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | |
| ---------------------------------------------------------------------------------------------------------------------------------------------- | |
| [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ | |
| [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ | |
| {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ |