Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- OBJ model library 2.2
- -- ---------------------
- -- by Totoro and Xytabich (computercraft.ru)
- local png = require("PNGImage")
- atobj = {}
- local vertex = {}
- local faces = {}
- local triangles = {}
- local image
- local texCoords = {}
- local palette = {}
- local frames = {}
- local animFaces1 = {}
- local animFaces2 = {}
- local color = {r = 1, g = 0, b = 0, a = 1}
- local position = {x = 0, y = 0, z = 0}
- local rotation = {x = 0, y = 0, z = 0}
- local scale = 1.0
- local paletteColors = true
- local function getVT(data)
- local v, t = data:match("(-?%d+)/(-?%d+)")
- return tonumber(v), tonumber(t) or nil
- end
- local function round(v)
- local r = math.floor(v)
- if v-0.5 > r then return math.ceil(v)
- else return r end
- end
- local function inBounds(u, v) -- trim the number to the borders of 0-1
- if u > 1 then
- local a, b = math.modf(u)
- u = b
- elseif u < 0 then
- local a, b = math.modf(u)
- u = 1+b
- end
- if v > 1 then
- local a, b = math.modf(v)
- v = b
- elseif v < 0 then
- local a, b = math.modf(v)
- v = 1+b
- end
- return u, v
- end
- local function getFaceColor(t1, t2, t3)
- if (image == nil) or (t1 > #texCoords) or
- (t2 > #texCoords) or (t3 > #texCoords) then return nil
- else
- local u,v = table.unpack(texCoords[t1])
- local w,h = image:getSize()
- w=w-1 h=h-1
- if paletteColors then
- local r,g,b,a = image:getPixel(round(u*w), round((1-v)*h))
- if r == nil then return nil end
- return r/255, g/255, b/255, a/255
- else -- average color of 3 points - алгоритм для ленивых
- local r1,g1,b1,a1 = image:getPixel(round(u*w), round((1-v)*h))
- if r1 == nil then return nil end
- u,v = table.unpack(texCoords[t2])
- local r2,g2,b2,a2 = image:getPixel(round(u*w), round((1-v)*h))
- if r2 == nil then return nil end
- u,v = table.unpack(texCoords[t3])
- local r3,g3,b3,a3 = image:getPixel(round(u*w), round((1-v)*h))
- if r3 == nil then return nil end
- return ((r1+r2+r3)/3)/255, ((g1+g2+g3)/3)/255, ((b1+b2+b3)/3)/255, ((a1+a2+a3)/3)/255
- end
- end
- end
- local function getPaletteIndex(r,g,b,a)
- for i=1, #palette do
- local pr,pg,pb,pa = table.unpack(palette[i])
- if (r==pr) and (g==pg) and (b==pb) and (a==pa) then
- return i
- end
- end
- table.insert(palette, {r,g,b,a})
- return #palette
- end
- local function getPaletteColor(i)
- if (i < 1) or (i > #palette) then return 1,1,1,1
- else return table.unpack(palette[i]) end
- end
- local function lerp(v1, v2, t)
- local v = {0,0,0}
- v[1] = (1-t)*v1[1] + t*v2[1];
- v[2] = (1-t)*v1[2] + t*v2[2];
- v[3] = (1-t)*v1[3] + t*v2[3];
- return v
- end
- local function findTab(tab, i)
- for n,v in pairs(tab) do
- if v ~= nil then
- if v[1] == i then return v[2] end
- end
- end
- return nil
- end
- local function getPointRotation(v)
- local x,y,z = table.unpack(v)
- local rx,ry,rz = 0,0,0
- rx = x*math.cos(rotation.y)+z*math.sin(rotation.y)+x*math.cos(rotation.z)-y*math.sin(rotation.z)
- ry = y*math.cos(rotation.x)+z*math.sin(rotation.x)+x*math.sin(rotation.z)+y*math.cos(rotation.z)
- rz = -y*math.sin(rotation.x)+z*math.cos(rotation.x)-x*math.sin(rotation.y)+z*math.cos(rotation.y)
- return {rx,ry,rz}
- end
- local function updateTransform()
- for n, triangle in pairs(triangles) do
- local v1 = getPointRotation(triangle.vertexes[1])
- local v2 = getPointRotation(triangle.vertexes[2])
- local v3 = getPointRotation(triangle.vertexes[3])
- triangle.setVertex(1, v1[1]*scale + position.x, v1[2]*scale + position.y, v1[3]*scale + position.z)
- triangle.setVertex(2, v2[1]*scale + position.x, v2[2]*scale + position.y, v2[3]*scale + position.z)
- triangle.setVertex(3, v3[1]*scale + position.x, v3[2]*scale + position.y, v3[3]*scale + position.z)
- end
- end
- atobj.loadTexture = function(filename)
- image = png.newFromFile(filename);
- end
- atobj.load = function(filename)
- file = io.open(filename, "r")
- if file ~= nil then
- vertex = {}
- for line in file:lines() do
- if line ~= nil and line ~= '' then
- local key, a, b, c, d = line:match("(%S+)%s+(%S+)%s+(%S+)%s+(%S+)%s*(%S*)")
- -- load vertex data / skip normals
- if key == 'v' then
- local x, y, z = tonumber(a), tonumber(b), tonumber(c)
- table.insert(vertex, {x,y,z})
- -- load texture data
- elseif key == "vt" then
- local u, v = tonumber(a), tonumber(b)
- table.insert(texCoords, table.pack(inBounds(u, v)))
- -- load faces data
- elseif key == 'f' then
- local v1, t1 = getVT(a)
- local v2, t2 = getVT(b)
- local v3, t3 = getVT(c)
- if v1 < 0 then
- local len = #vertex + 1
- v1, v2, v3 = len + v1, len + v2, len + v3
- end
- local p = 0
- if t1 ~= nil then
- r,g,b,a = getFaceColor(t1, t2, t3)
- if r ~= nil then
- p = getPaletteIndex(r,g,b,a)
- end
- end
- table.insert(faces, {vertex[v1], vertex[v2], vertex[v3], p})
- end
- end
- end
- file:close()
- else
- error("[OBJ.load] File not found!")
- end
- end
- atobj.loadFrame = function(filename) -- из базового кадра берутся значения в случае отсутствия их в таблице измененных вершин
- file = io.open(filename, "r")
- if file ~= nil then
- local frame = {}
- local frameVertex = {}
- local frameFaces = {}
- local lastVertex = 1
- local lastFace = 1
- for line in file:lines() do
- if line ~= nil and line ~= '' then
- local key, a, b, c, d = line:match("(%S+)%s+(%S+)%s+(%S+)%s+(%S+)%s*(%S*)")
- -- load vertex data
- if key == 'v' then
- local x, y, z = tonumber(a), tonumber(b), tonumber(c)
- local vx, vy, vz = table.unpack(vertex[lastVertex])
- if (x ~= vx) or (y ~= vy) or (z ~= vz) then
- table.insert(frameVertex, {lastVertex, {x,y,z}})
- end
- lastVertex = lastVertex+1
- -- load faces data
- elseif key == 'f' then
- local v1 = getVT(a)
- local v2 = getVT(b)
- local v3 = getVT(c)
- if v1 < 0 then
- local len = #vertex + 1
- v1, v2, v3 = len + v1, len + v2, len + v3
- end
- local fv1 = findTab(frameVertex,v1)
- local fv2 = findTab(frameVertex,v2)
- local fv3 = findTab(frameVertex,v3)
- if (fv1 ~= nil) or (fv2 ~= nil) or (fv3 ~= nil) then
- table.insert(frameFaces, {lastFace, {fv1, fv2, fv3}})
- end
- lastFace = lastFace+1
- end
- end
- end
- table.insert(frames, frameFaces)
- file:close()
- else
- error("[OBJ.loadFrame] File not found!")
- end
- end
- atobj.setColor = function(r, g, b, a)
- color.r = r; color.g = g; color.b = b; color.a = a or 1;
- end
- atobj.setPosition = function(x, y, z)
- position.x = x; position.y = y; position.z = z
- updateTransform()
- end
- atobj.setRotation = function(x, y, z)
- rx = x; ry = y; rz = z
- if rx < 0 then rx = 360+rx
- elseif rx > 360 then rx = rx-360 end
- if ry < 0 then ry = 360+ry
- elseif ry > 360 then ry = ry-360 end
- if rz < 0 then rz = 360+rz
- elseif rz > 360 then rx = rz-360 end
- rotation.x = math.rad(rx); rotation.y = math.rad(ry); rotation.z = math.rad(rz)
- updateTransform()
- end
- atobj.setScale = function(s)
- scale = s
- updateTransform()
- end
- atobj.getColor = function()
- return {color.r, color.g, color.b, color.a}
- end
- atobj.getPosition = function()
- return {position.x, position.y, position.z}
- end
- atobj.getRotation = function()
- return {math.deg(rotation.x), math.deg(rotation.y), math.deg(rotation.z)}
- end
- atobj.getScale = function()
- return scale
- end
- atobj.getFramesNum = function()
- return #frames
- end
- atobj.usePalette = function(use)
- if use ~= nil then paletteColors = use
- else return paletteColors end
- end
- atobj.draw = function(glasses)
- local count = 0
- for n, face in pairs(faces) do
- local triangle = glasses.addTriangle3D()
- local vertexes = {}
- table.insert(vertexes, table.pack(face[1][1], face[1][2], face[1][3]))
- table.insert(vertexes, table.pack(face[2][1], face[2][2], face[2][3]))
- table.insert(vertexes, table.pack(face[3][1], face[3][2], face[3][3]))
- r,g,b,a = getPaletteColor(face[4])
- triangle.setColor(color.r*r, color.g*g, color.b*b)
- triangle.setAlpha(color.a*a)
- triangle.setVisibleThroughObjects(false)
- triangle.vertexes = vertexes
- table.insert(triangles, n, triangle)
- ---
- count = count + 1
- if count > 18 then count = 0; os.sleep(0.1) end
- end
- updateTransform()
- end
- atobj.setFrame = function(fn)
- if (fn ~= 0) and (frames[fn] == nil) then return false end
- animFaces1 = {} -- vertexes
- animFaces2 = {} -- vertexes, triangleNumber
- if fn == 0 then
- for i=1, #frames do
- table.insert(animFaces2, table.pack(faces[i][1], faces[i][2], faces[i][3], i))
- table.insert(animFaces1, triangles[i].vertexes)
- end
- else
- for n, tf in pairs(frames[fn]) do
- local i, f = table.unpack(tf)
- table.insert(animFaces2, table.pack(f[1] or triangles[i].vertexes[1],
- f[2] or triangles[i].vertexes[2], f[3] or triangles[i].vertexes[3], i))
- table.insert(animFaces1, triangles[i].vertexes)
- end
- end
- return true
- end
- atobj.animate = function(t)
- for n, f in pairs(animFaces2) do
- v1 = lerp(animFaces1[n][1], f[1], t)
- v2 = lerp(animFaces1[n][2], f[2], t)
- v3 = lerp(animFaces1[n][3], f[3], t)
- local vertexes = {}
- table.insert(vertexes, table.pack(v1[1], v1[2], v1[3]))
- table.insert(vertexes, table.pack(v2[1], v2[2], v2[3]))
- table.insert(vertexes, table.pack(v3[1], v3[2], v3[3]))
- triangles[f[4]].setVertex(1, getPointRotation(vertexes[1])[1]*scale + position.x,
- getPointRotation(vertexes[1])[2]*scale + position.y, getPointRotation(vertexes[1])[3]*scale + position.z)
- triangles[f[4]].setVertex(2, getPointRotation(vertexes[2])[1]*scale + position.x,
- getPointRotation(vertexes[2])[2]*scale + position.y, getPointRotation(vertexes[2])[3]*scale + position.z)
- triangles[f[4]].setVertex(3, getPointRotation(vertexes[3])[1]*scale + position.x,
- getPointRotation(vertexes[3])[2]*scale + position.y, getPointRotation(vertexes[3])[3]*scale + position.z)
- triangles[f[4]].vertexes = vertexes
- end
- end
- atobj.getVertexNum = function()
- return #vertex
- end
- atobj.getPolyNum = function()
- return #faces
- end
- return atobj
Add Comment
Please, Sign In to add comment