Skip to content

Instantly share code, notes, and snippets.

@Yevano
Created January 25, 2020 23:52
Show Gist options
  • Select an option

  • Save Yevano/a48ab1cc592cccda55cef1933c73e179 to your computer and use it in GitHub Desktop.

Select an option

Save Yevano/a48ab1cc592cccda55cef1933c73e179 to your computer and use it in GitHub Desktop.
-- Rev 2
local sin = math.sin
local cos = math.cos
local tan = math.tan
local abs = math.abs
local min = math.min
local max = math.max
local floor = math.floor
local sqrt = math.sqrt
local clock = os.clock
local term_setCursorPos = term.setCursorPos
local term_blit = term.blit
local table_concat = table.concat
local STRATEGY_FULL_CELL = 0
local STRATEGY_HEX_CELL = 1
local STRATEGY_TWO_CELL = 2
local function vec2(x, y)
return { x = x, y = y }
end
local function vec3(x, y, z)
return { x = x, y = y, z = z }
end
local function vec4(x, y, z, w)
return { x = x, y = y, z = z, w = w }
end
local function length2(v)
return (v.x^2 + v.y^2)^0.5
end
local function length3(v)
return (v.x^2 + v.y^2 + v.z^2)^0.5
end
local function length4(v)
return (v.x^2 + v.y^2 + v.z^2 + v.w^2)^0.5
end
local function normalize2(v)
return div2s(v, length2(v))
end
local function normalize3(v)
return div3s(v, length3(v))
end
local function normalize4(v)
return div4s(v, length4(v))
end
local function distance2(v1, v2)
return ((v1.x - v2.x)^2 + (v1.y - v2.y)^2)^0.5
end
local function distance3(v1, v2)
return ((v1.x - v2.x)^2 + (v1.y - v2.y)^2 + (v1.z - v2.z)^2)^0.5
end
local function distance4(v1, v2)
return ((v1.x - v2.x)^2 + (v1.y - v2.y)^2 + (v1.z - v2.z)^2 + (v1.w - v2.w)^2)^0.5
end
local function dot2(v1, v2)
return v1.x*v2.x + v1.y*v2.y
end
local function dot3(v1, v2)
return v1.x*v2.x + v1.y*v2.y + v1.z*v2.z
end
local function dot4(v1, v2)
return v1.x*v2.x + v1.y*v2.y + v1.z*v2.z + v1.w*v2.w
end
local function add2(v1, v2)
return vec2(v1.x+v2.x, v1.y+v2.y)
end
local function add3(v1, v2)
return vec3(v1.x+v2.x, v1.y+v2.y, v1.z+v2.z)
end
local function add4(v1, v2)
return vec4(v1.x+v2.x, v1.y+v2.y, v1.z+v2.z, v1.w+v2.w)
end
local function sub2(v1, v2)
return vec2(v1.x-v2.x, v1.y-v2.y)
end
local function sub3(v1, v2)
return vec3(v1.x-v2.x, v1.y-v2.y, v1.z-v2.z)
end
local function sub4(v1, v2)
return vec4(v1.x-v2.x, v1.y-v2.y, v1.z-v2.z, v1.w-v2.w)
end
local function mul2(v1, v2)
return vec2(v1.x*v2.x, v1.y*v2.y)
end
local function mul3(v1, v2)
return vec3(v1.x*v2.x, v1.y*v2.y, v1.z*v2.z)
end
local function mul4(v1, v2)
return vec4(v1.x*v2.x, v1.y*v2.y, v1.z*v2.z, v1.w*v2.w)
end
local function div2(v1, v2)
return vec2(v1.x/v2.x, v1.y/v2.y)
end
local function div3(v1, v2)
return vec3(v1.x/v2.x, v1.y/v2.y, v1.z/v2.z)
end
local function div4(v1, v2)
return vec4(v1.x/v2.x, v1.y/v2.y, v1.z/v2.z, v1.w/v2.w)
end
local function add2s(v1, n)
return vec2(v1.x+n, v1.y+n)
end
local function add3s(v1, n)
return vec3(v1.x+n, v1.y+n, v1.z+n)
end
local function add4s(v1, n)
return vec4(v1.x+n, v1.y+n, v1.z+n, v1.w+n)
end
local function sub2s(v1, n)
return vec2(v1.x-n, v1.y-n)
end
local function sub3s(v1, n)
return vec3(v1.x-n, v1.y-n, v1.z-n)
end
local function sub4s(v1, n)
return vec4(v1.x-n, v1.y-n, v1.z-n, v1.w-n)
end
local function mul2s(v1, n)
return vec2(v1.x*n, v1.y*n)
end
local function mul3s(v1, n)
return vec3(v1.x*n, v1.y*n, v1.z*n)
end
local function mul4s(v1, n)
return vec4(v1.x*n, v1.y*n, v1.z*n, v1.w*n)
end
local function div2s(v1, n)
return vec2(v1.x/n, v1.y/n)
end
local function div3s(v1, n)
return vec3(v1.x/n, v1.y/n, v1.z/n)
end
local function div4s(v1, n)
return vec4(v1.x/n, v1.y/n, v1.z/n, v1.w/n)
end
local function mat2mulvec2(m, v)
return vec2(m[1] * v.x + m[2] * v.y,
m[3] * v.x + m[4] * v.y)
end
local function mat3mulvec3(m, v)
return vec3(m[1] * v.x + m[2] * v.y + m[3] * v.z,
m[4] * v.x + m[5] * v.y + m[6] * v.z,
m[7] * v.x + m[8] * v.y + m[9] * v.z)
end
local function getRotMat2(a)
return { cos(a), -sin(a), sin(a), cos(a) }
end
local function getRotMat3x(a)
return { 1, 0, 0,
0, cos(a), -sin(a),
0, sin(a), cos(a) }
end
local function getRotMat3y(a)
return { cos(a), 0, sin(a),
0, 1, 0,
-sin(a), 0, cos(a) }
end
local function getRotMat3z(a)
return { cos(a), -sin(a), 0,
sin(a), cos(a), 0,
0, 0, 1 }
end
local function fract(n)
return n - floor(n)
end
local function mix(x, y, a)
return x * (1 - a) + y * a
end
local function clamp(a, s, l)
return a < s and s or a > l and l or a
end
local function smoothstep(edge0, edge1, x)
local t = clamp((x - edge0) / (edge1 - edge0), 0, 1)
return t * t * (3 - 2 * t)
end
local function lab2xyz(lab)
local y = (lab.x + 16.0) / 116.0
local y3 = y^3.0
local x = (lab.y / 500.0) + y
local x3 = x^3.0
local z = y - (lab.z / 200.0)
local z3 = z^3.0
if y3 > 0.008856 then
y = y3
else
y = (y - (16.0 / 116.0)) / 7.787
end
if x3 > 0.008856 then
x = x3
else
x = (x - (16.0 / 116.0)) / 7.787
end
if z3 > 0.008856 then
z = z3
else
z = (z - (16.0 / 116.0)) / 7.787
end
return vec3(x * 95.0429, y * 100.0, z * 108.8900)
end
local Mi = {{ 3.2406, -1.5372, -0.4986},
{-0.9689, 1.8758, 0.0415},
{ 0.0557, -0.2040, 1.0570}}
local function xyz2rgb(xyz)
local x = xyz.x / 100.0
local y = xyz.y / 100.0
local z = xyz.z / 100.0
local r = (x * Mi[1][1]) + (y * Mi[1][2]) + (z * Mi[1][3])
local g = (x * Mi[2][1]) + (y * Mi[2][2]) + (z * Mi[2][3])
local b = (x * Mi[3][1]) + (y * Mi[3][2]) + (z * Mi[3][3])
-- assume sRGB
if r > 0.0031308 then
r = ((1.055 * r^(1.0 / 2.4)) - 0.055)
else
r = (r * 12.92)
end
if g > 0.0031308 then
g = ((1.055 * g^(1.0 / 2.4)) - 0.055)
else
g = (g * 12.92)
end
if b > 0.0031308 then
b = ((1.055 * b^(1.0 / 2.4)) - 0.055)
else
b = (b * 12.92)
end
r = (r < 0) and 0 or r
g = (g < 0) and 0 or g
b = (b < 0) and 0 or b
return vec3(r, g, b)
end
local function lab2rgb(lab)
return xyz2rgb(lab2xyz(lab))
end
local function rgb2lab(color)
-- Original code: http://www.brucelindbloom.com
-- Ported to Lua by Yevano.
local r, g, b = color.x, color.y, color.z
local X, Y, Z, fx, fy, fz, xr, yr, z
local Ls, as, bs
local eps = 216 / 24389
local k = 24389 / 27
local Xr = 0.964221 -- reference white D50
local Yr = 1
local Zr = 0.825211
-- assuming sRGB (D65)
if r <= 0.04045 then
r = r / 12
else
r = ((r + 0.055) / 1.055)^2.4
end
if g <= 0.04045 then
g = g / 12
else
g = ((g + 0.055) / 1.055)^2.4
end
if b <= 0.04045 then
b = b / 12
else
b = ((b + 0.055) / 1.055)^2.4
end
X = 0.436052025 * r + 0.385081593 * g + 0.143087414 * b
Y = 0.222491598 * r + 0.71688606 * g + 0.060621486 * b
Z = 0.013929122 * r + 0.097097002 * g + 0.71418547 * b
-- XYZ to Lab
xr = X / Xr
yr = Y / Yr
zr = Z / Zr
if xr > eps then
fx = xr^(1 / 3)
else
fx = ((k * xr + 16.) / 116.)
end
if yr > eps then
fy = yr^(1 / 3)
else
fy = ((k * yr + 16.) / 116.)
end
if zr > eps then
fz = zr^(1 / 3)
else
fz = ((k * zr + 16.) / 116)
end
Ls = (116 * fy) - 16
as = 500 * (fx - fy)
bs = 200 * (fy - fz)
return vec3(2.55 * Ls + .5, as + .5, bs + .5)
end
local function colorDistance(c1, c2)
local lab1 = rgb2lab(c1)
local lab2 = rgb2lab(c2)
return distance3(lab1, lab2)
end
local function createPalette(indexTable, redPal, greenPal, bluePal, ldFunc)
ldFunc = ldFunc or function() return 0.1 end
local colorTable = { }
local pal = {
indexTable = indexTable,
colorTable = colorTable,
redPal = redPal,
greenPal = greenPal,
bluePal = bluePal
}
local s = os.clock()
for r = 0, redPal - 1 do
colorTable[r] = { }
for g = 0, greenPal - 1 do
colorTable[r][g] = { }
for b = 0, bluePal - 1 do
local minDist = 9999
local entry
for i = 1, #indexTable do
local dist = colorDistance(vec3(r/(redPal-1), g/(greenPal-1), b/(bluePal-1)), indexTable[i])
if dist < minDist then
minDist = dist
entry = i
end
end
colorTable[r][g][b] = entry
end
end
if os.clock() - s > ldFunc((r*greenPal*bluePal)/(redPal*greenPal*bluePal)) then
sleep(0)
s = os.clock()
end
end
return pal
end
local function paletteConvert(palette, color)
local x = color.x < 0 and 0 or color.x > 1 and 1 or color.x
local y = color.y < 0 and 0 or color.y > 1 and 1 or color.y
local z = color.z < 0 and 0 or color.z > 1 and 1 or color.z
local r = floor(x * palette.redPal)
local g = floor(y * palette.greenPal)
local b = floor(z * palette.bluePal)
if r == palette.redPal then r = r - 1 end
if g == palette.greenPal then g = g - 1 end
if b == palette.bluePal then b = b - 1 end
local i = palette.colorTable[r][g][b]
return i
end
local function createShaderProgram()
local prog = {
shaders = { }
}
return prog
end
local function addShader(program, shader)
program.shaders[#program.shaders + 1] = shader
end
local function applyShaderProgram(program, frameBuffer)
local pixelData = frameBuffer.pixelData
local w = frameBuffer.size.x
local h = frameBuffer.size.y
for i = 1, #program.shaders do
local shaderFunc = program.shaders[i].shaderFunc
local inputs = program.shaders[i].inputs
for x = 1, w do
for y = 1, h do
pixelData[x + (y - 1) * w] = shaderFunc(vec4(pixelData[x + (y - 1) * w]), vec2((x - 1), h - y), inputs)
end
end
end
end
local function createShader(shaderFunc)
local shader = {
shaderFunc = shaderFunc,
inputs = { }
}
return shader
end
local function setShaderInput(shader, i, v)
shader.inputs[i] = v
end
local function createFrameBuffer(palette, charTable, size, renderStrategy, blit, scp)
renderStrategy = renderStrategy or STRATEGY_FULL_CELL
if renderStrategy == STRATEGY_HEX_CELL and (size.x % 2 ~= 0 or size.y % 3 ~= 0) then
error("Frame Buffer using STRATEGY_HEX_CELL must have width multiple of 2 and height multiple of 3.")
end
if renderStrategy == STRATEGY_TWO_CELL then
error("STRATEGY_TWO_CELL not yet implemented.")
end
local pixelData = { }
local buf = {
palette = palette,
charTable = charTable,
size = size,
pixelData = pixelData,
renderStrategy = renderStrategy,
blit = blit or term_blit,
scp = scp or term_setCursorPos
}
for i = 1, size.x * size.y do
pixelData[i] = vec4(0, 0, 0, 0)
end
return buf
end
-- Thanks for writing this useful function, oli414.
local function getDrawingCharacter(topLeft, topRight, left, right, bottomLeft, bottomRight)
local data = 128
if not bottomRight then
data = data + (topLeft and 1 or 0)
data = data + (topRight and 2 or 0)
data = data + (left and 4 or 0)
data = data + (right and 8 or 0)
data = data + (bottomLeft and 16 or 0)
else
data = data + (topLeft and 0 or 1)
data = data + (topRight and 0 or 2)
data = data + (left and 0 or 4)
data = data + (right and 0 or 8)
data = data + (bottomLeft and 0 or 16)
end
return string.char(data), bottomRight
end
local function drawFrameBuffer(buf, pos)
local w, h = buf.size.x, buf.size.y
local x, y = pos.x, pos.y
local pixelData = buf.pixelData
local palette = buf.palette
local charTable = buf.charTable
local blit = buf.blit
local scp = buf.scp
if buf.renderStrategy == STRATEGY_FULL_CELL then
for i = y, y + h - 1 do
local s = { }
local b = { }
local f = { }
for j = (i-1)*w + 1, i*w do
local colIdx = paletteConvert(palette, pixelData[j])
local charEntry = charTable[colIdx]
s[#s + 1] = charEntry[1]
b[#b + 1] = charEntry[2]
f[#f + 1] = charEntry[3]
end
scp(x, i)
blit(table_concat(s), table_concat(f), table_concat(b))
end
elseif buf.renderStrategy == STRATEGY_HEX_CELL then
for sy = 0, h-1, 3 do
local s = { }
local b = { }
local f = { }
for sx = 0, w-1, 2 do
local uniqueColors = { }
local colorCounts = { }
local convColors = { }
for j = 0, 2 do
for i = 0, 1 do
local col = charTable[paletteConvert(palette, pixelData[sx+i + (sy+j) * w + 1])][2]
convColors[#convColors + 1] = col
if colorCounts[col] then
colorCounts[col] = colorCounts[col] + 1
else
colorCounts[col] = 1
uniqueColors[#uniqueColors + 1] = col
end
end
end
table.sort(uniqueColors, function(a, b) return colorCounts[a] > colorCounts[b] end)
local c0 = uniqueColors[1]
local c1 = uniqueColors[2] or c0
local char, inv = getDrawingCharacter(
convColors[1] ~= c1,
convColors[2] ~= c1,
convColors[3] ~= c1,
convColors[4] ~= c1,
convColors[5] ~= c1,
convColors[6] ~= c1)
s[#s + 1] = char
if inv then
b[#b + 1] = c0
f[#f + 1] = c1
else
b[#b + 1] = c1
f[#f + 1] = c0
end
end
scp(x, y + sy/3)
blit(table_concat(s), table_concat(f), table_concat(b))
end
elseif buf.renderStrategy == STRATEGY_TWO_CELL then
error("STRATEGY_TWO_CELL not yet implemented.")
end
end
local function getUnstretchedResolution(buf)
return vec2(buf.size.x, buf.size.y * 3/2)
end
local function clearFrameBuffer(buf, color)
local pixelData = buf.pixelData
for i = 1, #pixelData do
pixelData[i] = color
end
end
local g = getfenv()
g.STRATEGY_FULL_CELL = STRATEGY_FULL_CELL
g.STRATEGY_HEX_CELL = STRATEGY_HEX_CELL
g.STRATEGY_TWO_CELL = STRATEGY_TWO_CELL
g.vec2 = vec2
g.vec3 = vec3
g.vec4 = vec4
g.length2 = length2
g.length3 = length3
g.length4 = length4
g.normalize2 = normalize2
g.normalize3 = normalize3
g.normalize4 = normalize4
g.distance2 = distance2
g.distance3 = distance3
g.distance4 = distance4
g.dot2 = dot2
g.dot3 = dot3
g.dot4 = dot4
g.add2 = add2
g.add3 = add3
g.add4 = add4
g.sub2 = sub2
g.sub3 = sub3
g.sub4 = sub4
g.mul2 = mul2
g.mul3 = mul3
g.mul4 = mul4
g.div2 = div2
g.div3 = div3
g.div4 = div4
g.add2s = add2s
g.add3s = add3s
g.add4s = add4s
g.sub2s = sub2s
g.sub3s = sub3s
g.sub4s = sub4s
g.mul2s = mul2s
g.mul3s = mul3s
g.mul4s = mul4s
g.div2s = div2s
g.div3s = div3s
g.div4s = div4s
g.mat2mulvec2 = mat2mulvec2
g.mat3mulvec3 = mat3mulvec3
g.getRotMat2 = getRotMat2
g.getRotMat3x = getRotMat3x
g.getRotMat3y = getRotMat3y
g.getRotMat3z = getRotMat3z
g.fract = fract
g.mix = mix
g.clamp = clamp
g.smoothstep = smoothstep
g.lab2xyz = lab2xyz
g.xyz2rgb = xyz2rgb
g.lab2rgb = lab2rgb
g.rgb2lab = rgb2lab
g.colorDistance = colorDistance
g.createPalette = createPalette
g.paletteConvert = paletteConvert
g.createShaderProgram = createShaderProgram
g.addShader = addShader
g.applyShaderProgram = applyShaderProgram
g.createShader = createShader
g.setShaderInput = setShaderInput
g.createFrameBuffer = createFrameBuffer
g.drawFrameBuffer = drawFrameBuffer
g.getUnstretchedResolution = getUnstretchedResolution
g.clearFrameBuffer = clearFrameBuffer
os.loadAPI("gfx")
-- For convenience.
local sin = math.sin
local cos = math.cos
local tan = math.tan
local abs = math.abs
local min = math.min
local max = math.max
local floor = math.floor
local sqrt = math.sqrt
local clock = os.clock
-- I got lazy so I just localized all of
-- these functions here.
local STRATEGY_FULL_CELL = gfx.STRATEGY_FULL_CELL
local STRATEGY_HEX_CELL = gfx.STRATEGY_HEX_CELL
local STRATEGY_TWO_CELL = gfx.STRATEGY_TWO_CELL
local vec2 = gfx.vec2
local vec3 = gfx.vec3
local vec4 = gfx.vec4
local length2 = gfx.length2
local length3 = gfx.length3
local length4 = gfx.length4
local normalize2 = gfx.normalize2
local normalize3 = gfx.normalize3
local normalize4 = gfx.normalize4
local distance2 = gfx.distance2
local distance3 = gfx.distance3
local distance4 = gfx.distance4
local dot2 = gfx.dot2
local dot3 = gfx.dot3
local dot4 = gfx.dot4
local add2 = gfx.add2
local add3 = gfx.add3
local add4 = gfx.add4
local sub2 = gfx.sub2
local sub3 = gfx.sub3
local sub4 = gfx.sub4
local mul2 = gfx.mul2
local mul3 = gfx.mul3
local mul4 = gfx.mul4
local div2 = gfx.div2
local div3 = gfx.div3
local div4 = gfx.div4
local add2s = gfx.add2s
local add3s = gfx.add3s
local add4s = gfx.add4s
local sub2s = gfx.sub2s
local sub3s = gfx.sub3s
local sub4s = gfx.sub4s
local mul2s = gfx.mul2s
local mul3s = gfx.mul3s
local mul4s = gfx.mul4s
local div2s = gfx.div2s
local div3s = gfx.div3s
local div4s = gfx.div4s
local mat2mulvec2 = gfx.mat2mulvec2
local mat3mulvec3 = gfx.mat3mulvec3
local getRotMat2 = gfx.getRotMat2
local getRotMat3x = gfx.getRotMat3x
local getRotMat3y = gfx.getRotMat3y
local getRotMat3z = gfx.getRotMat3z
local fract = gfx.fract
local mix = gfx.mix
local clamp = gfx.clamp
local smoothstep = gfx.smoothstep
local lab2xyz = gfx.lab2xyz
local xyz2rgb = gfx.xyz2rgb
local lab2rgb = gfx.lab2rgb
local rgb2lab = gfx.rgb2lab
local colorDistance = gfx.colorDistance
local createPalette = gfx.createPalette
local paletteConvert = gfx.paletteConvert
local createShaderProgram = gfx.createShaderProgram
local addShader = gfx.addShader
local applyShaderProgram = gfx.applyShaderProgram
local createShader = gfx.createShader
local setShaderInput = gfx.setShaderInput
local createFrameBuffer = gfx.createFrameBuffer
local drawFrameBuffer = gfx.drawFrameBuffer
local getUnstretchedResolution = gfx.getUnstretchedResolution
local clearFrameBuffer = gfx.clearFrameBuffer
-- This table contains the set of pixels we
-- draw to our frame buffer. In this case,
-- we will just use all the colors with no
-- foreground text.
local charTable = {
{" ", "0", "0"},
{" ", "1", "0"},
{" ", "2", "0"},
{" ", "3", "0"},
{" ", "4", "0"},
{" ", "5", "0"},
{" ", "6", "0"},
{" ", "7", "0"},
{" ", "8", "0"},
{" ", "9", "0"},
{" ", "a", "0"},
{" ", "b", "0"},
{" ", "c", "0"},
{" ", "d", "0"},
{" ", "e", "0"},
{" ", "f", "0"}
}
-- This table contains the colors for each
-- pixel in charTable. e.g., index 0 is used
-- for colors.white.
local indexTable = {
vec3(0xF0/0xFF, 0xF0/0xFF, 0xF0/0xFF),
vec3(0xF2/0xFF, 0xB2/0xFF, 0x33/0xFF),
vec3(0xE5/0xFF, 0x7F/0xFF, 0xD8/0xFF),
vec3(0x99/0xFF, 0xB2/0xFF, 0xF2/0xFF),
vec3(0xDE/0xFF, 0xDE/0xFF, 0x6C/0xFF),
vec3(0x7F/0xFF, 0xCC/0xFF, 0x19/0xFF),
vec3(0xF2/0xFF, 0xB2/0xFF, 0xCC/0xFF),
vec3(0x4C/0xFF, 0x4C/0xFF, 0x4C/0xFF),
vec3(0x99/0xFF, 0x99/0xFF, 0x99/0xFF),
vec3(0x4C/0xFF, 0x99/0xFF, 0xB2/0xFF),
vec3(0xB2/0xFF, 0x66/0xFF, 0xE5/0xFF),
vec3(0x33/0xFF, 0x66/0xFF, 0xCC/0xFF),
vec3(0x7F/0xFF, 0x66/0xFF, 0x4C/0xFF),
vec3(0x57/0xFF, 0xA6/0xFF, 0x4E/0xFF),
vec3(0xCC/0xFF, 0x4C/0xFF, 0x4C/0xFF),
vec3(0x19/0xFF, 0x19/0xFF, 0x19/0xFF)
}
-- Note that the above two tables must
-- correspond by index.
local function progressHook(prog)
term.clear()
term.setCursorPos(1, 1)
print("Generating color palette... " .. tostring(prog * 100) .. "%")
return 0.1
end
local function Object(_type)
local self = { }
local m_type = _type
local function type()
return m_type
end
self.type = type
return self
end
local len = 1
local blocks = { }
local function blockExists(x, y, z)
local a = blocks[x]
if not a then return false end
local b = a[y]
if not b then return false end
local c = b[z]
if not c then return false end
return true
end
local function getBlock(x, y, z)
if blockExists(x, y, z) then return blocks[x][y][z] end
end
local function setBlock(x, y, z, value)
local a = blocks[x]
if not a then
blocks[x] = { [y] = { [z] = value } }
return
end
local b = a[y]
if not b then
a[y] = { [z] = value }
return
end
b[z] = value
end
local function clearBlocks()
blocks = { }
end
local blockLook
local function Keyboard()
local self = Object(Keyboard)
local m_keysDown
do
m_keysDown = { }
for i = 0, 255 do
m_keysDown[i] = false
end
end
local function getKeyDown(key)
return m_keysDown[key]
end
local function setKeyDown(key, state)
m_keysDown[key] = state
end
self.getKeyDown = getKeyDown
self.setKeyDown = setKeyDown
return self
end
local keyboard = Keyboard()
local function Vec4_eq(u, v)
return u.x() == v.x() and u.y() == v.y() and u.z() == v.z() and u.w() == v.w()
end
local function Vec4(_x, _y, _z, _w)
local self = Object(Vec4)
local m_x = _x or 0
local m_y = _y or 0
local m_z = _z or 0
local m_w = _w or 0
local function x(_x)
m_x = _x or m_x
return m_x
end
local function y(_y)
m_y = _y or m_y
return m_y
end
local function z(_z)
m_z = _z or m_z
return m_z
end
local function w(_w)
m_w = _w or m_w
return m_w
end
local function neg()
return Vec4(-m_x, -m_y, -m_z, -m_w)
end
local function add(_, v)
return Vec4(m_x + v.x(), m_y + v.y(), m_z + v.z(), m_w + v.w())
end
local function sub(_, v)
return Vec4(m_x - v.x(), m_y - v.y(), m_z - v.z(), m_w - v.w())
end
local function mul(_, s)
return Vec4(m_x * s, m_y * s, m_z * s, m_w * s)
end
local function div(_, s)
return Vec4(m_x / s, m_y / s, m_z / s, m_w / s)
end
local function lerp(dest, lerpFactor)
return (dest - self) * lerpFactor + self
end
local function length()
return math.sqrt(self.dot(self))
end
local function normalized()
return self/length()
end
local function rotateQuat(rotation)
local conjugate = rotation.conjugate();
local w = rotation * self * conjugate;
return Vec4(w.x(), w.y(), w.z(), 1);
end
local function dot(r)
return m_x*r.x() + m_y*r.y() + m_z*r.z() + m_w*r.w()
end
self.x = x
self.y = y
self.z = z
self.w = w
self.lerp = lerp
self.length = length
self.normalized = normalized
self.rotateQuat = rotateQuat
self.dot = dot
return setmetatable(self,
{ __add = add, __sub = sub, __mul = mul, __div = div, __unm = neg, __eq = Vec4_eq })
end
local function Mat4()
local self = Object(Mat4)
local m_m =
{{0,0,0,0},
{0,0,0,0},
{0,0,0,0},
{0,0,0,0}}
local function m(_m)
m_m = _m or m_m
return m_m
end
local function copy(src)
m_m[1][1] = src.m()[1][1] m_m[1][2] = src.m()[1][2] m_m[1][3] = src.m()[1][3] m_m[1][4] = src.m()[1][4]
m_m[2][1] = src.m()[2][1] m_m[2][2] = src.m()[2][2] m_m[2][3] = src.m()[2][3] m_m[2][4] = src.m()[2][4]
m_m[3][1] = src.m()[3][1] m_m[3][2] = src.m()[3][2] m_m[3][3] = src.m()[3][3] m_m[3][4] = src.m()[3][4]
m_m[4][1] = src.m()[4][1] m_m[4][2] = src.m()[4][2] m_m[4][3] = src.m()[4][3] m_m[4][4] = src.m()[4][4]
return self
end
local function initIdentity()
m_m[1][1] = 1 m_m[1][2] = 0 m_m[1][3] = 0 m_m[1][4] = 0
m_m[2][1] = 0 m_m[2][2] = 1 m_m[2][3] = 0 m_m[2][4] = 0
m_m[3][1] = 0 m_m[3][2] = 0 m_m[3][3] = 1 m_m[3][4] = 0
m_m[4][1] = 0 m_m[4][2] = 0 m_m[4][3] = 0 m_m[4][4] = 1
return self
end
local function initScreenSpaceTransform(halfWidth, halfHeight)
m_m[1][1] = halfWidth m_m[1][2] = 0 m_m[1][3] = 0 m_m[1][4] = halfWidth - 0.5
m_m[2][1] = 0 m_m[2][2] = -halfHeight m_m[2][3] = 0 m_m[2][4] = halfHeight - 0.5
m_m[3][1] = 0 m_m[3][2] = 0 m_m[3][3] = 1 m_m[3][4] = 0
m_m[4][1] = 0 m_m[4][2] = 0 m_m[4][3] = 0 m_m[4][4] = 1
return self
end
local function initTranslation(x, y, z)
m_m[1][1] = 1 m_m[1][2] = 0 m_m[1][3] = 0 m_m[1][4] = x
m_m[2][1] = 0 m_m[2][2] = 1 m_m[2][3] = 0 m_m[2][4] = y
m_m[3][1] = 0 m_m[3][2] = 0 m_m[3][3] = 1 m_m[3][4] = z
m_m[4][1] = 0 m_m[4][2] = 0 m_m[4][3] = 0 m_m[4][4] = 1
return self
end
local function transform(r)
return
Vec4(m_m[1][1] * r.x() + m_m[1][2] * r.y() + m_m[1][3] * r.z() + m_m[1][4] * r.w(),
m_m[2][1] * r.x() + m_m[2][2] * r.y() + m_m[2][3] * r.z() + m_m[2][4] * r.w(),
m_m[3][1] * r.x() + m_m[3][2] * r.y() + m_m[3][3] * r.z() + m_m[3][4] * r.w(),
m_m[4][1] * r.x() + m_m[4][2] * r.y() + m_m[4][3] * r.z() + m_m[4][4] * r.w())
end
local function mul(_, r)
local res = Mat4()
local resm = res.m()
r = r.m()
for i = 1, 4 do
for j = 1, 4 do
resm[i][j] =
m_m[i][1] * r[1][j] +
m_m[i][2] * r[2][j] +
m_m[i][3] * r[3][j] +
m_m[i][4] * r[4][j]
end
end
return res
end
local function initScale(x, y, z)
m_m[1][1] = x; m_m[1][2] = 0; m_m[1][3] = 0; m_m[1][4] = 0;
m_m[2][1] = 0; m_m[2][2] = y; m_m[2][3] = 0; m_m[2][4] = 0;
m_m[3][1] = 0; m_m[3][2] = 0; m_m[3][3] = z; m_m[3][4] = 0;
m_m[4][1] = 0; m_m[4][2] = 0; m_m[4][3] = 0; m_m[4][4] = 1;
return self;
end
local function initRotation(x, y, z, angle)
local sin = math.sin(angle)
local cos = math.cos(angle)
m[1][1] = cos+x*x*(1-cos) m[1][2] = x*y*(1-cos)-z*sin m[1][3] = x*z*(1-cos)+y*sin m[1][4] = 0
m[2][1] = y*x*(1-cos)+z*sin m[2][2] = cos+y*y*(1-cos) m[2][3] = y*z*(1-cos)-x*sin m[2][4] = 0
m[3][1] = z*x*(1-cos)-y*sin m[3][2] = z*y*(1-cos)+x*sin m[3][3] = cos+z*z*(1-cos) m[3][4] = 0
m[4][1] = 0 m[4][2] = 0 m[4][3] = 0 m[4][4] = 1
return self
end
local function initRotation3(x, y, z)
local rx = Mat4()
local ry = Mat4()
local rz = Mat4()
rz.m()[1][1] = math.cos(z) rz.m()[1][2] = -math.sin(z) rz.m()[1][3] = 0 rz.m()[1][4] = 0
rz.m()[2][1] = math.sin(z) rz.m()[2][2] = math.cos(z) rz.m()[2][3] = 0 rz.m()[2][4] = 0
rz.m()[3][1] = 0 rz.m()[3][2] = 0 rz.m()[3][3] = 1 rz.m()[3][4] = 0
rz.m()[4][1] = 0 rz.m()[4][2] = 0 rz.m()[4][3] = 0 rz.m()[4][4] = 1
rx.m()[1][1] = 1 rx.m()[1][2] = 0 rx.m()[1][3] = 0 rx.m()[1][4] = 0
rx.m()[2][1] = 0 rx.m()[2][2] = math.cos(x) rx.m()[2][3] = -math.sin(x) rx.m()[2][4] = 0
rx.m()[3][1] = 0 rx.m()[3][2] = math.sin(x) rx.m()[3][3] = math.cos(x) rx.m()[3][4] = 0
rx.m()[4][1] = 0 rx.m()[4][2] = 0 rx.m()[4][3] = 0 rx.m()[4][4] = 1
ry.m()[1][1] = math.cos(y) ry.m()[1][2] = 0 ry.m()[1][3] = -math.sin(y) ry.m()[1][4] = 0
ry.m()[2][1] = 0 ry.m()[2][2] = 1 ry.m()[2][3] = 0 ry.m()[2][4] = 0
ry.m()[3][1] = math.sin(y) ry.m()[3][2] = 0 ry.m()[3][3] = math.cos(y) ry.m()[3][4] = 0
ry.m()[4][1] = 0 ry.m()[4][2] = 0 ry.m()[4][3] = 0 ry.m()[4][4] = 1
m_m = (rx * ry * rz).m()
return self
end
local function initPerspective(fov, aspectRatio, zNear, zFar)
local tanHalfFOV = math.tan(fov / 2)
local zRange = zNear - zFar
m_m[1][1] = 1 / (tanHalfFOV * aspectRatio) m_m[1][2] = 0 m_m[1][3] = 0 m_m[1][4] = 0
m_m[2][1] = 0 m_m[2][2] = 1 / tanHalfFOV m_m[2][3] = 0 m_m[2][4] = 0
m_m[3][1] = 0 m_m[3][2] = 0 m_m[3][3] = (-zNear - zFar)/zRange m_m[3][4] = 2 * zFar * zNear / zRange
m_m[4][1] = 0 m_m[4][2] = 0 m_m[4][3] = 1 m_m[4][4] = 0
return self
end
local function initRotationFUR(f, u, r)
m_m[1][1] = r.x() m_m[1][2] = r.y() m_m[1][3] = r.z() m_m[1][4] = 0
m_m[2][1] = u.x() m_m[2][2] = u.y() m_m[2][3] = u.z() m_m[2][4] = 0
m_m[3][1] = f.x() m_m[3][2] = f.y() m_m[3][3] = f.z() m_m[3][4] = 0
m_m[4][1] = 0 m_m[4][2] = 0 m_m[4][3] = 0 m_m[4][4] = 1
return self
end
self.m = m
self.copy = copy
self.initIdentity = initIdentity
self.initScreenSpaceTransform = initScreenSpaceTransform
self.initTranslation = initTranslation
self.transform = transform
self.initScale = initScale
self.initRotation3 = initRotation3
self.initPerspective = initPerspective
self.initRotationFUR = initRotationFUR
return setmetatable(self, {
__mul = mul })
end
local function Quaternion()
local self = Object(Quaternion)
local m_x
local m_y
local m_z
local m_w
local function x(_x)
m_x = _x or m_x
return m_x
end
local function y(_y)
m_y = _y or m_y
return m_y
end
local function z(_z)
m_z = _z or m_z
return m_z
end
local function w(_w)
m_w = _w or m_w
return m_w
end
local function initComponents(_x, _y, _z, _w)
m_x = _x
m_y = _y
m_z = _z
m_w = _w
return self
end
local function initAxisAngle(axis, angle)
local sinHalfAngle = math.sin(angle/2)
local cosHalfAngle = math.cos(angle/2)
m_x = axis.x() * sinHalfAngle
m_y = axis.y() * sinHalfAngle
m_z = axis.z() * sinHalfAngle
m_w = cosHalfAngle
return self
end
local function initMatrix(rot)
local trace = rot.m()[1][1] + rot.m()[2][2] + rot.m()[3][3]
if trace > 0 then
local s = 0.5 / math.sqrt(trace + 1)
m_w = 0.25 / s
m_x = (rot.m()[2][3] - rot.m()[3][2]) * s
m_y = (rot.m()[3][1] - rot.m()[1][3]) * s
m_z = (rot.m()[1][2] - rot.m()[2][1]) * s
else -- BELOW INC
if rot.m()[1][1] > rot.m()[2][2] and rot.m()[1][1] > rot.m()[3][3] then
local s = 2 * math.sqrt(1 + rot.m()[1][1] - rot.m()[2][2] - rot.m()[3][3])
m_w = (rot.m()[2][3] - rot.m()[3][2]) / s
m_x = 0.25 * s
m_y = (rot.m()[2][1] + rot.m()[1][2]) / s
m_z = (rot.m()[3][1] + rot.m()[1][3]) / s
elseif rot.m()[2][2] > rot.m()[3][3] then
local s = 2 * math.sqrt(1 + rot.m()[2][2] - rot.m()[1][1] - rot.m()[3][3])
m_w = (rot.m()[3][1] - rot.m()[1][3]) / s
m_x = (rot.m()[2][1] + rot.m()[1][2]) / s
m_y = 0.25 * s
m_z = (rot.m()[3][2] + rot.m()[2][3]) / s
else
local s = 2 * math.sqrt(1 + rot.m()[3][3] - rot.m()[1][1] - rot.m()[2][2])
m_w = (rot.m()[1][2] - rot.m()[2][1] ) / s
m_x = (rot.m()[3][1] + rot.m()[1][3] ) / s
m_y = (rot.m()[2][3] + rot.m()[3][2] ) / s
m_z = 0.25 * s
end
end
local length = math.sqrt(m_x * m_x + m_y * m_y + m_z * m_z + m_w * m_w)
m_x = m_x/length
m_y = m_y/length
m_z = m_z/length
m_w = m_w/length
return self
end
local function length()
return math.sqrt(m_x * m_x + m_y * m_y + m_z * m_z + m_w * m_w)
end
local function normalized()
local len = length()
return Quaternion().initComponents(m_x / len, m_y / len, m_z / len, m_w / len)
end
local function conjugate()
return Quaternion().initComponents(-m_x, -m_y, -m_z, m_w)
end
local function toRotationMatrix()
local forward = Vec4(2 * (m_x * m_z - m_w * m_y), 2 * (m_y * m_z + m_w * m_x), 1 - 2 * (m_x * m_x + m_y * m_y))
local up = Vec4(2 * (m_x * m_y + m_w * m_z), 1 - 2 * (m_x * m_x + m_z * m_z), 2 * (m_y * m_z - m_w * m_x))
local right = Vec4(1 - 2 * (m_y * m_y + m_z * m_z), 2 * (m_x * m_y - m_w * m_z), 2 * (m_x * m_z + m_w * m_y))
return Mat4().initRotationFUR(forward, up, right)
end
local function mulVec(r)
local w = -m_x * r.x() - m_y * r.y() - m_z * r.z()
local x = m_w * r.x() + m_y * r.z() - m_z * r.y()
local y = m_w * r.y() + m_z * r.x() - m_x * r.z()
local z = m_w * r.z() + m_x * r.y() - m_y * r.x()
return Quaternion().initComponents(x, y, z, w)
end
local function mulQuat(r)
local w = m_w * r.w() - m_x * r.x() - m_y * r.y() - m_z * r.z()
local x = m_x * r.w() + m_w * r.x() + m_y * r.z() - m_z * r.y()
local y = m_y * r.w() + m_w * r.y() + m_z * r.x() - m_x * r.z()
local z = m_z * r.w() + m_w * r.z() + m_x * r.y() - m_y * r.x()
return Quaternion().initComponents(x, y, z, w)
end
local function mul(_, r)
if r.type() == Vec4 then
return mulVec(r)
elseif r.type() == Quaternion then
return mulQuat(r)
end
end
local function getForward()
return Vec4(0,0,1,1).rotateQuat(self)
end
local function getBack()
return Vec4(0,0,-1,1).rotateQuat(self)
end
local function getUp()
return Vec4(0,1,0,1).rotateQuat(self)
end
local function getDown()
return Vec4(0,-1,0,1).rotateQuat(self)
end
local function getRight()
return Vec4(1,0,0,1).rotateQuat(self)
end
local function getLeft()
return Vec4(-1,0,0,1).rotateQuat(self)
end
self.initComponents = initComponents
self.initAxisAngle = initAxisAngle
self.initMatrix = initMatrix
self.length = length
self.normalized = normalized
self.conjugate = conjugate
self.toRotationMatrix = toRotationMatrix
self.x = x
self.y = y
self.z = z
self.w = w
self.getForward = getForward
self.getBack = getBack
self.getUp = getUp
self.getDown = getDown
self.getRight = getRight
self.getLeft = getLeft
return setmetatable(self, {
__mul = mul })
end
local function Transform(_pos, _rot, _scale)
local self = Object(Transform)
local m_pos = _pos or Vec4(0, 0, 0, 0)
local m_rot = _rot or Quaternion().initComponents(0, 0, 0, 1)
local m_scale = _scale or Vec4(1, 1, 1, 1)
local function rotate(rotation)
return Transform(m_pos, (rotation * m_rot).normalized(), m_scale)
end
local function getTransformedPos()
return m_pos
end
local function getTransformedRot()
return m_rot
end
local function getPos()
return m_pos
end
local function getRot()
return m_rot
end
local function setPos(pos)
return Transform(pos, m_rot, m_scale)
end
self.rotate = rotate
self.getTransformedPos = getTransformedPos
self.getTransformedRot = getTransformedRot
self.getPos = getPos
self.getRot = getRot
self.setPos = setPos
return self
end
local function Camera(_projection)
local self = Object(Camera)
local Y_AXIS = Vec4(0, 1, 0)
local m_transform = Transform()
local m_projection = _projection
local function getTransform()
return m_transform
end
local function getViewProjection()
local cameraRotation = m_transform.getTransformedRot().conjugate().toRotationMatrix()
local cameraPos = -m_transform.getTransformedPos()
local cameraTranslation = Mat4().initTranslation(cameraPos.x(), cameraPos.y(), cameraPos.z())
return m_projection * cameraRotation * cameraTranslation
end
local function move(dir, amt)
m_transform = m_transform.setPos(m_transform.getPos() + dir * amt)
end
local function rotate(axis, angle)
m_transform = m_transform.rotate(Quaternion().initAxisAngle(axis, angle))
end
local function update(keyboard)
local moveSpeed = 0.4
local rotSpeed = 0.1
if keyboard.getKeyDown(keys.w) then
move(m_transform.getRot().getForward(), moveSpeed)
end
if keyboard.getKeyDown(keys.s) then
move(m_transform.getRot().getForward(), -moveSpeed)
end
if keyboard.getKeyDown(keys.a) then
move(m_transform.getRot().getLeft(), moveSpeed)
end
if keyboard.getKeyDown(keys.d) then
move(m_transform.getRot().getRight(), moveSpeed)
end
if keyboard.getKeyDown(keys.space) then
move(m_transform.getRot().getUp(), moveSpeed)
end
if keyboard.getKeyDown(keys.leftCtrl) then
move(m_transform.getRot().getDown(), moveSpeed)
end
if keyboard.getKeyDown(keys.right) then
rotate(Y_AXIS, rotSpeed)
end
if keyboard.getKeyDown(keys.left) then
rotate(Y_AXIS, -rotSpeed)
end
if keyboard.getKeyDown(keys.up) then
rotate(m_transform.getRot().getRight(), rotSpeed)
end
if keyboard.getKeyDown(keys.down) then
rotate(m_transform.getRot().getRight(), -rotSpeed)
end
if keyboard.getKeyDown(keys.b) then
if blockLook then
local x = blockLook.x()
local y = blockLook.y()
local z = blockLook.z()
setBlock(x, y, z, nil)
end
end
end
self.getTransform = getTransform
self.getViewProjection = getViewProjection
self.move = move
self.rotate = rotate
self.update = update
return self
end
local function Vert(_pos, _texCoords, _normal)
local self = Object(Vert)
local m_pos = _pos
local m_texCoords = _texCoords
local m_normal = _normal
local function pos(_pos)
m_pos = _pos or m_pos
return m_pos
end
local function texCoords(_color)
m_texCoords = _texCoords or m_texCoords
return m_texCoords
end
local function normal(_normal)
m_normal = _normal or m_normal
return m_normal
end
local function transform(transform)
return Vert(transform.transform(m_pos), m_texCoords, m_normal)
end
local function perspectiveDivide(v)
return Vert(Vec4(m_pos.x()/m_pos.w(), m_pos.y()/m_pos.w(), m_pos.z()/m_pos.w(), m_pos.w()), m_texCoords, m_normal)
end
local function lerp(other, lerpAmt)
return Vert(
m_pos.lerp(other.pos(), lerpAmt),
m_texCoords.lerp(other.texCoords(), lerpAmt)
--[[,m_normal.lerp(other.normal(), lerpAmt)]])
end
local function isInsideViewFrustum()
return
math.abs(m_pos.x()) <= math.abs(m_pos.w()) and
math.abs(m_pos.y()) <= math.abs(m_pos.w()) and
math.abs(m_pos.z()) <= math.abs(m_pos.w())
end
local function get(index)
if index == 0 then
return m_pos.x()
elseif index == 1 then
return m_pos.y()
elseif index == 2 then
return m_pos.z()
elseif index == 3 then
return m_pos.w()
end
end
self.pos = pos
self.texCoords = texCoords
self.transform = transform
self.perspectiveDivide = perspectiveDivide
self.lerp = lerp
self.isInsideViewFrustum = isInsideViewFrustum
self.get = get
self.normal = normal
return self
end
local function Edge(gradients, minYVert, maxYVert, minYVertIndex)
local self = Object(Edge)
local m_x
local m_xStep
local m_yStart
local m_yEnd
local m_texCoordX
local m_texCoordXStep
local m_texCoordY
local m_texCoordYStep
local m_oneOverZ
local m_oneOverZStep
local m_depth
local m_depthStep
--local m_light
--local m_lightStep
local m_lastX = 0
local function x(_x)
m_x = _x or m_x
return m_x
end
local function yStart(_yStart)
m_yStart = _yStart or m_yStart
return m_yStart
end
local function yEnd(_yEnd)
m_yEnd = _yEnd or m_yEnd
return m_yEnd
end
local function texCoordX(_texCoordX)
m_texCoordX = _texCoordX or m_texCoordX
return m_texCoordX
end
local function texCoordXStep(_texCoordXStep)
m_texCoordXStep = _texCoordXStep or m_texCoordXStep
return m_texCoordXStep
end
local function texCoordY(_texCoordY)
m_texCoordY = _texCoordY or m_texCoordY
return m_texCoordY
end
local function texCoordYStep(_texCoordYStep)
m_texCoordYStep = _texCoordYStep or m_texCoordYStep
return m_texCoordYStep
end
local function oneOverZ(_oneOverZ)
m_oneOverZ = _oneOverZ or m_oneOverZ
return m_oneOverZ
end
local function oneOverZStep(_oneOverZStep)
m_oneOverZStep = _oneOverZStep or m_oneOverZStep
return m_oneOverZStep
end
local function depth(_depth)
m_depth = _depth or m_depth
return m_depth
end
local function depthStep(_depthStep)
m_depthStep = _depthStep or m_depthStep
return m_depthStep
end
local function lastX()
return m_lastX
end
--[[local function light(_light)
m_light = _light or m_light
return m_light
end
local function lightStep(_lightStep)
m_lightStep = _lightStep or m_lightStep
return m_lightStep
end]]
do
m_yStart = math.ceil(minYVert.pos().y())--
m_yEnd = math.ceil(maxYVert.pos().y())
local xDist = maxYVert.pos().x() - minYVert.pos().x()
local yDist = maxYVert.pos().y() - minYVert.pos().y()
local yPrestep = m_yStart - minYVert.pos().y()
m_xStep = xDist/yDist
m_x = minYVert.pos().x() + yPrestep * m_xStep
m_lastX = m_x
local xPrestep = m_x - minYVert.pos().x()
m_texCoordX = gradients.getTexCoordX(minYVertIndex) +
gradients.texCoordXXStep() * xPrestep +
gradients.texCoordXYStep() * yPrestep
m_texCoordXStep = gradients.texCoordXYStep() + gradients.texCoordXXStep() * m_xStep;
m_texCoordY = gradients.getTexCoordY(minYVertIndex) +
gradients.texCoordYXStep() * xPrestep +
gradients.texCoordYYStep() * yPrestep
m_texCoordYStep = gradients.texCoordYYStep() + gradients.texCoordYXStep() * m_xStep;
m_oneOverZ = gradients.getOneOverZ(minYVertIndex) +
gradients.oneOverZXStep() * xPrestep +
gradients.oneOverZYStep() * yPrestep
m_oneOverZStep = gradients.oneOverZYStep() + gradients.oneOverZXStep() * m_xStep;
m_depth = gradients.getDepth(minYVertIndex) +
gradients.depthXStep() * xPrestep +
gradients.depthYStep() * yPrestep
m_depthStep = gradients.depthYStep() + gradients.depthXStep() * m_xStep;
--[[m_light = gradients.getLight(minYVertIndex) +
gradients.lightXStep() * xPrestep +
gradients.lightYStep() * yPrestep
m_lightStep = gradients.lightYStep() + gradients.lightXStep() * m_xStep;]]
end
local function step()
m_lastX = m_x
m_x = m_x + m_xStep
m_texCoordX = m_texCoordX + m_texCoordXStep
m_texCoordY = m_texCoordY + m_texCoordYStep
m_oneOverZ = m_oneOverZ + m_oneOverZStep
m_depth = m_depth + m_depthStep
--m_light = m_light + m_lightStep
end
self.x = x
self.yStart = yStart
self.yEnd = yEnd
self.texCoordX = texCoordX
self.texCoordXStep = texCoordXStep
self.texCoordY = texCoordY
self.texCoordYStep = texCoordYStep
self.oneOverZ = oneOverZ
self.oneOverZStep = oneOverZStep
self.step = step
self.depth = depth
self.depthStep = depthStep
self.lastX = lastX
--[[self.light = light
self.lightStep = lightStep]]
return self
end
local function Gradients(minYVert, midYVert, maxYVert)
local self = Object(Gradients)
local m_texCoordX
local m_texCoordY
local m_oneOverZ
local m_depth
--local m_light
local m_texCoordXXStep
local m_texCoordXYStep
local m_texCoordYXStep
local m_texCoordYYStep
local m_oneOverZXStep
local m_oneOverZYStep
local m_depthXStep
local m_depthYStep
--local m_lightXStep
--local m_lightYStep
local function getTexCoordX(loc)
return m_texCoordX[loc]
end
local function getTexCoordY(loc)
return m_texCoordY[loc]
end
local function getOneOverZ(loc)
return m_oneOverZ[loc]
end
local function getDepth(loc)
return m_depth[loc]
end
--[[local function getLight(loc)
return m_light[loc]
end]]
local function texCoordXXStep(_texCoordXXStep)
m_texCoordXXStep = _texCoordXXStep or m_texCoordXXStep
return m_texCoordXXStep
end
local function texCoordXYStep(_texCoordXYStep)
m_texCoordXYStep = _texCoordXYStep or m_texCoordXYStep
return m_texCoordXYStep
end
local function texCoordYXStep(_texCoordYXStep)
m_texCoordYXStep = _texCoordYXStep or m_texCoordYXStep
return m_texCoordYXStep
end
local function texCoordYYStep(_texCoordYYStep)
m_texCoordYYStep = _texCoordYYStep or m_texCoordYYStep
return m_texCoordYYStep
end
local function oneOverZXStep(_oneOverZXStep)
m_oneOverZXStep = _oneOverZXStep or m_oneOverZXStep
return m_oneOverZXStep
end
local function oneOverZYStep(_oneOverZYStep)
m_oneOverZYStep = _oneOverZYStep or m_oneOverZYStep
return m_oneOverZYStep
end
local function depthXStep(_depthXStep)
m_depthXStep = _depthXStep or m_depthXStep
return m_depthXStep
end
local function depthYStep(_depthYStep)
m_depthYStep = _depthYStep or m_depthYStep
return m_depthYStep
end
--[[local function lightXStep(_lightXStep)
m_lightXStep = _lightXStep or m_lightXStep
return m_lightXStep
end
local function lightYStep(_lightYStep)
m_lightYStep = _lightYStep or m_lightYStep
return m_lightYStep
end]]
local function calcXStep(values, minYVert, midYVert, maxYVert, oneOverDX)
return
(((values[2] - values[3]) *
(minYVert.pos().y() - maxYVert.pos().y())) -
((values[1] - values[3]) *
(midYVert.pos().y() - maxYVert.pos().y()))) * oneOverDX
end
local function calcYStep(values, minYVert, midYVert, maxYVert, oneOverDY)
return
(((values[2] - values[3]) *
(minYVert.pos().x() - maxYVert.pos().x())) -
((values[1] - values[3]) *
(midYVert.pos().x() - maxYVert.pos().x()))) * oneOverDY
end
local function saturate(val)
--[[if val < 0 then
return 0
end
if val > 1 then
return 1
end
return val]]
return val < 0 and 0 or val > 1 and 1 or val
end
do
m_oneOverZ = { }
m_texCoordX = { }
m_texCoordY = { }
m_depth = { }
--m_light = { }
--[[local lightDir = Vec4(0, 0, 1).normalized()
m_light[1] = saturate(minYVert.normal().dot(lightDir))
m_light[2] = saturate(midYVert.normal().dot(lightDir))
m_light[3] = saturate(maxYVert.normal().dot(lightDir))]]
m_depth[1] = minYVert.pos().z()
m_depth[2] = midYVert.pos().z()
m_depth[3] = maxYVert.pos().z()
m_oneOverZ[1] = 1/minYVert.pos().w()
m_oneOverZ[2] = 1/midYVert.pos().w()
m_oneOverZ[3] = 1/maxYVert.pos().w()
m_texCoordX[1] = minYVert.texCoords().x() * m_oneOverZ[1]
m_texCoordX[2] = midYVert.texCoords().x() * m_oneOverZ[2]
m_texCoordX[3] = maxYVert.texCoords().x() * m_oneOverZ[3]
m_texCoordY[1] = minYVert.texCoords().y() * m_oneOverZ[1]
m_texCoordY[2] = midYVert.texCoords().y() * m_oneOverZ[2]
m_texCoordY[3] = maxYVert.texCoords().y() * m_oneOverZ[3]
local oneOverDX = 1 /
(((midYVert.pos().x() - maxYVert.pos().x()) *
(minYVert.pos().y() - maxYVert.pos().y())) -
((minYVert.pos().x() - maxYVert.pos().x()) *
(midYVert.pos().y() - maxYVert.pos().y())));
local oneOverDY = -oneOverDX;
m_texCoordXXStep = calcXStep(m_texCoordX, minYVert, midYVert, maxYVert, oneOverDX)
m_texCoordXYStep = calcYStep(m_texCoordX, minYVert, midYVert, maxYVert, oneOverDY)
m_texCoordYXStep = calcXStep(m_texCoordY, minYVert, midYVert, maxYVert, oneOverDX)
m_texCoordYYStep = calcYStep(m_texCoordY, minYVert, midYVert, maxYVert, oneOverDY)
m_oneOverZXStep = calcXStep(m_oneOverZ, minYVert, midYVert, maxYVert, oneOverDX)
m_oneOverZYStep = calcYStep(m_oneOverZ, minYVert, midYVert, maxYVert, oneOverDY)
m_depthXStep = calcXStep(m_depth, minYVert, midYVert, maxYVert, oneOverDX)
m_depthYStep = calcYStep(m_depth, minYVert, midYVert, maxYVert, oneOverDY)
--[[m_lightXStep = calcXStep(m_light, minYVert, midYVert, maxYVert, oneOverDX)
m_lightYStep = calcYStep(m_light, minYVert, midYVert, maxYVert, oneOverDY)]]
end
self.getTexCoordX = getTexCoordX
self.getTexCoordY = getTexCoordY
self.getOneOverZ = getOneOverZ
self.getDepth = getDepth
self.texCoordXXStep = texCoordXXStep
self.texCoordXYStep = texCoordXYStep
self.texCoordYXStep = texCoordYXStep
self.texCoordYYStep = texCoordYYStep
self.oneOverZXStep = oneOverZXStep
self.oneOverZYStep = oneOverZYStep
self.depthXStep = depthXStep
self.depthYStep = depthYStep
self.getLight = getLight
--[[self.lightXStep = lightXStep
self.lightYStep = lightYStep]]
return self
end
local function Triangle(_v1, _v2, _v3, _texture, _callback, _info)
local self = Object(Triangle)
local m_vertices
local m_texture
local m_callback
local m_info
local vertices
local vertex
local texture
local callback
local info
local isInsideViewFrustum
do
m_vertices = { _v1, _v2, _v3 }
m_texture = _texture
m_callback = _callback
m_info = _info or { }
end
function vertices()
return unpack(m_vertices)
end
function vertex(i)
return m_vertices[i]
end
function texture()
return m_texture
end
function callback()
return m_callback
end
function info()
return m_info
end
function isInsideViewFrustum()
for i = 1, 3 do
if not m_vertices[i].isInsideViewFrustum() then
return false
end
end
return true
end
self.vertices = vertices
self.vertex = vertex
self.texture = texture
self.callback = callback
self.info = info
self.isInsideViewFrustum = isInsideViewFrustum
return self
end
local function RenderContext(_renderTarget)
local self = Object(RenderContext)
local m_renderTarget = _renderTarget
local m_zBuffer = { }
local m_drawList = { }
do
for i = 1, m_renderTarget.size.x * m_renderTarget.size.y do
m_zBuffer[i] = 0
end
end
local function addTriangle(v1, v2, v3, texture, callback, info)
local tri = Triangle(v1, v2, v3, texture, callback, info)
m_drawList[#m_drawList + 1] = tri
end
local function plot(x, y, color)
m_renderTarget.pixelData[x + y * m_renderTarget.size.x + 1] = color
end
local function clearDrawList()
for i = 1, #m_drawList do
m_drawList[i] = nil
end
end
local function clearDepthBuffer()
for i = 1, m_renderTarget.size.x * m_renderTarget.size.y do
m_zBuffer[i] = math.huge
end
end
local function clipPolygonComponent(vertices, componentIndex, componentFactor, result)
local previousVertex = vertices[#vertices]
local previousComponent = previousVertex.get(componentIndex) * componentFactor
local previousInside = previousComponent <= previousVertex.pos().w()
for i = 1, #vertices do
local currentVertex = vertices[i]
local currentComponent = currentVertex.get(componentIndex) * componentFactor
local currentInside = currentComponent <= currentVertex.pos().w()
if currentInside ~= previousInside then
local lerpAmt = (previousVertex.pos().w() - previousComponent)/
((previousVertex.pos().w() - previousComponent) -
(currentVertex.pos().w() - currentComponent))
result[#result + 1] = previousVertex.lerp(currentVertex, lerpAmt)
end
if currentInside then
result[#result + 1] = currentVertex
end
previousVertex = currentVertex
previousComponent = currentComponent
previousInside = currentInside
end
end
local function clearTable(t)
for i = 1, #t do
t[i] = nil
end
end
local function clipPolygonAxis(vertices, auxillaryList, componentIndex)
clipPolygonComponent(vertices, componentIndex, 1, auxillaryList)
clearTable(vertices)
if #auxillaryList == 0 then
return false
end
clipPolygonComponent(auxillaryList, componentIndex, -1, vertices)
clearTable(auxillaryList)
return #vertices ~= 0
end
local function drawScanLine(left, right, j, triangle)
local texture = triangle.texture()
local callback = triangle.callback()
local xMin = math.ceil(left.x())
local xMax = math.ceil(right.x())
local xPrestep = xMin - left.x()
local xDist = right.x() - left.x()
local texCoordXXStep = (right.texCoordX() - left.texCoordX())/xDist
local texCoordYXStep = (right.texCoordY() - left.texCoordY())/xDist
local oneOverZXStep = (right.oneOverZ() - left.oneOverZ()) /xDist
local depthXStep = (right.depth() - left.depth()) /xDist
--local lightXStep = (right.light() - left.light()) /xDist
local texCoordX = left.texCoordX() + texCoordXXStep * xPrestep
local texCoordY = left.texCoordY() + texCoordYXStep * xPrestep
local oneOverZ = left.oneOverZ() + oneOverZXStep * xPrestep
local depth = left.depth() + depthXStep * xPrestep
--local light = left.light() + lightXStep * xPrestep
local texWidth = texture.size.x
local texHeight = texture.size.y
for i = xMin, xMax - 1 do
local index = i + j * m_renderTarget.size.x
if depth < m_zBuffer[index + 1] then
m_zBuffer[index + 1] = depth
local z = 1/oneOverZ
local srcX = math.floor((texCoordX * z) * texWidth)
local srcY = math.floor((texCoordY * z) * texHeight)
local color = texture.pixelData[srcX + srcY * texWidth + 1]
local r, g, b, a = color.x, color.y, color.z, color.w
local ambientLight = 0.5
local viewDistance = 10
--plot(i, j, vec4(r*((1-smoothstep(1, viewDistance+1, z+1))*(1-ambientLight) + ambientLight), g*((1-smoothstep(1, viewDistance+1, z+1))*(1-ambientLight) + ambientLight), b*((1-smoothstep(1, viewDistance+1, z+1))*(1-ambientLight) + ambientLight), a))
if i == centerW and j == centerH then
centerHit = true
end
--fill[#fill + 1] = { i, j, vec4(r, g, b, a) }
local inColor = vec4(r, g, b, a)
local info = { }
info.screenPos = vec2(i, j)
info.color = inColor
info.z = math.log(depth)
info.triangle = triangle
setmetatable(info, { __index = triangle.info() })
plot(i, j, callback(info) or inColor)
end
oneOverZ = oneOverZ + oneOverZXStep
texCoordX = texCoordX + texCoordXXStep
texCoordY = texCoordY + texCoordYXStep
depth = depth + depthXStep
--light = light + lightXStep
end
end
local function scanEdges(a, b, handedness, triangle)
local left = a
local right = b
if handedness then
local temp = left
left = right
right = temp
end
local yStart = b.yStart()
local yEnd = b.yEnd()
local centerHit = false
local fills = { }
for j = yStart, yEnd - 1 do
local ch, fill = drawScanLine(left, right, j, triangle)
if ch then centerHit = true end
fills[#fills + 1] = fill
left.step()
right.step()
end
return centerHit, fills
end
local function scanTriangle(triangle, handedness)
local minYVert, midYVert, maxYVert = triangle.vertices()
local gradients = Gradients(minYVert, midYVert, maxYVert)
local maxToMin = Edge(gradients, minYVert, maxYVert, 1)
local maxToMid = Edge(gradients, minYVert, midYVert, 1)
local midToMin = Edge(gradients, midYVert, maxYVert, 2)
local centerHit = false
local triFills = { }
local fills
ch, fills = scanEdges(maxToMin, maxToMid, handedness, triangle)
if ch then centerHit = true end
triFills[1] = fills
ch, fills = scanEdges(maxToMin, midToMin, handedness, triangle)
if ch then centerHit = true end
triFills[2] = fills
for k = 1, 2 do
fills = triFills[k]
if false and centerHit then
for i = 1, #fills do
local fill = fills[i]
for j = 1, #fill do
plot(fill[j][1], fill[j][2], vec4(1, 0, 1, 1))
end
end
else
for i = 1, #fills do
local fill = fills[i]
for j = 1, #fill do
local f = fill[j]
if triangle.callback() then
local info = { }
info.screenPos = vec2(f[1], f[2])
info.color = f[3]
local outColor = triangle.callback()(info)
plot(f[1], f[2], outColor or f[3])
else
plot(unpack(f))
end
end
end
end
end
end
local function triangleTwiceArea(a, b, c)
local x1 = b.pos().x() - a.pos().x()
local y1 = b.pos().y() - a.pos().y()
local x2 = c.pos().x() - a.pos().x()
local y2 = c.pos().y() - a.pos().y()
return x1 * y2 - x2 * y1
end
local function fillTriangle(triangle)
local v1, v2, v3 = triangle.vertices()
local sst = Mat4().initScreenSpaceTransform(m_renderTarget.size.x/2, m_renderTarget.size.y/2)
local minYVert = v1.transform(sst).perspectiveDivide()
local midYVert = v2.transform(sst).perspectiveDivide()
local maxYVert = v3.transform(sst).perspectiveDivide()
if triangleTwiceArea(minYVert, maxYVert, midYVert) >= 0 then
return
end
if maxYVert.pos().y() < midYVert.pos().y() then
local temp = maxYVert
maxYVert = midYVert
midYVert = temp
end
if midYVert.pos().y() < minYVert.pos().y() then
local temp = midYVert
midYVert = minYVert
minYVert = temp
end
if maxYVert.pos().y() < midYVert.pos().y() then
local temp = maxYVert
maxYVert = midYVert
midYVert = temp
end
local handedness = triangleTwiceArea(minYVert, maxYVert, midYVert) >= 0
local newTriangle = Triangle(minYVert, midYVert, maxYVert, triangle.texture(), triangle.callback(), triangle.info())
scanTriangle(newTriangle, handedness)
end
local function drawTriangle(triangle)
if triangle.isInsideViewFrustum() then
fillTriangle(triangle)
return
end
local vertices = { triangle.vertex(1), triangle.vertex(2), triangle.vertex(3) }
local auxillaryList = { }
if
clipPolygonAxis(vertices, auxillaryList, 0) and
clipPolygonAxis(vertices, auxillaryList, 1) and
clipPolygonAxis(vertices, auxillaryList, 2) then
local initialVertex = vertices[1]
for i = 2, #vertices - 1 do
local newTriangle = Triangle(
initialVertex, vertices[i], vertices[i + 1],
triangle.texture(), triangle.callback(), triangle.info())
fillTriangle(newTriangle)
end
end
end
local rotCounter = 0
local v1, t1 = Vec4(-1, 1, 1, 1), Vec4(0, 1, 0, 0)
local v2, t2 = Vec4(1, 1, 1, 1), Vec4(1, 1, 0, 0)
local v3, t3 = Vec4(1, -1, 1, 1), Vec4(1, 0, 0, 0)
local v4, t4 = Vec4(-1, -1, 1, 1), Vec4(0, 0, 1, 1)
local v5 = Vec4(-1, 1, -1, 1)
local v6 = Vec4(1, 1, -1, 1)
local v7 = Vec4(1, -1, -1, 1)
local v8 = Vec4(-1, -1, -1, 1)
local matrices = { Mat4().initIdentity() }
local m_transform = matrices[1]
local function pushMatrix(m)
matrices[#matrices + 1] = matrices[#matrices] * m
m_transform = matrices[#matrices]
end
local function popMatrix()
matrices[#matrices] = nil
m_transform = matrices[#matrices]
end
local charToColor = {
[1] = vec3(0xF0/0xFF, 0xF0/0xFF, 0xF0/0xFF),
[2] = vec3(0xF2/0xFF, 0xB2/0xFF, 0x33/0xFF),
[4] = vec3(0xE5/0xFF, 0x7F/0xFF, 0xD8/0xFF),
[8] = vec3(0x99/0xFF, 0xB2/0xFF, 0xF2/0xFF),
[16] = vec3(0xDE/0xFF, 0xDE/0xFF, 0x6C/0xFF),
[32] = vec3(0x7F/0xFF, 0xCC/0xFF, 0x19/0xFF),
[64] = vec3(0xF2/0xFF, 0xB2/0xFF, 0xCC/0xFF),
[128] = vec3(0x4C/0xFF, 0x4C/0xFF, 0x4C/0xFF),
[256] = vec3(0x99/0xFF, 0x99/0xFF, 0x99/0xFF),
[512] = vec3(0x4C/0xFF, 0x99/0xFF, 0xB2/0xFF),
[1024] = vec3(0xB2/0xFF, 0x66/0xFF, 0xE5/0xFF),
[2048] = vec3(0x33/0xFF, 0x66/0xFF, 0xCC/0xFF),
[4096] = vec3(0x7F/0xFF, 0x66/0xFF, 0x4C/0xFF),
[8192] = vec3(0x57/0xFF, 0xA6/0xFF, 0x4E/0xFF),
[16384] = vec3(0xCC/0xFF, 0x4C/0xFF, 0x4C/0xFF),
[32768] = vec3(0x19/0xFF, 0x19/0xFF, 0x19/0xFF)
}
local function loadTexture(file, frameBuffer, width, height)
local img = paintutils.loadImage(file)
local data = frameBuffer.pixelData
for y = 1, height do
local row = img[y]
if row then
for x = 1, width do
data[x + (height-y) * width] = row[x] and charToColor[row[x]] or charToColor[colors.black]
end
end
end
end
local function drawCube(t1, t2, t3, t4, cubeTexture, drawCallback)
addTriangle(
Vert(v2, t2).transform(m_transform),
Vert(v1, t1).transform(m_transform),
Vert(v3, t3).transform(m_transform), cubeTexture, drawCallback)
addTriangle(
Vert(v3, t3).transform(m_transform),
Vert(v1, t1).transform(m_transform),
Vert(v4, t4).transform(m_transform), cubeTexture, drawCallback)
addTriangle(
Vert(v6, t1).transform(m_transform),
Vert(v2, t2).transform(m_transform),
Vert(v3, t3).transform(m_transform), cubeTexture, drawCallback)
addTriangle(
Vert(v6, t1).transform(m_transform),
Vert(v3, t3).transform(m_transform),
Vert(v7, t4).transform(m_transform), cubeTexture, drawCallback)
addTriangle(
Vert(v5, t1).transform(m_transform),
Vert(v6, t2).transform(m_transform),
Vert(v7, t3).transform(m_transform), cubeTexture, drawCallback)
addTriangle(
Vert(v5, t1).transform(m_transform),
Vert(v7, t3).transform(m_transform),
Vert(v8, t4).transform(m_transform), cubeTexture, drawCallback)
addTriangle(
Vert(v1, t1).transform(m_transform),
Vert(v5, t2).transform(m_transform),
Vert(v4, t4).transform(m_transform), cubeTexture, drawCallback)
addTriangle(
Vert(v4, t4).transform(m_transform),
Vert(v5, t2).transform(m_transform),
Vert(v8, t3).transform(m_transform), cubeTexture, drawCallback)
addTriangle(
Vert(v1, t1).transform(m_transform),
Vert(v2, t2).transform(m_transform),
Vert(v5, t4).transform(m_transform), cubeTexture, drawCallback)
addTriangle(
Vert(v2, t2).transform(m_transform),
Vert(v6, t3).transform(m_transform),
Vert(v5, t4).transform(m_transform), cubeTexture, drawCallback)
addTriangle(
Vert(v8, t4).transform(m_transform),
Vert(v3, t2).transform(m_transform),
Vert(v4, t1).transform(m_transform), cubeTexture, drawCallback)
addTriangle(
Vert(v3, t2).transform(m_transform),
Vert(v8, t4).transform(m_transform),
Vert(v7, t3).transform(m_transform), cubeTexture, drawCallback)
end
local camera = Camera(Mat4().initPerspective(70/180*math.pi, m_renderTarget.size.x/m_renderTarget.size.y, 0.1, 1000))
camera.move(Vec4(0, 0, -1, 0), 3)
local rotCounter = 0
local function getTexture(path)
local fb = createFrameBuffer(palette, charTable, vec2(16, 16), STRATEGY_FULL_CELL)
loadTexture(path, fb, 16, 16)
return fb
end
local blockTextures = {
getTexture("textures/cobble"),
getTexture("textures/redstone")
}
local function averagePoints(tri)
local a = tri.vertex(1).pos()
local b = tri.vertex(2).pos()
local c = tri.vertex(3).pos()
local ret = Vec4(
(a.x() + b.x() + c.x())/3,
(a.y() + b.y() + c.y())/3,
(a.z() + b.z() + c.z())/3)
return ret
end
local function sortTriangles(a, b)
return a.dist < b.dist
end
local function drawTriangles()
-- TODO: Decide whether this improves performance on average cases.
if false then
for i = 1, #m_drawList do
m_drawList[i].dist = averagePoints(m_drawList[i]).length()
end
table.sort(m_drawList, sortTriangles)
end
for i = 1, #m_drawList do
drawTriangle(m_drawList[i])
end
end
for x = -len, len do
for y = -len, len do
for z = -len, len do
setBlock(x, y, z, math.random(1, 2))
end
end
end
local function renderScene()
camera.update(keyboard)
--clearBlocks()
clearDrawList()
clearDepthBuffer()
clearFrameBuffer(m_renderTarget, vec4(0, 0, 0, 1))
rotCounter = rotCounter + 0.05
pushMatrix(camera.getViewProjection())
--[[pushMatrix(Mat4().initRotation3(0, os.clock(), 0))
pushMatrix(Mat4().initTranslation(0, 0, 0))
drawCube(t1, t2, t3, t4, cubeTexture)
popMatrix()
for i = 1, 3 do
pushMatrix(Mat4().initTranslation(2.5 * i, 0, 0))
drawCube(t1, t2, t3, t4, cubeTexture)
popMatrix()
pushMatrix(Mat4().initTranslation(-2.5 * i, 0, 0))
drawCube(t1, t2, t3, t4, cubeTexture)
popMatrix()
end
popMatrix()]]
local function drawCallback(info)
local c = info.color
local x = info.screenPos.x
local y = info.screenPos.y
local centerW = math.ceil(m_renderTarget.size.x/2)
local centerH = math.ceil(m_renderTarget.size.y/2)
--print(tostring(centerW) .. ", " .. tostring(x) .. ", " .. tostring(centerH) .. ", " .. tostring(y))
--error()
if centerW == x and centerH == y then
blockLook = info.blockPos
end
if blockLook == info.blockPos then
return vec4(1 - c.x, 1 - c.y, 1 - c.z, 1)
end
return c
end
--[[
local t = os.clock()
for x = -(len/2), len/2 - 1 do
for y = -(len/2), len/2 - 1 do
for z = -(len/2), len/2 - 1 do
if Vec4(x, y, z).length() < len/2 then
setBlock(
x + 0*math.floor(math.sin(t) * 4),
y + 0*math.floor(math.cos(t) * 4), z, 2)
end
end
end
end
]]
for x, a in pairs(blocks) do
for y, b in pairs(a) do
for z, block in pairs(b) do
pushMatrix(Mat4().initTranslation(x * 2, y * 2, z * 2 + len + 5))
if not blockExists(x, y, z + 1) then
addTriangle(
Vert(v2, t2).transform(m_transform),
Vert(v1, t1).transform(m_transform),
Vert(v3, t3).transform(m_transform), blockTextures[block], drawCallback, { blockPos = Vec4(x, y, z) })
addTriangle(
Vert(v3, t3).transform(m_transform),
Vert(v1, t1).transform(m_transform),
Vert(v4, t4).transform(m_transform), blockTextures[block], drawCallback, { blockPos = Vec4(x, y, z) })
end
if not blockExists(x + 1, y, z) then
addTriangle(
Vert(v6, t1).transform(m_transform),
Vert(v2, t2).transform(m_transform),
Vert(v3, t3).transform(m_transform), blockTextures[block], drawCallback, { blockPos = Vec4(x, y, z) })
addTriangle(
Vert(v6, t1).transform(m_transform),
Vert(v3, t3).transform(m_transform),
Vert(v7, t4).transform(m_transform), blockTextures[block], drawCallback, { blockPos = Vec4(x, y, z) })
end
if not blockExists(x, y, z - 1) then
addTriangle(
Vert(v5, t1).transform(m_transform),
Vert(v6, t2).transform(m_transform),
Vert(v7, t3).transform(m_transform), blockTextures[block], drawCallback, { blockPos = Vec4(x, y, z) })
addTriangle(
Vert(v5, t1).transform(m_transform),
Vert(v7, t3).transform(m_transform),
Vert(v8, t4).transform(m_transform), blockTextures[block], drawCallback, { blockPos = Vec4(x, y, z) })
end
if not blockExists(x - 1, y, z) then
addTriangle(
Vert(v1, t1).transform(m_transform),
Vert(v5, t2).transform(m_transform),
Vert(v4, t4).transform(m_transform), blockTextures[block], drawCallback, { blockPos = Vec4(x, y, z) })
addTriangle(
Vert(v4, t4).transform(m_transform),
Vert(v5, t2).transform(m_transform),
Vert(v8, t3).transform(m_transform), blockTextures[block], drawCallback, { blockPos = Vec4(x, y, z) })
end
if not blockExists(x, y + 1, z) then
addTriangle(
Vert(v1, t1).transform(m_transform),
Vert(v2, t2).transform(m_transform),
Vert(v5, t4).transform(m_transform), blockTextures[block], drawCallback, { blockPos = Vec4(x, y, z) })
addTriangle(
Vert(v2, t2).transform(m_transform),
Vert(v6, t3).transform(m_transform),
Vert(v5, t4).transform(m_transform), blockTextures[block], drawCallback, { blockPos = Vec4(x, y, z) })
end
if not blockExists(x, y - 1, z) then
addTriangle(
Vert(v8, t4).transform(m_transform),
Vert(v3, t2).transform(m_transform),
Vert(v4, t1).transform(m_transform), blockTextures[block], drawCallback, { blockPos = Vec4(x, y, z) })
addTriangle(
Vert(v3, t2).transform(m_transform),
Vert(v8, t4).transform(m_transform),
Vert(v7, t3).transform(m_transform), blockTextures[block], drawCallback, { blockPos = Vec4(x, y, z) })
end
popMatrix()
end
end
end
popMatrix()
drawTriangles()
end
self.renderScene = renderScene
return self
end
local function main()
local mon = peripheral.wrap("right")
mon.setTextScale(0.5)
-- Create the color palette. This is what
-- will convert our RGB colors into pixels
-- which can be written to the screen.
local palette = createPalette(indexTable, 8, 8, 8, progressHook)
term.clear()
-- Create the frame buffer. This is what we
-- apply the shaders to and can be quickly
-- blitted onto the screen.
local tw, th = term.getSize()
print(tw, ", ", th)
local frameBuffer = createFrameBuffer(palette, charTable, vec2(tw*2, th*3), STRATEGY_HEX_CELL--[[, mon.blit, mon.setCursorPos]])
local ctx = RenderContext(frameBuffer)
local start = clock()
while true do
ctx.renderScene(frameBuffer)
-- Draw the frame buffer onto the screen.
drawFrameBuffer(frameBuffer, vec2(1, 1))
-- Here I'm just doing a trick to make the
-- drawing run as fast as possible. You
-- limit the number of frames drawn if you
-- do this on a server.
--os.queueEvent("")
--os.pullEvent()
os.queueEvent("__dummy")
local e, k, h
repeat
if keyboard.getKeyDown(keys.tab) then
term.clear()
return
end
e, k, h = os.pullEvent()
if e == "key_up" then
keyboard.setKeyDown(k, false)
elseif e == "key" and not h then
keyboard.setKeyDown(k, true)
end
until e == "__dummy"
end
end
-- Generic trace code.
local function errHandler(e)
term.setTextColor(colors.red)
local errors = { }
local ok, err, name
local i = 4
print(e)
while true do
ok, err = pcall(error, "", i)
if err:sub(1, 10) == "TRACE_ROOT" then
break
end
print(err)
i = i + 1
end
term.setTextColor(colors.white)
end
local args = { ... }
local function init(main, args)
main(unpack(args))
end
local bc = string.dump(init)
xpcall(function() loadstring(bc, "TRACE_ROOT")(main, args) end, errHandler)
os.unloadAPI("gfx")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment