home *** CD-ROM | disk | FTP | other *** search
/ Unreal Tools / UnrealTools.iso / ASEExport4Unreal.zip / ASEExport4Unreal.lua
Text File  |  2007-11-15  |  26KB  |  599 lines

  1. -- lua
  2. ---------------------------------------
  3. -- UnrealASE Exporter for Modo  v1.04 -
  4. ---------------------------------------
  5. -- AUTHOR: Zoltan Erdokovy (zoltan.erdokovy@gmail.com)
  6. --
  7. --
  8. -- This script saves the selected layer and its child layers into an ASE file.
  9. -- IMPORTANT: This exporter exports ONLY the Unreal relevant parts of the ASE format!
  10. -- So you probably can't use it to transfer objects to application other than UnrealEd.
  11. -- Although DeepExploration shows the objects properly.
  12. --
  13. -- USAGE:
  14. -- The objects will be exported to the "objectdir" directory, located in the "content directory".
  15. -- The "objectdir" variable can be changed bellow, the content dir can be set in the preferences window.
  16. -- The name of the exported file will be the name of the selected layer.
  17. -- It exports the first selected layer and any kids it has. (Child layers don't have to be selected.)
  18. -- The children layers should contain the collision primitives, with the proper name. (MCDSP/MCDCX for UT2k4 and UCX/USP for U3)
  19. -- The exporter exports the following vertex maps:
  20. -- UV called "UV1"
  21. -- UV called "UV2"
  22. -- UV called "UV3"
  23. -- RGB map called "Color"
  24. -- If no vertexmap found with these names, then it assigns 0,0,0 automatically.
  25. -- Set all your materials to a 89 degrees smoothing and use the separated polygon technique to achieve
  26. -- proper shading. Unreal disregards smoothinggroup ID >32, so this exporter reuses the 0-32 range. Sometimes 
  27. -- this results in smoothing together otherwise independent, neighbouring poly islands. To fix this just cut and 
  28. -- paste one of them to change the order of the polygons.
  29. -- Sometimes smoothing groups are not exported properly. A re-export after restarting modo will fix it.
  30. --
  31. -- You can set what unit in modo you want to be 1 unit in unreal. Check out the "UnitSystem" variable bellow.
  32. -- I recommend using gameunits, but you can use a few other units, the object will be scaled properly.
  33. --
  34. -- Known issues:
  35. -- You have to edit the parameters in the script. It would need too many arguments to define all aspects
  36. -- of the export, I think. But if you want this changed, just drop me a mail.
  37. --
  38. -- If you find a bug or have a feature requests don't hesitate to contact me. :)
  39. --
  40. --
  41. -- Changes in v1.04:
  42. --
  43. -- - Fixed smoothing group numbering.
  44. -- - Fixed errors when something was selected.
  45. -- - Fixed default value for content dir.
  46. --
  47. --
  48. -- Changes in v1.03:
  49. --
  50. -- - Fixed precision when scaling from game units.
  51. -- - Fixed export when no partname is assigned to polys.
  52. -- - Fixed smoothing group generation.
  53. -- - 3 UV support.
  54. --
  55. --
  56. -- Changes in v1.02:
  57. --
  58. -- - Fixed quad/ngon handling, fixed discontinuos UVs.
  59. --
  60. --
  61. -- Changes in v1.01:
  62. --
  63. -- - Fixed object rotation.
  64. -- - Added scale factors when using different unit systems.
  65.  
  66.  version = "v1.04"
  67.  contentdir = "c:"
  68.  objectdir = "/!Export" -- The proper directory to store exported objects.
  69.  
  70.  UnitSystem = "METER" -- Set what you want to be 1 unreal unit:
  71.                          -- "GAMEUNIT", "METER", "MILLIMETER", "FEET", "INCH".
  72.  
  73.  TempFileName = "temp.lxo"     -- The temp file's name.
  74.  bSaveTempFile = false         -- If true it saves the temporary scene to a file, next to the exported files.
  75. -----------------------------
  76.  UV1Name = "UV1"
  77.  UV2Name = "UV2"
  78.  UV3Name = "UV3"
  79.  VColName = "Color"
  80.  
  81.  
  82. --           --
  83. -- FORMATNUM --
  84. --           --
  85. function FormatNum (Num)
  86.      return (string.format("%.4f", Num))
  87. end
  88.  
  89. --               --
  90. -- ASSIGNSGROUPS --
  91. --               --
  92. function AssignSGroups ()
  93.  
  94.      SGroup = 0            -- The actual smoothing group.
  95.     
  96.     --lx("select.drop polygon")
  97.     
  98.     for i = 0, FaceNum-1 do
  99.         SelectLayer(1)
  100.         if  FaceSGroups[i] == nil then                    -- If we have no stored smg...
  101.             lx("select.element [1] polygon add ["..i.."]")    -- Select face #i on the first layer.
  102.             lx("select.connect")                        -- Select connected faces.
  103.             --lxq("query layerservice layer.name ? 1")
  104.             ActSel = lxq("query layerservice polys ? selected")    -- We get back the array of indexes of selected polys.
  105.             ActSelSize = table.getn(ActSel)                -- Get the number of selected polys.
  106.             
  107.             for j = 1, ActSelSize do                    -- Go through all selected polys.
  108.                 if FaceSGroups[tonumber(ActSel[j])] == nil then            -- If we have no stored data there...
  109.                     FaceSGroups[tonumber(ActSel[j])] = SGroup            -- We set the smg.
  110.                 end
  111.                 --lxout("tonumber(ActSel[j]) == "..tonumber(ActSel[j]))
  112.             end
  113.             --lx("select.drop polygon")                    -- Deselect everything.
  114.             SGroup = SGroup+1                            -- Increase the smg number.
  115.             if SGroup == 33 then SGroup = 0 end            -- If we have reached the 32 SMG limit then we start over.
  116.         else
  117.         end
  118.     end
  119. end
  120.  
  121. --               --
  122. -- GETFACEPOINTS --
  123. --               --
  124. function GetFacePoints (FaceIndex)
  125.      p = lxq("query layerservice poly.vertList ? "..FaceIndex)
  126.      return ({p[1],p[2],p[3]})
  127. end
  128.  
  129. --                  --
  130. -- GETPOINTPOSITION --
  131. --                  --
  132. function GetPointPosition (PointIndex)
  133.      p = lxq("query layerservice vert.pos ? "..PointIndex)  -- Getting original coordinates.
  134. -- Rotating the object so it will be in the proper position in UEd. --
  135.  
  136.      p = {p[1], p[3], -p[2]}  --  X,Z,-Y  = 90  around Unreal X
  137.      p = {-p[1], p[2], -p[3]} -- -X,Y,-Z  = 180 around Unreal Y
  138.      p = {-p[2], p[1], p[3]}  --  -Y,X,Z  = 90  around Unreal Z
  139.      p = {p[1]*UnitScale, p[2]*UnitScale, p[3]*UnitScale}  -- Scale properly.
  140.  
  141.      return ({FormatNum(p[1]),FormatNum(p[2]),FormatNum(p[3])})
  142. end
  143.  
  144. --             --
  145. -- UVSETEXISTS --
  146. --             --
  147. function UVSetExists (TargetUVName)
  148.  
  149.     lxq("query layerservice vmap_groups ? all")
  150.      VmapNum = lxq("query layerservice vmap.n ? all")[1]
  151.      for i = 0, VmapNum-1 do
  152.           ActVmapType = lxq("query layerservice vmap.type ? "..i)[1]
  153.           ActVmapName = lxq("query layerservice vmap.name ? "..i)[1]
  154.           if ( ActVmapType == "texture") and ( ActVmapName == TargetUVName) then
  155.             return(true)
  156.         end
  157.     end
  158.     
  159.     return(false)
  160. end
  161.  
  162. --            --
  163. -- GETPOINTUV --
  164. --            --
  165. function GetPointUV (PointIndex, TargetUVName)
  166.      lxq("query layerservice vmap_groups ? all")
  167.      VmapNum = lxq("query layerservice vmap.n ? all")[1]
  168.      for i = 0, VmapNum-1 do
  169.           ActVmapType = lxq("query layerservice vmap.type ? "..i)[1]
  170.           ActVmapName = lxq("query layerservice vmap.name ? "..i)[1]
  171.           if ( ActVmapType == "texture") and ( ActVmapName == TargetUVName) then
  172.                p = lxq("query layerservice vert.vmapValue ? "..PointIndex)
  173.  
  174.                --if p == ("query layerservice vert.vmapValue ? "..PointIndex) then  -- !!! WORKAROUND !!!
  175.                --     p = nil                                                       -- If the point has no value on a vmap
  176.                --end                                                                -- then the query should give back nil,
  177.                                                                                   -- but now it gives back the query itself.
  178.                                                                                   -- If the bug gets squashed, this 3 lines
  179.                                                                                   -- can be removed.
  180.  
  181.                if p == nil then p = {"0.0000","0.0000"} end      -- Failsafe if a vertex doesn't have a UV value.
  182.           end
  183.      end
  184.      return ({FormatNum(p[1]),FormatNum(p[2])})
  185. end
  186.  
  187. --               --
  188. -- GETPOINTCOLOR --
  189. --               --
  190. function GetPointColor (PointIndex)
  191.      p = {"0.0000","0.0000","0.0000"}
  192.      lxq("query layerservice vmap_groups ? all")
  193.      for i = 0, (lxq("query layerservice vmap.n ? all")[1])-1 do
  194.           ActVmapType = lxq("query layerservice vmap.type ? "..i)[1]
  195.           ActVmapName = lxq("query layerservice vmap.name ? "..i)[1]
  196.           if ( ActVmapType == "rgb") and ( ActVmapName == VColName) then
  197.                p = lxq("query layerservice vert.vmapValue ? "..PointIndex)
  198.  
  199.                --if p == ("query layerservice vert.vmapValue ? "..PointIndex) then  -- !!! WORKAROUND !!!
  200.                --     p = nil                                                       -- If the point has no value on a vmap
  201.                --end                                                                -- then the query should give back nil,
  202.                                                                                   -- but now it gives back the query itself.
  203.                                                                                   -- If the bug gets squashed, this 3 lines
  204.                                                                                   -- can be removed.
  205.  
  206.                if p == nil then p = {"1.0000","1.0000","1.0000"} end       -- Failsafe if a vertex doesn't have a color value.
  207.           end
  208.      end
  209.      return ({FormatNum(p[1]),FormatNum(p[2]),FormatNum(p[3])})
  210. end
  211.  
  212. --               --
  213. -- GETFACENORMAL --
  214. --               --
  215. function GetFaceNormal (FaceIndex)
  216.      p = lxq("query layerservice poly.normal ? "..FaceIndex)
  217.      return ({FormatNum(p[1]),FormatNum(p[2]),FormatNum(p[3])})
  218. end
  219.  
  220. --                --
  221. -- GETPOINTNORMAL --
  222. --                --
  223. function GetPointNormal (PointIndex)
  224.      p = lxq("query layerservice vert.normal ? "..PointIndex)
  225.      return ({FormatNum(p[1]),FormatNum(p[2]),FormatNum(p[3])})
  226. end
  227.  
  228. --                   --
  229. -- GETFACEMATERIALID --
  230. --                   --
  231. function GetFaceMaterialID (FaceIndex)
  232.      m = lxq("query layerservice poly.material ? "..FaceIndex)[1]  -- It gives back a material name, but we need an index.
  233.      for i = 0, (MaterialNum-1) do      -- Iterating through the materials.
  234.           if MaterialNames[i+1] == m then
  235.                MaterialID = i
  236.           end
  237.      end
  238.      return (MaterialID)        -- And return with the proper material index.
  239. end
  240.  
  241. --             --
  242. -- SELECTLAYER --
  243. --             --
  244.  
  245. function SelectLayer (LayerIndex)
  246.      lx("select.layer "..LayerIndex.." set")             -- Let's make absolutely damn sure...
  247.      lxq("query layerservice layer.name ? "..LayerIndex) -- ...that we have the given layer selected...
  248.      lxq("query layerservice layer.index ? fg")          -- ... in every possible way.
  249. end
  250.  
  251.  
  252.  
  253. --      --
  254. -- MAIN --
  255. --      --
  256. lxout("------- ASE conversion started. -------")
  257. lxout("("..version..")")
  258. StartTime = os.time()
  259.  
  260.  MainLayer = 0       -- The index of the main layer.
  261.  MainLayerName = ""  -- The name of the main layer.
  262.  ActLayer = 8        -- The index of the layer we are working on.
  263.  ChildrenNum = 0     -- The number of children.
  264.  ChildrenLayers = {} -- Array for indices of child layers.
  265.  ChildrenNames = {}  -- Array for names of child layers.
  266.  Layers = {}         -- The indices of all relevant layers: main layer + any children.
  267.  LayerNames = {}     -- The names of all relevant layers: main layer + any children.
  268.  LayerNum = 0        -- The number of all relevant layers.
  269.  MaterialNum = 0     -- The number of materials.
  270.  MaterialNames = {}  -- Array for material names.
  271.  
  272.  FacePoints = {}     -- Array for the point indices of a face.
  273.  FaceSGroups = {}    -- Array of numbers, one for each face, representing smoothing groups.
  274.  
  275.  Pos = {}            -- Array for point positions in both 3D and UV space.
  276.  
  277.  
  278.  ProcFaceNum = 0     -- The total number of processed faces.
  279.  
  280. -- Determining scale factor for different unit systems --
  281.  
  282. if UnitSystem == "GAMEUNIT" then UnitScale = 53.3333
  283. elseif UnitSystem == "METER" then UnitScale = 1
  284. elseif UnitSystem == "MILLIMETER" then UnitScale = 1000
  285. elseif UnitSystem == "FEET" then UnitScale = 3.2808398950131
  286. elseif UnitSystem == "INCH" then UnitScale = 39.3700787
  287. else UnitScale = 1 end
  288.  
  289. -- Dropping every selection --
  290. --lx("select.drop vertex")
  291. --lx("select.drop edge")
  292. --lx("select.drop polygon")
  293. --lx("select.vertexMap \"\" txuv replace")
  294. --lx("select.invert")
  295.  
  296. -- Setting up directories --
  297. contentdir = lxq("pref.value lwio.lwoContentDir ?")
  298. lxout("> Content dir: "..contentdir[1])
  299. if (contentdir == nil) then error("Please set the content directory.") end
  300. contentdir = contentdir[1]
  301. string.gsub(contentdir,"\\","/")                   -- Replacing all "\" to "/".
  302. savedir = contentdir..objectdir                    -- Adding the proper object dir to the final path.
  303.  
  304. -- Collecting layer data --
  305.  
  306. MainLayer = lxq("query layerservice layer.index ? fg")[1]       -- We need only the first selected layer.
  307. MainLayerName = lxq("query layerservice layer.name ? fg")[1]    -- We use the name of the first fg layer as export name.
  308. lxout("> MainLayerIndex: "..MainLayer)
  309.  
  310. ChildrenNum = lxq("query layerservice layer.childCount ? "..MainLayer)[1]  -- Get child count.
  311. lxout("> ChildrenNum: "..ChildrenNum)
  312. if ChildrenNum ~= 0 then                                 -- If there are children, then get info about them.
  313.      ChildrenLayers = lxq("query layerservice layer.children ? "..MainLayer)
  314.      for i=1, ChildrenNum do
  315.           -- !!!WORKAROUND!!! -- We add +1 to the recieved layer indices to fix a bug in the layer.children query.
  316.           ChildrenLayers[i] = ChildrenLayers[i]+1
  317.           lxout("> Child "..i.." index: "..ChildrenLayers[i])
  318.           -- Collecting children data --
  319.           ChildrenNames[i] = lxq("query layerservice layer.name ? "..ChildrenLayers[i])[1]
  320.           lxout("> Child "..i.." name: "..ChildrenNames[i])
  321.      end
  322.  
  323.      -- Making arrays for all relevant layer data --
  324.      Layers = ChildrenLayers
  325.      table.insert(Layers,1,MainLayer)                    -- Collect the indices of all relevant layers.
  326.      LayerNames = ChildrenNames
  327.      table.insert(LayerNames,1,MainLayerName)            -- Collect the names of all relevant layers.
  328.      LayerNum = ChildrenNum+1                            -- Compute the number of the relevant layers.
  329. else                                                     -- If no children, then we set layer data of the mainlayer.
  330.      Layers = {MainLayer}
  331.      LayerNames = {MainLayerName}
  332.      LayerNum = 1
  333. end
  334.  
  335. -- Copying data to a new scene --
  336. lxout("- Copying data to a new scene. -")
  337. OriginalScene = lxq("query sceneservice scene.index ? current")[1]  -- Store the index of the source scene.
  338. lx("scene.new")
  339. NewScene = lxq("query sceneservice scene.index ? current")[1]       -- Store the index of the new scene.
  340.  
  341. for i = 1, LayerNum do      -- Iterating through the layers.
  342.      lx("scene.set "..OriginalScene)                     -- Go back from the new scene to the original.
  343.      SelectLayer(Layers[i])                              -- Select the proper layer.
  344.      lx("select.copy")                                   -- Copy layer contents.
  345.      lx("scene.set "..NewScene)                          -- Go to the new scene.
  346.      SelectLayer(i)                                      -- Select the next empty layer.
  347.      lx("select.paste")                                  -- Paste stuff.
  348.      lx("item.name "..LayerNames[i].." mesh")            -- Set proper name.
  349.      if (i < LayerNum) then                              -- If there are children, and we are not working with the last of them...
  350.           lx("layer.newItem mesh")                       -- ... then we make a new empty layer for the next one.
  351.      end
  352. end
  353.  
  354.  
  355. -- Preparing files --
  356.  
  357. fileOutName = savedir.."/"..MainLayerName..".ase"
  358. TempFileName = savedir.."/"..TempFileName
  359. fileOut = io.open(fileOutName, "w+")
  360. if (fileOut == nil) then error("Can't open "..fileOutName.."!") end
  361.  
  362. -- Writing data to file --
  363.  
  364. -- Header --
  365. fileOut:write("*3DSMAX_ASCIIEXPORT 200\n")
  366. fileOut:write("*COMMENT \"Generated by ASEExport4Unreal v1.0\" \n")
  367.  
  368. -- Scene --
  369. fileOut:write("*SCENE {\n")
  370. fileOut:write("\t*SCENE_FILENAME \""..LayerNames[1].."\"\n")
  371. fileOut:write("\t*SCENE_FIRSTFRAME 0\n")
  372. fileOut:write("\t*SCENE_LASTFRAME 100\n")
  373. fileOut:write("\t*SCENE_FRAMESPEED 30\n")
  374. fileOut:write("\t*SCENE_TICKSPERFRAME 160\n")
  375. fileOut:write("\t*SCENE_BACKGROUND_STATIC 0.0000\t0.0000\t0.0000\n")
  376. fileOut:write("\t*SCENE_AMBIENT_STATIC 0.0000\t0.0000\t0.0000\n")
  377. fileOut:write("}\n")
  378.  
  379. ---------------------------
  380. -- Proccessing materials --
  381. ---------------------------
  382. lxout("- Proccessing materials -")
  383.  
  384.  
  385. SelectLayer(1)                -- Select te first layer, where we actually care about materials.
  386.                               -- This is the render object, all other layers are for collision.
  387.  
  388. MaterialNum = lxq("query layerservice material.n ? all")[1]
  389. --lxout("> Material number: "..MaterialNum)
  390. for j = 1, MaterialNum do
  391.      MaterialNames[j] = lxq("query layerservice material.name ? "..j-1)[1]
  392. end
  393.  
  394. fileOut:write("*MATERIAL_LIST {\n")
  395.  
  396. fileOut:write("\t*MATERIAL_COUNT 1 \n")
  397. fileOut:write("\t*MATERIAL 0 {\n")
  398. fileOut:write("\t\t*MATERIAL_NAME \""..MaterialNames[1].."\"\n")
  399. fileOut:write("\t\t*MATERIAL_CLASS \"Multi/Sub-Object\" \n")
  400. fileOut:write("\t\t*NUMSUBMTLS "..MaterialNum.."\n")
  401.  
  402. for i = 1, MaterialNum do      -- Iterating through the materials which become submaterials.
  403.      fileOut:write("\t\t*SUBMATERIAL "..(i-1).." { \n")
  404.      fileOut:write("\t\t\t*MATERIAL_NAME \""..MaterialNames[i].."\"\n")
  405.      fileOut:write("\t\t\t*MATERIAL_CLASS \"Standard\" \n")
  406.      fileOut:write("\t\t\t*MAP_DIFFUSE {\n")
  407.      fileOut:write("\t\t\t\t*MAP_NAME \""..MaterialNames[i].."\"\n")
  408.      fileOut:write("\t\t\t\t*BITMAP \"c:\\"..MaterialNames[i]..".tga\"\n")
  409.     fileOut:write("\t\t\t\t*UVW_U_TILING 1.0000 \n")
  410.     fileOut:write("\t\t\t\t*UVW_V_TILING 1.0000 \n")
  411.      fileOut:write("\t\t\t}\n")
  412.      fileOut:write("\t\t}\n")
  413. end
  414. fileOut:write("\t}\n")
  415. fileOut:write("}\n")
  416.  
  417. --------------------------
  418. -- Proccessing geometry --
  419. --------------------------
  420.  
  421. lxout("- Proccessing geometry -")
  422. for ActLayer = 1, LayerNum do      -- Iterating through the layers.
  423.      SelectLayer(ActLayer)
  424.  
  425.      lx("select.type polygon")
  426.      lx("poly.triple")
  427.  
  428.      Faces = lxq("query layerservice polys ? all")    -- Getting the list of faces.
  429.      FaceNum = table.getn(Faces)
  430.      ProcFaceNum = ProcFaceNum + FaceNum
  431.  
  432.      if ActLayer == 1 then    -- We only bother with smoothing groups in the case of layer #1.
  433.           AssignSGroups()     -- Assigning the smoothing groups before the unweld destroys poly islands.
  434.      end
  435.      lx("select.type polygon")
  436.      lx("vert.split")       -- Unweld, so every vertex has it's own UV coordinates.
  437.      SelectLayer(ActLayer)  -- Reselect layer to make sure internal data is updated.
  438.      Vertices = lxq("query layerservice verts ? all")   -- Getting the list of vertices.
  439.      VertexNum = table.getn(Vertices)
  440.  
  441.      fileOut:write("*GEOMOBJECT {\n")
  442.      fileOut:write("\t*NODE_NAME \""..LayerNames[ActLayer].."\"\n")
  443.  
  444.      -- Geometry - Node --
  445.      fileOut:write("\t*NODE_TM {\n")
  446.      fileOut:write("\t\t*NODE_NAME \""..LayerNames[ActLayer].."\"\n")
  447.      fileOut:write("\t}\n")
  448.  
  449.      -- Geometry - Mesh --
  450.      fileOut:write("\t*MESH {\n" )
  451.      fileOut:write("\t\t*MESH_NUMVERTEX "..VertexNum.."\n")
  452.      fileOut:write("\t\t*MESH_NUMFACES "..FaceNum.."\n")
  453.  
  454.      -- Geometry - Mesh - Vertex list --
  455.      fileOut:write("\t\t*MESH_VERTEX_LIST {\n")
  456.      for j = 0, (VertexNum-1) do      -- Iterating through the vertices.
  457.           Pos = GetPointPosition(j)
  458.           fileOut:write("\t\t\t*MESH_VERTEX\t"..j.."\t"..Pos[1].."\t"..Pos[2].."\t"..Pos[3].."\n")
  459.      end
  460.      fileOut:write("\t\t}\n")
  461.  
  462.      -- Geometry - Mesh - Face list --
  463.      fileOut:write("\t\t*MESH_FACE_LIST {\n")
  464.      for j = 0, (FaceNum-1) do      -- Iterating through the faces.
  465.           FacePoints = GetFacePoints(j)
  466.           fileOut:write("\t\t\t*MESH_FACE\t"..j..":\tA:\t"..FacePoints[1].." B:\t"..FacePoints[2].." C:\t"..FacePoints[3])
  467.           if ActLayer == 1 then
  468.                -- If the actual layer is #1 then we assign the proper material ID.
  469.                fileOut:write(" AB:\t1 BC:\t1 CA:\t0\t*MESH_SMOOTHING "..FaceSGroups[j].."\t*MESH_MTLID "..GetFaceMaterialID(j).."\n")
  470.           else
  471.                -- If the actual layer is not #1 then it's for collision info, so we force material #1, and prevent storing
  472.                -- unused material references in the object.
  473.                fileOut:write(" AB:\t1 BC:\t1 CA:\t0\t*MESH_SMOOTHING 0\t*MESH_MTLID 1 \n")
  474.           end
  475.      end
  476.      fileOut:write("\t\t}\n")
  477.  
  478. ---------------------
  479. -- Proccessing UVs --
  480. ---------------------
  481.      -- Texture - Vertex list - UV1 --
  482.      fileOut:write("\t\t*MESH_NUMTVERTEX "..VertexNum.."\n")
  483.      fileOut:write("\t\t*MESH_TVERTLIST {\n")
  484.      for j = 0, (VertexNum-1) do      -- Iterating through the vertices.
  485.           UVPos = GetPointUV(j,UV1Name)
  486.           fileOut:write("\t\t\t*MESH_TVERT "..j.."\t"..UVPos[1].."\t"..UVPos[2].."\t0.0000\n")
  487.      end
  488.      fileOut:write("\t\t}\n")  -- Closing MESH_TVERTLIST
  489.  
  490.      -- Texture - Face list --
  491.      fileOut:write("\t\t*MESH_NUMTVFACES "..FaceNum.."\n")
  492.      fileOut:write("\t\t*MESH_TFACELIST {\n")
  493.      for j = 0, (FaceNum-1) do      -- Iterating through the faces.
  494.           FacePoints = GetFacePoints(j)
  495.           fileOut:write("\t\t\t*MESH_TFACE\t"..j.."\t"..FacePoints[1].."\t"..FacePoints[2].."\t"..FacePoints[3].."\n")
  496.      end
  497.      fileOut:write("\t\t}\n")  -- Closing MESH_TFACELIST
  498.     
  499.      fileOut:write("\t\t*MESH_MAPPINGCHANNEL 2 {\n")
  500.  
  501.      -- Texture - Vertex list - UV2 --
  502.      fileOut:write("\t\t\t*MESH_NUMTVERTEX "..VertexNum.."\n")
  503.      fileOut:write("\t\t\t*MESH_TVERTLIST {\n")
  504.      for j = 0, (VertexNum-1) do      -- Iterating through the vertices.
  505.           UVPos = GetPointUV(j,UV2Name)
  506.           fileOut:write("\t\t\t\t*MESH_TVERT\t"..j.."\t"..UVPos[1].."\t"..UVPos[2].."\t0.0000\n")
  507.      end
  508.      fileOut:write("\t\t\t}\n")  -- Closing MESH_TVERTLIST
  509.  
  510.      -- Texture - Face list --
  511.      fileOut:write("\t\t\t*MESH_NUMTVFACES "..FaceNum.."\n")
  512.      fileOut:write("\t\t\t*MESH_TFACELIST {\n")
  513.      for j = 0, (FaceNum-1) do      -- Iterating through the faces.
  514.           FacePoints = GetFacePoints(j)
  515.           fileOut:write("\t\t\t\t*MESH_TFACE\t"..j.."\t"..FacePoints[1].."\t"..FacePoints[2].."\t"..FacePoints[3].."\n")
  516.      end
  517.     
  518.      fileOut:write("\t\t\t}\n" )  -- Closing MESH_TFACELIST
  519.      fileOut:write("\t\t}\n")  -- Closing MESH_MAPPINGCHANNEL 2
  520.     
  521.     
  522.     if UVSetExists(UV3Name) then    -- If UV3 exists then we bother with writing it to the file.
  523.         fileOut:write("\t\t*MESH_MAPPINGCHANNEL 3 {\n")
  524.          -- Texture - Vertex list - UV3 --
  525.          fileOut:write("\t\t\t*MESH_NUMTVERTEX "..VertexNum.."\n")
  526.          fileOut:write("\t\t\t*MESH_TVERTLIST {\n")
  527.          for j = 0, (VertexNum-1) do      -- Iterating through the vertices.
  528.               UVPos = GetPointUV(j,UV3Name)
  529.               fileOut:write("\t\t\t\t*MESH_TVERT\t"..j.."\t"..UVPos[1].."\t"..UVPos[2].."\t0.0000\n")
  530.          end
  531.          fileOut:write("\t\t\t}\n")  -- Closing MESH_TVERTLIST
  532.          -- Texture - Face list --
  533.          fileOut:write("\t\t\t*MESH_NUMTVFACES "..FaceNum.."\n")
  534.          fileOut:write("\t\t\t*MESH_TFACELIST {\n")
  535.          for j = 0, (FaceNum-1) do      -- Iterating through the faces.
  536.               FacePoints = GetFacePoints(j)
  537.               fileOut:write("\t\t\t\t*MESH_TFACE\t"..j.."\t"..FacePoints[1].."\t"..FacePoints[2].."\t"..FacePoints[3].."\n")
  538.          end
  539.          fileOut:write("\t\t\t}\n" )  -- Closing MESH_TFACELIST
  540.          fileOut:write("\t\t}\n")  -- Closing MESH_MAPPINGCHANNEL 3
  541.     end
  542.     
  543.  
  544. ------------------------------
  545. -- Proccessing vertex color --
  546. ------------------------------
  547.      -- VertexColor - Vertex list --
  548.      fileOut:write("\t\t*MESH_NUMCVERTEX "..VertexNum.."\n")
  549.      fileOut:write("\t\t*MESH_CVERTLIST {\n")
  550.      for j = 0, (VertexNum-1) do      -- Iterating through the vertices.
  551.           Col = GetPointColor(j)
  552.           fileOut:write("\t\t\t*MESH_VERTCOL\t"..j.."\t"..Col[1].."\t"..Col[2].."\t"..Col[3].."\n")
  553.      end
  554.      fileOut:write("\t\t}\n" )
  555.  
  556.      -- VertexColor - Face list --
  557.      fileOut:write("\t\t*MESH_NUMCVFACES "..FaceNum.."\n")
  558.      fileOut:write("\t\t*MESH_CFACELIST {\n")
  559.      for j = 0, (FaceNum-1) do      -- Iterating through the faces.
  560.           FacePoints = GetFacePoints(j)
  561.           fileOut:write("\t\t\t*MESH_CFACE\t"..j.."\t"..FacePoints[1].."\t"..FacePoints[2].."\t"..FacePoints[3].."\n")
  562.      end
  563.      fileOut:write("\t\t}\n")
  564.  
  565. -------------------------
  566. -- Proccessing normals --
  567. -------------------------
  568.      fileOut:write("\t\t*MESH_NORMALS {\n")
  569.      for j = 0, (FaceNum-1) do      -- Iterating through the faces.
  570.           Normal = GetFaceNormal(j)
  571.           fileOut:write("\t\t\t*MESH_FACENORMAL\t"..j.."\t"..Normal[1].."\t"..Normal[2].."\t"..Normal[3].."\n")
  572.           FacePoints = GetFacePoints(j)
  573.           for k = 1, 3 do      -- Iterating through the points of the actual face.
  574.                Normal = GetPointNormal(FacePoints[k])
  575.                fileOut:write("\t\t\t\t*MESH_VERTEXNORMAL\t"..FacePoints[k].."\t"..Normal[1].."\t"..Normal[2].."\t"..Normal[3].."\n")
  576.           end
  577.      end
  578.      fileOut:write("\t\t}\n" )
  579.      fileOut:write("\t}\n" )
  580.      fileOut:write("\t*MATERIAL_REF 0\n" )
  581.      fileOut:write("}\n" )
  582. end
  583.  
  584.  
  585.  
  586. -----------------
  587. -- Cleaning up --
  588. -----------------
  589. if bSaveTempFile then lx("!scene.saveAs filename:\""..TempFileName.."\"") end
  590. lx("!scene.close")                                          -- Closing scene with suppressed dialog.
  591. fileOut:close()
  592. SelectLayer(MainLayer)            -- Going back to the original layer.
  593.  
  594. EndTime = os.time()
  595. ExportTime = os.difftime(EndTime, StartTime)
  596. lxout("Export took "..ExportTime.." seconds.")
  597. lxout("Total number of processed polygons: "..ProcFaceNum)
  598. lxout("Speed: "..(ProcFaceNum / ExportTime).." polygons/sec.")
  599. lxout("------- Object exported. -------")