local fps = 0 local math_floor = math.floor local time = 0 local function ClearBuffers(meta, colorbuffer, depthbuffer, color, depth) local i for i = 0, meta[3] - 1 do colorbuffer[1 + i * 3] = color[1] colorbuffer[1 + i * 3 + 1] = color[2] colorbuffer[1 + i * 3 + 2] = color[3] depthbuffer[1 + i] = depth end end local function DegToRad(deg) local rad rad = deg * 0.0174532925 return rad end local function Min(a, b) local r if a < b then r = a else r = b end return r end local function Min3(a, b, c) local r r = Min(Min(a, b), c) return r end local function Max(a, b) local r if a > b then r = a else r = b end return r end local function Max3(a, b, c) local r r = Max(Max(a, b), c) return r end local function IsOnRight(a, b, c) local r if (b[1] - a[1]) * (c[2] - a[2]) - (b[2] - a[2]) * (c[1] - a[1]) <= 0 then r = true else r = false end return r end local function Distance2(a, b) local x, y, d x = b[1] - a[1] y = b[2] - a[2] d = math.sqrt(x * x + y * y) return d end local function Normalize(a) local l l = math.sqrt(a[1] * a[1] + a[2] * a[2] + a[3] * a[3]) a[1] = a[1] / l a[2] = a[2] / l a[3] = a[3] / l end local function MapToRes(meta, a) a[1] = a[1] / a[4] a[2] = a[2] / a[4] a[3] = a[3] / a[4] a[1] = (a[1] + 1.0) * 0.5 * (meta[1] - 1) a[2] = (1.0 - a[2]) * 0.5 * (meta[2] - 1) end local function Cross(result, a, b) result[1] = a[2] * b[3] - a[3] * b[2] result[2] = a[3] * b[1] - a[1] * b[3] result[3] = a[1] * b[2] - a[2] * b[1] end local function Dot(a, b) local result result = a[1] * b[1] + a[2] * b[2] + a[3] * b[3] return result end local function Dot2(a, b) local result result = a[1] * b[1] + a[2] * b[2] return result end local function VecCopy3(result, a) result[1] = a[1] result[2] = a[2] result[3] = a[3] end local function VecSubVec3(result, a, b) result[1] = a[1] - b[1] result[2] = a[2] - b[2] result[3] = a[3] - b[3] end local function MatMultMat(result, a, b) result[1] = a[1] * b[1] + a[2] * b[5] + a[3] * b[9] + a[4] * b[13] result[2] = a[1] * b[2] + a[2] * b[6] + a[3] * b[10] + a[4] * b[14] result[3] = a[1] * b[3] + a[2] * b[7] + a[3] * b[11] + a[4] * b[15] result[4] = a[1] * b[4] + a[2] * b[8] + a[3] * b[12] + a[4] * b[16] result[5] = a[5] * b[1] + a[6] * b[5] + a[7] * b[9] + a[8] * b[13] result[6] = a[5] * b[2] + a[6] * b[6] + a[7] * b[10] + a[8] * b[14] result[7] = a[5] * b[3] + a[6] * b[7] + a[7] * b[11] + a[8] * b[15] result[8] = a[5] * b[4] + a[6] * b[8] + a[7] * b[12] + a[8] * b[16] result[9] = a[9] * b[1] + a[10] * b[5] + a[11] * b[9] + a[12] * b[13] result[10] = a[9] * b[2] + a[10] * b[6] + a[11] * b[10] + a[12] * b[14] result[11] = a[9] * b[3] + a[10] * b[7] + a[11] * b[11] + a[12] * b[15] result[12] = a[9] * b[4] + a[10] * b[8] + a[11] * b[12] + a[12] * b[16] result[13] = a[13] * b[1] + a[14] * b[5] + a[15] * b[9] + a[16] * b[13] result[14] = a[13] * b[2] + a[14] * b[6] + a[15] * b[10] + a[16] * b[14] result[15] = a[13] * b[3] + a[14] * b[7] + a[15] * b[11] + a[16] * b[15] result[16] = a[13] * b[4] + a[14] * b[8] + a[15] * b[12] + a[16] * b[16] end local function MatMultVec(result, a, v) result[1] = a[1] * v[1] + a[2] * v[2] + a[3] * v[3] + a[4] * v[4] result[2] = a[5] * v[1] + a[6] * v[2] + a[7] * v[3] + a[8] * v[4] result[3] = a[9] * v[1] + a[10] * v[2] + a[11] * v[3] + a[12] * v[4] result[4] = a[13] * v[1] + a[14] * v[2] + a[15] * v[3] + a[16] * v[4] end local function MatMultVec3(result, a, v) result[1] = a[1] * v[1] + a[2] * v[2] + a[3] * v[3] + a[4] result[2] = a[5] * v[1] + a[6] * v[2] + a[7] * v[3] + a[8] result[3] = a[9] * v[1] + a[10] * v[2] + a[11] * v[3] + a[12] result[4] = a[13] * v[1] + a[14] * v[2] + a[15] * v[3] + a[16] end local function LookAt(mat, campos, targetpos, upvec) local forward = {} local right = {} local up = {} VecSubVec3(forward, targetpos, campos) Normalize(forward) Cross(right, forward, upvec) Normalize(right) Cross(up, right, forward) mat[1] = right[1] mat[2] = right[2] mat[3] = right[3] mat[4] = -Dot(right, campos) mat[5] = up[1] mat[6] = up[2] mat[7] = up[3] mat[8] = -Dot(up, campos) mat[9] = -forward[1] mat[10] = -forward[2] mat[11] = -forward[3] mat[12] = Dot(forward, campos) mat[13] = 0.0 mat[14] = 0.0 mat[15] = 0.0 mat[16] = 1.0 end local function Perspective(mat, fov, aspectratio, near, far) local tanhalffovy tanhalffovy = math.tan(fov * 0.5) mat[1] = 1 / (aspectratio * tanhalffovy) mat[2] = 0.0 mat[3] = 0.0 mat[4] = 0.0 mat[5] = 0.0 mat[6] = 1 / tanhalffovy mat[7] = 0.0 mat[8] = 0.0 mat[9] = 0.0 mat[10] = 0.0 mat[11] = -(far + near) / (far - near) mat[12] = -(2 * far * near) / (far - near) mat[13] = 0.0 mat[14] = 0.0 mat[15] = -1.0 mat[16] = 0.0 end local function OutputVT100(meta, colorbuffer) print("\x1b[1;1H") local r1, g1, b1, r2, b2, g2, width, height, idx, rowoffset width = meta[1] height = meta[2] local out = {} local pr1, pg1, pb1, pr2, pg2, pb2 = 0, 0, 0, 0, 0, 0 for y = 0, height - 2, 2 do table.insert(out, "\n") for x = 0, width - 1 do idx = (x + y * width) * 3 rowoffset = width * 3 r1 = math_floor(colorbuffer[1 + idx] * 255) g1 = math_floor(colorbuffer[1 + idx + 1] * 255) b1 = math_floor(colorbuffer[1 + idx + 2] * 255) r2 = math_floor(colorbuffer[1 + idx + rowoffset] * 255) g2 = math_floor(colorbuffer[1 + idx + 1 + rowoffset] * 255) b2 = math_floor(colorbuffer[1 + idx + 2 + rowoffset] * 255) if r1 == pr1 and g1 == pg1 and b1 == pb1 and r2 == pr2 and g2 == pg2 and b2 == pb2 then table.insert(out, "\xDF") else pr1, pg1, pb1, pr2, pg2, pb2 = r1, g1, b1, r2, g2, b2 table.insert(out, string.format("\x1b[38;2;%d;%d;%dm\x1b[48;2;%d;%d;%dm\xDF", r1, g1, b1, r2, g2, b2)) end -- io.write("\x1b[38;2;" .. -- r1 .. ";" .. g1 .. ";" .. b1 .. "m" .. "\x1b[48;2;" .. r2 .. ";" .. g2 .. ";" .. b2 .. "m" .. "\xDF") end end io.write(table.concat(out)) io.write(string.format("\n\x1b[38;2;255;255;255m\x1b[48;2;0;0;0m%d FPS", fps)) end local function DrawTriangle(meta, colorbuffer, depthbuffer, wp0, wp1, wp2, texture, c0, c1, c2, mvp, lightdir, n0, n1, n2) local p0 = {} local p1 = {} local p2 = {} MatMultVec3(p0, mvp, wp0) MatMultVec3(p1, mvp, wp1) MatMultVec3(p2, mvp, wp2) if p0[4] ~= 0.0 and p1[4] ~= 0.0 and p2[4] ~= 0.0 then MapToRes(meta, p0) MapToRes(meta, p1) MapToRes(meta, p2) local aabbmin = {} local aabbmax = {} aabbmin[1] = Max(Min3(p0[1], p1[1], p2[1]), 0) aabbmin[2] = Max(Min3(p0[2], p1[2], p2[2]), 0) aabbmax[1] = Min(Max3(p0[1], p1[1], p2[1]), meta[1] - 1) aabbmax[2] = Min(Max3(p0[2], p1[2], p2[2]), meta[2] - 1) local idx, tx, ty, ti local p = {} local depth local w0, w1, w2, dot00, dot01, dot11, dot20, dot21, denom, d0, d1, d2 local v0 = {} local v1 = {} local v2 = {} local texcoord = {} local normal = {} local diff for y = math_floor(aabbmin[2]), math_floor(aabbmax[2]) do for x = math_floor(aabbmin[1]), math_floor(aabbmax[1]) do p[1] = x p[2] = y if IsOnRight(p0, p1, p) and IsOnRight(p1, p2, p) and IsOnRight(p2, p0, p) then v0[1] = p1[1] - p0[1] v0[2] = p1[2] - p0[2] v1[1] = p2[1] - p0[1] v1[2] = p2[2] - p0[2] v2[1] = p[1] - p0[1] v2[2] = p[2] - p0[2] dot00 = Dot2(v0, v0) dot01 = Dot2(v0, v1) dot11 = Dot2(v1, v1) dot20 = Dot2(v2, v0) dot21 = Dot2(v2, v1) denom = dot00 * dot11 - dot01 * dot01 w1 = (dot11 * dot20 - dot01 * dot21) / denom w2 = (dot00 * dot21 - dot01 * dot20) / denom w0 = 1.0 - w1 - w2 depth = p0[3] * w0 + p1[3] * w1 + p2[3] * w2 idx = math_floor(x) + meta[1] * math_floor(y) if depth > 0.0 and depthbuffer[1 + idx] > depth then depthbuffer[1 + idx] = depth idx = idx * 3 texcoord[1] = w0 * c0[1] + w1 * c1[1] + w2 * c2[1] texcoord[2] = w0 * c0[2] + w1 * c1[2] + w2 * c2[2] normal[1] = w0 * n0[1] + w1 * n1[1] + w2 * n2[1] normal[2] = w0 * n0[2] + w1 * n1[2] + w2 * n2[2] normal[3] = w0 * n0[3] + w1 * n1[3] + w2 * n2[3] Normalize(normal) diff = Max(0.5, Dot(normal, lightdir)) tx = math_floor(texcoord[1] * meta[4]) ty = math_floor((1 - texcoord[2]) * meta[5]) ti = (tx + ty * meta[4]) * 3 -- uz ne kokote colorbuffer[1 + idx] = texture[1 + ti] / 255 * diff colorbuffer[1 + idx + 1] = texture[1 + ti + 1] / 255 * diff colorbuffer[1 + idx + 2] = texture[1 + ti + 2] / 255 * diff OutputVT100(meta, colorbuffer) end end end end end end local file = io.open("data.txt", "r") local function Input() return file:read("*n") end -- file:close() -- Close the file -- return number local function Main() os.execute(" ") local meta = {} -- meta[1] = 175 -- meta[2] = 120 meta[1] = 175 * 2 meta[2] = 120 * 2 meta[3] = meta[1] * meta[2] local depthbuffer = {} local colorbuffer = {} local background = {} background[1] = 0.3 background[2] = 0.3 background[3] = 0.3 ClearBuffers(meta, colorbuffer, depthbuffer, background, 100.0) local lightdir = {} lightdir[1] = .3 lightdir[2] = 1 lightdir[3] = .4 Normalize(lightdir) local view = {} local proj = {} local mvp = {} local campos = {} local targetpos = {} local upvector = {} targetpos[1] = 0 targetpos[2] = 0 targetpos[3] = 0 upvector[1] = 0 upvector[2] = 1 upvector[3] = 0 local aspectratio aspectratio = 1.46 Perspective(proj, DegToRad(90.0) / aspectratio, aspectratio, 0.1, 50.0) local p0 = {} local p1 = {} local p2 = {} local c0 = {} local c1 = {} local c2 = {} local n0 = {} local n1 = {} local n2 = {} local datasize, i, vertices datasize = Input() vertices = Input() local data = {} for i = 1, datasize do data[i] = Input() end print("model rdy") meta[4] = Input() meta[5] = Input() local tp tp = meta[4] * meta[5] * 3 local texture = {} for i = 0, tp - 1 do texture[1 + i] = Input() end print("textura rdy") local temp local i0, i1, i2 local camangle camangle = 0 local frames = 0 local lastframereset = 0 while true do frames = frames + 1 time = os.clock() * 1000 if time > lastframereset + 1000 then fps = frames frames = 0 lastframereset = time end ClearBuffers(meta, colorbuffer, depthbuffer, background, 100.0) local camdis camdis = 7.0 campos[1] = math.sin(camangle) * camdis campos[2] = 0.8 * camdis campos[3] = math.cos(camangle) * camdis camangle = time * 0.0003 LookAt(view, campos, targetpos, upvector) MatMultMat(mvp, proj, view) for i = 0, vertices - 3, 3 do i0 = i * 8 i1 = (i + 1) * 8 i2 = (i + 2) * 8 p0[1] = data[1 + i0] p0[2] = data[1 + i0 + 1] p0[3] = data[1 + i0 + 2] p1[1] = data[1 + i1] p1[2] = data[1 + i1 + 1] p1[3] = data[1 + i1 + 2] p2[1] = data[1 + i2] p2[2] = data[1 + i2 + 1] p2[3] = data[1 + i2 + 2] c0[1] = data[1 + i0 + 3] c0[2] = data[1 + i0 + 4] c1[1] = data[1 + i1 + 3] c1[2] = data[1 + i1 + 4] c2[1] = data[1 + i2 + 3] c2[2] = data[1 + i2 + 4] n0[1] = data[1 + i0 + 5] n0[2] = data[1 + i0 + 6] n0[3] = data[1 + i0 + 7] n1[1] = data[1 + i1 + 5] n1[2] = data[1 + i1 + 6] n1[3] = data[1 + i1 + 7] n2[1] = data[1 + i2 + 5] n2[2] = data[1 + i2 + 6] n2[3] = data[1 + i2 + 7] DrawTriangle(meta, colorbuffer, depthbuffer, p0, p1, p2, texture, c0, c1, c2, mvp, lightdir, n0, n1, n2) end OutputVT100(meta, colorbuffer) end end Main()