-- OBJ model library 1.0 -- --------------------- -- by Totoro (computercraft.ru) -- --- -- texture support by Xytabich local png = require("PNGImage") tobj = {} local vertex = {} local faces = {} local image local texCoords = {} local palette = {} local color = {r = 1, g = 0, b = 0, a = 1} local position = {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 tobj.loadTexture = function(filename) image = png.newFromFile(filename); end tobj.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 tobj.setColor = function(r, g, b, a) color.r = r; color.g = g; color.b = b; color.a = a or 1; end tobj.setPosition = function(x, y, z) position.x = x; position.y = y; position.z = z end tobj.setScale = function(s) scale = s end tobj.getColor = function() return {color.r, color.g, color.b, color.a} end tobj.getPosition = function() return {position.x, position.y, position.z} end tobj.getScale = function() return scale end tobj.usePalette = function(use) if use ~= nil then paletteColors = use else return paletteColors end end tobj.draw = function(glasses) local count = 0 for n, face in pairs(faces) do local triangle = glasses.addTriangle3D() triangle.setVertex(1, face[1][1]*scale + position.x, face[1][2]*scale + position.y, face[1][3]*scale + position.z) triangle.setVertex(2, face[2][1]*scale + position.x, face[2][2]*scale + position.y, face[2][3]*scale + position.z) triangle.setVertex(3, face[3][1]*scale + position.x, face[3][2]*scale + position.y, face[3][3]*scale + position.z) 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) --- count = count + 1 if count > 20 then count = 0; os.sleep(0.1) end end end tobj.getVertexNum = function() return #vertex end tobj.getPolyNum = function() return #faces end return tobj