Guest User

PAMPacker

a guest
Dec 9th, 2016
152
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 14.11 KB | None | 0 0
  1. local fs = require("filesystem")
  2. local png = require("PNGImage")
  3.  
  4. local converts = {}
  5.  
  6. function grab_byte(v)
  7.       return math.floor(v / 256), string.char(math.floor(v) % 256)
  8. end
  9.  
  10. converts.float2str = function(x)
  11.    local sign = 0
  12.    if x < 0 then
  13.      sign = 1
  14.      x = -x
  15.    end
  16.    local mantissa, exponent = math.frexp(x)
  17.    if x == 0 then
  18.       mantissa = 0
  19.       exponent = 0
  20.    else
  21.       mantissa = (mantissa * 2 - 1) * 8388608
  22.       exponent = exponent + 126
  23.    end
  24.    local v, byte = ""
  25.    x, byte = grab_byte(mantissa); v = v..byte
  26.    x, byte = grab_byte(x); v = v..byte
  27.    x, byte = grab_byte(exponent * 128 + x); v = v..byte
  28.    x, byte = grab_byte(sign * 128 + x); v = v..byte
  29.    return v
  30. end
  31.  
  32. converts.str2float = function(x)
  33.   local sign = 1
  34.   local mantissa = string.byte(x, 3) % 128
  35.  
  36.   for i = 2, 1, -1 do mantissa = mantissa * 256 + string.byte(x, i) end
  37.   if string.byte(x, 4) > 127 then sign = -1 end
  38.   local exponent = (string.byte(x, 4) % 128) * 2 + math.floor(string.byte(x, 3) / 128)
  39.   if exponent == 0 then return 0 end
  40.   mantissa = (math.ldexp(mantissa, -23) + 1) * sign
  41.   return math.ldexp(mantissa, exponent - 127)
  42. end
  43.  
  44. converts.int2str = function(n)
  45.   n = (n < 0) and (4294967296 + n) or n
  46.   return string.char((math.modf(n/16777216))%256, (math.modf(n/65536))%256, (math.modf(n/256))%256, n%256)
  47. end
  48.  
  49. converts.str2int = function(x)
  50.   b1, b2, b3, b4 = string.byte(x, 1, 4)
  51.   local n = b1*16777216 + b2*65536 + b3*256 + b4
  52.   n = (n > 2147483647) and (n - 4294967296) or n
  53.   return n
  54. end
  55.  
  56. print("Select a model type:\n0 - Standart 3D\n1 - Vertex animated 3D\n2 - Color animated 3D\n3 - Vertex and color animated 3D\n4 - Standart 2D\n5 - Vertex animated 2D\n6 - Color animated 2D\n7 - Vertex and color animated 2D")
  57. local inType = io.read()
  58. local type = tonumber(inType)
  59. if type == nil then type = 0 end
  60.  
  61. print("Enter model name:")
  62. local inModelName = io.read()
  63. if inModelName == "" then inModelName = "model" end
  64. inModelName = inModelName..".pam"
  65.  
  66. ::gotoInBaseModel::
  67. print("\nEnter base model path *.obj:")
  68. local inBaseModel = io.read()
  69. if inBaseModel == "exit" then goto gotoExit
  70. else
  71.   if (inBaseModel:len() > 4) and (inBaseModel:find(".obj", inBaseModel:len()-4) ~= nil) then
  72.     if not fs.exists(inBaseModel) then
  73.       print("File does not exists")
  74.       goto gotoInBaseModel
  75.     end
  76.   else
  77.     print("Bad file path")
  78.     goto gotoInBaseModel
  79.   end
  80. end
  81.  
  82. ::gotoInBasePalette::
  83. print("\nEnter base palette path *.png:")
  84. local inBasePalette = io.read()
  85. if inBasePalette == "exit" then goto gotoExit
  86. else
  87.   if (inBasePalette:len() > 4) and (inBasePalette:find(".png", inBasePalette:len()-4) ~= nil) then
  88.     if not fs.exists(inBasePalette) then
  89.       print("File does not exists")
  90.       goto gotoInBasePalette
  91.     end
  92.   else
  93.     print("Bad file path, can you pick file?(y/n):")
  94.     local yn = io.read()
  95.     if yn ~= nil and ((yn == "y") or (yn == "yes")) then goto gotoInBasePalette end
  96.     inBasePalette = ""
  97.   end
  98. end
  99.  
  100. local function getVT(data)
  101.   local v, t = data:match("(-?%d+)/(-?%d+)")
  102.   return tonumber(v), tonumber(t) or nil
  103. end
  104.  
  105. local function getUVColor(img, u, v)
  106.   if img == nil then return string.char(255,255,255,255) end
  107.   local w,h = img:getSize()
  108.   local r,g,b,a = img:getPixel(math.floor(u*w), math.floor((1-v)*h))
  109.   if r == nil then r=255 g=255 b=255 a=255 end
  110.   return string.char(r,g,b,a)
  111. end
  112.  
  113. local function inBounds(u, v)
  114.   if u > 1 then
  115.     local a, b = math.modf(u)
  116.     u = b
  117.   elseif u < 0 then
  118.     local a, b = math.modf(u)
  119.     u = 1+b
  120.   end
  121.   if v > 1 then
  122.     local a, b = math.modf(v)
  123.     v = b
  124.   elseif v < 0 then
  125.     local a, b = math.modf(v)
  126.     v = 1+b
  127.   end
  128.   return u, v
  129. end
  130.  
  131. local function loadModel(fileName)
  132.   local file = io.open(fileName, "r")
  133.   if file ~= nil then
  134.     local vertexes = {}
  135.     local triangles = {}
  136.     local textureCoords = {}
  137.     local retTextureCoords = {}
  138.    
  139.     for line in file:lines() do
  140.       if line ~= nil and line ~= '' then
  141.         local key, a, b, c, d = line:match("(%S+)%s+(%S+)%s+(%S+)%s+(%S+)%s*(%S*)")
  142.        
  143.         if key == 'v' then
  144.           local x, y, z = tonumber(a), tonumber(b), tonumber(c)
  145.           table.insert(vertexes, {x,y,z})
  146.        
  147.         elseif key == "vt" then
  148.           local u, v = tonumber(a), tonumber(b)
  149.           table.insert(textureCoords, table.pack(inBounds(u, v)))
  150.        
  151.         elseif key == 'f' then
  152.           local v1, t1 = getVT(a)
  153.           local v2 = getVT(b)
  154.           local v3 = getVT(c)
  155.           if v1 < 0 then
  156.             local len = #vertexes + 1
  157.             v1, v2, v3 = len + v1, len + v2, len + v3
  158.           end
  159.           local p = 0
  160.           if (t1 ~= nil) and (textureCoords[t1] ~= nil) then
  161.             table.insert(retTextureCoords, textureCoords[t1])
  162.             p = #retTextureCoords
  163.           end
  164.           table.insert(triangles, {v1,v2,v3, p})
  165.         end
  166.       end
  167.     end
  168.     file:close()
  169.     return vertexes, triangles, retTextureCoords
  170.   else return nil end
  171. end
  172.  
  173. local function loadModel2D(fileName)
  174.   local vertexes = {}
  175.   local triangles = {}
  176.   local textureCoords = {}
  177.   local retTextureCoords = {}
  178.   local file = io.open(fileName, "r")
  179.   if file ~= nil then
  180.     for line in file:lines() do
  181.       if line ~= nil and line ~= '' then
  182.         local key, a, b, c, d = line:match("(%S+)%s+(%S+)%s+(%S+)%s+(%S+)%s*(%S*)")
  183.        
  184.         if key == 'v' then
  185.           local x, y = tonumber(a), tonumber(b)
  186.           table.insert(vertexes, {x,y})
  187.        
  188.         elseif key == "vt" then
  189.           local u, v = tonumber(a), tonumber(b)
  190.           table.insert(textureCoords, table.pack(inBounds(u, v)))
  191.        
  192.         elseif key == 'f' then
  193.           local v1, t1 = getVT(a)
  194.           local v2 = getVT(b)
  195.           local v3 = getVT(c)
  196.           if v1 < 0 then
  197.             local len = #vertexes + 1
  198.             v1, v2, v3 = len + v1, len + v2, len + v3
  199.           end
  200.           local p = 0
  201.           if (t1 ~= nil) and (textureCoords[t1] ~= nil) then
  202.             table.insert(retTextureCoords, textureCoords[t1])
  203.             p = #retTextureCoords
  204.           end
  205.           table.insert(triangles, {v1,v2,v3,p})
  206.         end
  207.       end
  208.     end
  209.     file:close()
  210.     return vertexes, triangles, retTextureCoords
  211.   else return nil end
  212. end
  213.  
  214. if type < 4 then
  215.   local verts, tris, texts = loadModel(inBaseModel)
  216.   if verts == nil then
  217.     print("Bad model")
  218.     goto gotoExit
  219.   end
  220.   local image = nil
  221.   if inBasePalette ~= "" then
  222.     image = png.newFromFile(inBasePalette)
  223.   end
  224.   local data = "PAM"..string.char(type)..converts.int2str(#verts)..converts.int2str(#tris)
  225.   for n, vert in pairs(verts) do
  226.     local x,y,z = table.unpack(vert)
  227.     data = data..converts.float2str(x)..converts.float2str(y)..converts.float2str(z)
  228.   end
  229.   for n, tri in pairs(tris) do
  230.     local a,b,c,d = table.unpack(tri)
  231.     local color = ""
  232.     if (image == nil) or (d == 0) or (d > #texts) then color = string.char(255,255,255,255)
  233.     else
  234.       local u,v = table.unpack(texts[d])
  235.       color = getUVColor(image,u,v)
  236.     end
  237.     data = data..converts.int2str(a)..converts.int2str(b)..converts.int2str(c)..color
  238.   end
  239.  
  240.   local vcount = #verts
  241.   local fcount = 0
  242.   local pcount = 0
  243.   local fdata = ""
  244.   local pdata = ""
  245.  
  246.   if (type == 2) or (type == 3) then
  247.     local palettePaths = {}
  248.    
  249.     ::gotoInFramePalette::
  250.     print("\nEnter frame palette path *.png:")
  251.     local inFramePalette = io.read()
  252.     if inFramePalette == "exit" then goto gotoExit
  253.     else
  254.       if (inFramePalette:len() > 4) and (inFramePalette:find(".png", inFramePalette:len()-4) ~= nil) then
  255.         if fs.exists(inFramePalette) then
  256.           table.insert(palettePaths, inFramePalette)
  257.           goto gotoInFramePalette
  258.         else
  259.           print("File does not exists")
  260.           goto gotoInFramePalette
  261.         end
  262.       elseif inFramePalette == "" then
  263.         print("End palette frames")
  264.       else
  265.         print("Bad file path")
  266.         goto gotoInFramePalette
  267.       end
  268.     end
  269.    
  270.     for n, pal in pairs(palettePaths) do
  271.       image = png.newFromFile(pal)
  272.       if image ~= nil then
  273.         for n, tri in pairs(tris) do
  274.           local a,b,c,d = table.unpack(tri)
  275.           local u,v = table.unpack(texts[d])
  276.           local color = getUVColor(image,u,v)
  277.           pdata = pdata..color
  278.         end
  279.         pcount = pcount+1
  280.       else print("Bad palette frame "..pal.."\nSkipping")
  281.       end
  282.     end
  283.     pdata = converts.int2str(pcount)..pdata
  284.   end
  285.  
  286.   if (type == 1) or (type == 3) then
  287.     local framePaths = {}
  288.    
  289.     ::gotoInFrameModel::
  290.     print("\nEnter frame model path *.obj:")
  291.     local inFrameModel = io.read()
  292.     if inFrameModel == "exit" then goto gotoExit
  293.     else
  294.       if (inFrameModel:len() > 4) and (inFrameModel:find(".obj", inFrameModel:len()-4) ~= nil) then
  295.         if fs.exists(inFrameModel) then
  296.           table.insert(framePaths, inFrameModel)
  297.           goto gotoInFrameModel
  298.         else
  299.           print("File does not exists")
  300.           goto gotoInFrameModel
  301.         end
  302.       elseif inFrameModel == "" then
  303.         print("End vertex frames")
  304.       else
  305.         print("Bad file path")
  306.         goto gotoInFrameModel
  307.       end
  308.     end
  309.    
  310.     for n, fp in pairs(framePaths) do
  311.       verts = loadModel(fp)
  312.       if (verts == nil) or (#verts ~= vcount) then
  313.         print("Different number of vertexes in "..fp.."\nSkipping")
  314.       else
  315.         for n, vert in pairs(verts) do
  316.           local x,y,z = table.unpack(vert)
  317.           fdata = fdata..converts.float2str(x)..converts.float2str(y)..converts.float2str(z)
  318.         end
  319.         fcount = fcount+1
  320.       end
  321.     end
  322.    
  323.     fdata = converts.int2str(fcount)..fdata
  324.   end
  325.  
  326.   data = data..fdata..pdata
  327.  
  328.   local file = fs.open(inModelName, "wb")
  329.   file:write(data)
  330.   file:close()
  331.  
  332.   if type == 0 then print("Model succeful packed to "..inModelName)
  333.   elseif type == 1 then print("Model succeful packed to "..inModelName.." vertex frames count: "..fcount)
  334.   elseif type == 2 then print("Model succeful packed to "..inModelName.." palette frames count: "..pcount)
  335.   else print("Model succeful packed to "..inModelName.." vertex frames count: "..fcount.." palette frames count: "..pcount)
  336.   end
  337. elseif type < 8 then
  338.   local verts, tris, texts = loadModel2D(inBaseModel)
  339.   if verts == nil then
  340.     print("Bad model")
  341.     goto gotoExit
  342.   end
  343.   local image = nil
  344.   if inBasePalette ~= "" then
  345.     image = png.newFromFile(inBasePalette)
  346.   end
  347.   local data = "PAM"..string.char(type)..converts.int2str(#verts)..converts.int2str(#tris)
  348.   for n, vert in pairs(verts) do
  349.     local x,y = table.unpack(vert)
  350.     data = data..converts.float2str(x)..converts.float2str(y)
  351.   end
  352.   for n, tri in pairs(tris) do
  353.     local a,b,c,d = table.unpack(tri)
  354.     local color = ""
  355.     if (image == nil) or (d == 0) or (d > #texts) then color = string.char(255,255,255,255)
  356.     else
  357.       local u,v = table.unpack(texts[d])
  358.       color = getUVColor(image,u,v)
  359.     end
  360.     data = data..converts.int2str(a)..converts.int2str(b)..converts.int2str(c)..color
  361.   end
  362.   local vcount = #verts
  363.   local fcount = 0
  364.   local pcount = 0
  365.   local fdata = ""
  366.   local pdata = ""
  367.  
  368.   if (type == 6) or (type == 7) then
  369.     local palettePaths = {}
  370.    
  371.     ::gotoInFramePalette::
  372.     print("\nEnter frame palette path *.png:")
  373.     local inFramePalette = io.read()
  374.     if inFramePalette == "exit" then goto gotoExit
  375.     else
  376.       if (inFramePalette:len() > 4) and (inFramePalette:find(".png", inFramePalette:len()-4) ~= nil) then
  377.         if fs.exists(inFramePalette) then
  378.           table.insert(palettePaths, inFramePalette)
  379.           goto gotoInFramePalette
  380.         else
  381.           print("File does not exists")
  382.           goto gotoInFramePalette
  383.         end
  384.       elseif inFramePalette == "" then
  385.         print("End palette frames")
  386.       else
  387.         print("Bad file path")
  388.         goto gotoInFramePalette
  389.       end
  390.     end
  391.    
  392.     for n, pal in pairs(palettePaths) do
  393.       image = png.newFromFile(pal)
  394.       if image ~= nil then
  395.         for n, tri in pairs(tris) do
  396.           local a,b,c,d = table.unpack(tri)
  397.           local u,v = table.unpack(texts[d])
  398.           local color = getUVColor(image,u,v)
  399.           pdata = pdata..color
  400.         end
  401.         pcount = pcount+1
  402.       else print("Bad palette frame "..pal.."\nSkipping")
  403.       end
  404.     end
  405.     pdata = converts.int2str(pcount)..pdata
  406.   end
  407.  
  408.   if (type == 5) or (type == 7) then
  409.     local framePaths = {}
  410.    
  411.     ::gotoInFrameModel::
  412.     print("\nEnter frame model path *.obj:")
  413.     local inFrameModel = io.read()
  414.     if inFrameModel == "exit" then goto gotoExit
  415.     else
  416.       if (inFrameModel:len() > 4) and (inFrameModel:find(".obj", inFrameModel:len()-4) ~= nil) then
  417.         if fs.exists(inFrameModel) then
  418.           table.insert(framePaths, inFrameModel)
  419.           goto gotoInFrameModel
  420.         else
  421.           print("File does not exists")
  422.           goto gotoInFrameModel
  423.         end
  424.       elseif inFrameModel == "" then
  425.         print("End vertex frames")
  426.       else
  427.         print("Bad file path")
  428.         goto gotoInFrameModel
  429.       end
  430.     end
  431.    
  432.     for n, fp in pairs(framePaths) do
  433.       verts = loadModel2D(fp)
  434.       if (verts == nil) or (#verts ~= vcount) then
  435.         print("Different number of vertexes in "..fp.."\nSkipping")
  436.       else
  437.         for n, vert in pairs(verts) do
  438.           local x,y = table.unpack(vert)
  439.           fdata = fdata..converts.float2str(x)..converts.float2str(y)
  440.         end
  441.         fcount = fcount+1
  442.       end
  443.     end
  444.    
  445.     fdata = converts.int2str(fcount)..fdata
  446.   end
  447.  
  448.   data = data..fdata..pdata
  449.  
  450.   local file = fs.open(inModelName, "wb")
  451.   file:write(data)
  452.   file:close()
  453.  
  454.   if type == 4 then print("Model succeful packed to "..inModelName)
  455.   elseif type == 5 then print("Model succeful packed to "..inModelName.." vertex frames count: "..fcount)
  456.   elseif type == 6 then print("Model succeful packed to "..inModelName.." palette frames count: "..pcount)
  457.   else print("Model succeful packed to "..inModelName.." vertex frames count: "..fcount.." palette frames count: "..pcount)
  458.   end
  459. end
  460.  
  461. ::gotoExit::
Advertisement
Add Comment
Please, Sign In to add comment