home *** CD-ROM | disk | FTP | other *** search
/ Xentax forum attachments archive / xentax.7z / 16334 / nineTools.7z / smt_nine_mdl.ms < prev   
Encoding:
Text File  |  2019-06-09  |  17.9 KB  |  726 lines

  1. -- Config
  2. global cfg_EnableSkin = true;
  3.  
  4. -- Globals
  5. global g_ioContext = undefined;
  6.  
  7. -- Functions
  8.  
  9. -- Cache commonly used interface functions
  10. global _bit_SwapBytes = bit.SwapBytes;
  11. global _bit_And = bit.And;
  12. global _bit_IntAsFloat = bit.IntAsFloat;
  13. global _bit_Get = bit.Get;
  14. global _bit_IntAsChar = bit.intAsChar;
  15. global _bonesys_createbone = bonesys.createbone;
  16. global _skinOps_AddBone = skinOps.AddBone;
  17. global _modPanel_SetCurrentObject = modPanel.SetCurrentObject;
  18. global _skinOps_ReplaceVertexWeights = skinOps.ReplaceVertexWeights;
  19. global _skinOps_SetVertexWeights = skinOps.SetVertexWeights;
  20.  
  21. -- Utility
  22. fn utilSwap16 value =
  23. (
  24.     _bit_SwapBytes value 1 2
  25. )
  26.  
  27. fn utilSwap32 value =
  28. (
  29.     _bit_SwapBytes ( _bit_SwapBytes value 1 4 ) 2 3
  30. )
  31.  
  32. fn utilSwapFloat value =
  33. (
  34.     _bit_IntAsFloat ( _bit_SwapBytes ( _bit_SwapBytes value 1 4 ) 2 3 )
  35. )
  36.  
  37. fn utilAllBitsSet value mask =
  38. (
  39.     ( _bit_And value mask ) == mask;
  40. )
  41.  
  42. fn utilInitList count  =
  43. (
  44.     local list = #();
  45.     
  46.     if ( count > 0 ) then
  47.         list[count] = undefined;
  48.     
  49.     list;
  50. )
  51.  
  52. fn utilVector3YToZUp value =
  53. (
  54.     local temp = value.Y;
  55.     value.Y = -value.Z;
  56.     value.Z = temp;   
  57.     value;
  58. )
  59.  
  60. -- File IO
  61. ioEndian_Little = 0
  62. ioEndian_Big = 1
  63.  
  64. struct ioContext
  65. (
  66.     Stream,
  67.     FileName,
  68.     FilePath,
  69.     Endianness,
  70.     Swap,
  71.     BasePositions,
  72.     BasePositionIndex,
  73.     BasePosition,
  74.     SavedPositions,
  75.     SavedPositionIndex
  76. )
  77.  
  78. fn ioOpenFile filePath =
  79. (
  80.     g_ioContext = ioContext();
  81.     g_ioContext.Stream = fopen filePath #rb;
  82.     g_ioContext.FileName = GetFilenameFile filePath;
  83.     g_ioContext.FilePath = GetFilenamePath filePath;
  84.     g_ioContext.Endianness = ioEndian_Little;
  85.     g_ioContext.Swap = false;
  86.     g_ioContext.BasePositions = #( 0 );
  87.     g_ioContext.BasePositionIndex = 1;
  88.     g_ioContext.BasePosition = 0;
  89.     g_ioContext.SavedPositions = #();
  90.     g_ioContext.SavedPositionIndex = 0;
  91. )
  92.  
  93. fn ioSelectOpenFile category ext =
  94. (
  95.     local typesStr = category + "(*." + ext[1];
  96.     for i = 2 to ext.Count do
  97.     (
  98.         typesStr += ",*." + ext[i];
  99.     )
  100.     typesStr += ")|*." + ext[1];
  101.     for i = 2 to ext.Count do
  102.     (
  103.         typesStr += ";*." + ext[i];
  104.     )
  105.     
  106.     local filePath = getOpenFileName \ 
  107.         caption:("Open " + category + " file")\
  108.         types:typesStr \
  109.         historyCategory:( category + " Object Presets" )
  110.     
  111.     filePath;
  112. )
  113.  
  114. fn ioGetFileName =
  115. (
  116.     g_ioContext.FileName;
  117. )
  118.  
  119. fn ioGetFilePath =
  120. (
  121.     g_ioContext.FilePath;
  122. )
  123.  
  124. fn ioSetEndianness endian =
  125. (
  126.     g_ioContext.Endianness = endian;
  127.     g_ioContext.Swap = g_ioContext.Endianness == ioEndian_Big;
  128. )
  129.  
  130. fn ioTell =
  131. (
  132.     FTell g_ioContext.Stream;
  133. )
  134.  
  135. fn ioPushBase =
  136. (
  137.     g_ioContext.BasePositionIndex += 1;
  138.     g_ioContext.BasePosition = g_ioContext.BasePositions[ g_ioContext.BasePositionIndex ] = ioTell();
  139. )
  140.  
  141. fn ioPush =
  142. (
  143.     --print( "ioPush (0x" + ( bit.intashex(ioTell()) as string ) + ")" );
  144.     g_ioContext.SavedPositionIndex += 1;
  145.     g_ioContext.SavedPositions[ g_ioContext.SavedPositionIndex ] = ioTell();
  146. )
  147.  
  148. fn ioPopBase =
  149. (
  150.     g_ioContext.BasePositionIndex -= 1;
  151.     g_ioContext.BasePosition = g_ioContext.BasePositions[ g_ioContext.BasePositionIndex ];
  152. )
  153.  
  154. fn ioSeekSetAbs position = ()
  155.  
  156. fn ioPop =
  157. (
  158.     --print( "ioPop (0x" + ( bit.intashex(ioTell()) as string ) + ")" );
  159.     local savedPosition = g_ioContext.SavedPositions[ g_ioContext.SavedPositionIndex ];
  160.     g_ioContext.SavedPositionIndex -= 1;
  161.     ioSeekSetAbs( savedPosition );
  162. )
  163.  
  164. fn ioSeekCur position =
  165. (
  166.     FSeek g_ioContext.Stream position #seek_cur;
  167. )
  168.  
  169. fn ioSeekSetAbs position =
  170. (
  171.     FSeek g_ioContext.Stream position #seek_set;
  172. )
  173.  
  174. fn ioSeekSet position =
  175. (
  176.     FSeek g_ioContext.Stream ( g_ioContext.BasePosition + position ) #seek_set;
  177. )
  178.  
  179. fn ioReadU8 =
  180. (
  181.     ReadByte g_ioContext.Stream #unsigned;
  182. )
  183.  
  184. fn ioReadS16 =
  185. (
  186.     local value = ReadShort g_ioContext.Stream #signed;
  187.     if ( g_ioContext.Swap ) then value = utilSwap16( value );
  188.     value;
  189. )
  190.  
  191. fn ioReadU16 =
  192. (
  193.     local value = ReadShort g_ioContext.Stream #unsigned;
  194.     if ( g_ioContext.Swap ) then value = utilSwap16( value );
  195.     value;
  196. )
  197.  
  198. fn ioReadS32 =
  199. (
  200.     local value = ReadLong g_ioContext.Stream #signed;
  201.     if ( g_ioContext.Swap ) then value = utilSwap32( value );
  202.     value;
  203. )
  204.  
  205. fn ioReadU32 =
  206. (
  207.     local value = ReadLong g_ioContext.Stream #unsigned;
  208.     if ( g_ioContext.Swap ) then value = utilSwap32( value );
  209.     value;
  210. )
  211.  
  212. fn ioReadF32 =
  213. (
  214.     local value;
  215.     if ( g_ioContext.Swap ) then value = _bit_IntAsFloat( ioReadU32() );
  216.     else value = ReadFloat g_ioContext.Stream;
  217.     value;
  218. )
  219.  
  220. fn ioReadTexCoord =
  221. (
  222.     [ ioReadF32(), 1f - ioReadF32(), 0 ];
  223. )
  224.  
  225. fn ioReadVector2 =
  226. (
  227.     [ ioReadF32(), ioReadF32() ];
  228. )
  229.  
  230. fn ioReadVector3 =
  231. (
  232.     [ ioReadF32(), ioReadF32(), ioReadF32() ];
  233. )
  234.  
  235. fn ioReadVector4 =
  236. (
  237.     [ ioReadF32(), ioReadF32(), ioReadF32(), ioReadF32() ];
  238. )
  239.  
  240. fn ioReadQuaternion =
  241. (
  242.     quat (ioReadF32()) (ioReadF32()) (ioReadF32()) (ioReadF32());
  243. )
  244.  
  245. fn ioReadString =
  246. (
  247.     ReadString g_ioContext.Stream;
  248. )
  249.  
  250. struct nineAsset
  251. (
  252.     Magic,
  253.     Version,
  254.     Field08,
  255.     Field0C,
  256.     ContentOffset,
  257.     Content
  258. )
  259.  
  260. struct nineModel
  261. (
  262.     Field00,
  263.     VertexBufferSize,
  264.     TextureReferenceCount,
  265.     SkinBoneCount,
  266.     RootNodeOffset,
  267.     VertexBufferOffset,
  268.     TextureReferencesOffset,
  269.     SkinBoneMapOffset,
  270.     Field20,
  271.     Field24,
  272.     Field28,
  273.     Field2C,
  274.     Field30,
  275.     RootNode,
  276.     TextureReferences,
  277.     SkinBoneMap = #()
  278. )
  279.  
  280. struct nineNode
  281. (
  282.     ChildCount,
  283.     MeshCount,
  284.     ChildOffsetListOffset,
  285.     MeshListOffset,
  286.     Position,
  287.     Rotation,
  288.     Scale,
  289.     Field38,
  290.     Field3C,
  291.     Field40,
  292.     Field44,
  293.     Field48,
  294.     Children = #(),
  295.     Meshes = #(),
  296.     MaxBone
  297. )
  298.  
  299. struct nineMesh
  300. (
  301.     Field00, -- 1
  302.     IndexCount,
  303.     VertexCount,
  304.     VertexStartOffset, -- Relative offset
  305.     VertexStride,
  306.     VertexFlags, -- 0x23, 0x623 
  307.     BoundingBoxMaybe,
  308.     MaterialOffset, 
  309.     IndexStartOffset,
  310.     Field4C, -- 1
  311.     Field4E, -- 1
  312.     IndexStartOffset2, -- same as IndexStartOffset
  313.     Field54, -- 0
  314.     Field58, -- 1
  315.     Field5C, -- 0
  316.     Field60, -- 0
  317.     Field64,
  318.     VertexPositions = #(),
  319.     VertexNormals = #(),
  320.     VertexUVs = #(),
  321.     VertexBlendWeights = #(),
  322.     VertexBlendIndices = #(),
  323.     Triangles = #(),
  324.     Material,
  325.     MaxMesh
  326. )
  327.  
  328. struct nineMaterial
  329. (
  330.     TextureIndex
  331. )
  332.  
  333. fn nineMeshesRead count vertexBufferOffset textureReferences =
  334. (
  335.     local meshes = #();
  336.     for i = 1 to count do
  337.     (
  338.         local m = nineMesh();
  339.         m.Field00 = ioReadU32(); -- 1
  340.         m.IndexCount = ioReadU32();
  341.         m.VertexCount = ioReadU32();
  342.         m.VertexStartOffset = ioReadU32(); -- Relative offset
  343.         m.VertexStride = ioReadU16();
  344.         m.VertexFlags = ioReadU16(); -- 0x23 = ioReadU32(); 0x623 
  345.         ioSeekCur( 12 * 4 );
  346.         m.MaterialOffset = ioReadU32(); 
  347.         m.IndexStartOffset = ioReadU32();
  348.         m.Field4C = ioReadU16(); -- 1
  349.         m.Field4E = ioReadU16(); -- 1
  350.         m.IndexStartOffset2 = ioReadU32(); -- same as IndexStartOffset
  351.         m.Field54 = ioReadU32(); -- 0
  352.         m.Field58 = ioReadU32(); -- 1
  353.         m.Field5C = ioReadU32(); -- 0
  354.         m.Field60 = ioReadU32(); -- 0
  355.         m.Field64 = ioReadU32();
  356.         
  357.         --Assert( m.IndexStartOffset == m.IndexStartOffset2 );
  358.  
  359.         if ( vertexBufferOffset != 0 and m.VertexCount != 0 ) then
  360.         (
  361.             ioPush();
  362.             ioSeekSet( vertexBufferOffset + m.VertexStartOffset );
  363.             (
  364.                 case ( m.VertexStride ) of
  365.                 (
  366.                     24:
  367.                     for j = 1 to m.VertexCount do
  368.                     (
  369.                         m.VertexPositions[j] = ioReadVector3();
  370.                         m.VertexNormals[j] = ioReadVector3();
  371.                         m.VertexUVs[j] = [0,0,0];
  372.                     )
  373.                     
  374.                     32:
  375.                     for j = 1 to m.VertexCount do
  376.                     (
  377.                         m.VertexPositions[j] = ioReadVector3();
  378.                         m.VertexNormals[j] = ioReadVector3();
  379.                         m.VertexUVs[j] = ioReadTexCoord();
  380.                     )
  381.             
  382.                     52:
  383.                     for j = 1 to m.VertexCount do
  384.                     (
  385.                         m.VertexPositions[j] = ioReadVector3();
  386.                         m.VertexNormals[j] = ioReadVector3();
  387.                         
  388.                         local blendWeights = #();
  389.                         for k = 1 to 4 do
  390.                             blendWeights[k] = ioReadF32();
  391.                         
  392.                         m.VertexBlendWeights[j] = blendWeights;
  393.                         
  394.                         local blendIndices = #();
  395.                         for k = 1 to 4 do
  396.                             blendIndices[k] = ioReadU8() + 1;
  397.                         
  398.                         m.VertexBlendIndices[j] = blendIndices;
  399.                         m.VertexUVs[j] = ioReadTexCoord();
  400.                     )
  401.             
  402.                     default: ();
  403.                 )
  404.             )
  405.             ioPop();
  406.         )
  407.  
  408.         if ( m.IndexStartOffset != 0 and m.IndexCount != 0 ) then
  409.         (
  410.             ioPush();
  411.             ioSeekSet( m.IndexStartOffset );
  412.             m.Triangles = #();
  413.             
  414.             local a = ioReadU16() + 1;
  415.             local b = ioReadU16() + 1;
  416.             local direction = -1;
  417.             for j = 1 to m.IndexCount - 2 do
  418.             (
  419.                 local c = ioReadU16() + 1;
  420.                 
  421.                 direction *= -1;
  422.                 if ( a != b ) and ( b != c ) and ( c != a ) then 
  423.                 (
  424.                     if direction == 1 then append m.Triangles [a, b, c];
  425.                     else append m.Triangles [a, c, b];
  426.                 )
  427.                 
  428.                 a = b;
  429.                 b = c;
  430.             )
  431.             ioPop();
  432.         )
  433.         
  434.         if ( m.MaterialOffset != 0 ) then
  435.         (
  436.             ioPush();
  437.             ioSeekSet( m.MaterialOffset );
  438.             m.Material = nineMaterial();
  439.             m.Material.TextureIndex = ioReadU32() + 1;
  440.             ioPop();
  441.         )
  442.         
  443.         m.MaxMesh = mesh vertices:m.VertexPositions normals:m.VertexNormals faces:m.Triangles;
  444.         
  445.         -- Set up texture coordinates
  446.         m.MaxMesh.NumTVerts = m.VertexCount;
  447.         buildTVFaces m.MaxMesh;
  448.         for j = 1 to m.Triangles.Count do setTVFace m.MaxMesh j m.Triangles[j];
  449.         for j = 1 to m.VertexUVs.Count do setTVert m.MaxMesh j m.VertexUVs[j];
  450.             
  451.         -- Set up material
  452.         if ( m.Material != undefined ) then
  453.         (
  454.             local textureName = textureReferences[m.Material.TextureIndex];
  455.             m.MaxMesh.Material = standard();
  456.             m.MaxMesh.Material.Name = textureName + "_material";
  457.             m.MaxMesh.Material.DiffuseMap = Bitmaptexture filename:( ioGetFilePath() + "..\\textures\\" + textureName );
  458.             m.MaxMesh.Material.ShowinViewport = true; 
  459.             m.MaxMesh.BackFaceCull = on;
  460.         )
  461.         
  462.         meshes[i] = m;
  463.     )
  464.     
  465.     meshes;
  466. )
  467.  
  468. fn nineNodeRead parent vertexBufferOffset textureReferences &nodes =
  469. (
  470.     local n = nineNode();
  471.     append nodes n;
  472.     n.ChildCount = ioReadU32();
  473.     n.MeshCount = ioReadU32();
  474.     n.ChildOffsetListOffset = ioReadU32();
  475.     n.MeshListOffset = ioReadU32();
  476.     n.Position = ioReadVector3();
  477.     n.Rotation = ioReadQuaternion();
  478.     n.Scale = ioReadVector3();
  479.     n.Field38 = ioReadU32();
  480.     n.Field3C = ioReadU32();
  481.     n.Field40 = ioReadU32();
  482.     n.Field44 = ioReadU32();
  483.     n.Field48 = ioReadU32(); 
  484.     
  485.     local tfm = (Inverse n.Rotation) as matrix3;
  486.         tfm *= ScaleMatrix n.Scale;
  487.         tfm.row4 = n.Position;
  488.     
  489.     if ( parent != undefined ) then
  490.     (
  491.         tfm *= parent.MaxBone.transform;
  492.     )
  493.     
  494.     n.MaxBone = _bonesys_createbone \
  495.               tfm.row4    \
  496.               (tfm.row4 + 0.01 * (normalize tfm.row1)) \
  497.               (normalize tfm.row3);
  498.                       
  499.     --n.MaxBone.name = node.Name;
  500.     n.MaxBone.width  = 0.001;
  501.     n.MaxBone.height = 0.001;
  502.     n.MaxBone.transform = tfm;
  503.     n.MaxBone.setBoneEnable false 0;
  504.     n.MaxBone.wirecolor = yellow;
  505.     n.MaxBone.showlinks = true;
  506.     n.MaxBone.pos.controller      = TCB_position ();
  507.     n.MaxBone.rotation.controller = TCB_rotation ();
  508.     if ( parent != undefined ) then
  509.     (
  510.         n.MaxBone.Parent = parent.MaxBone;
  511.     )
  512.     
  513.     if ( n.MeshListOffset != 0 and n.MeshCount != 0 ) then
  514.     (
  515.         ioPush();
  516.         ioSeekSet( n.MeshListOffset );
  517.         n.Meshes = nineMeshesRead n.MeshCount vertexBufferOffset textureReferences;
  518.         for m in n.Meshes do
  519.         (
  520.             m.MaxMesh.Transform = n.MaxBone.Transform;
  521.             m.MaxMesh.Parent = n.MaxBone;
  522.         )
  523.         ioPop();
  524.     )
  525.  
  526.     if ( n.ChildOffsetListOffset != 0 ) then
  527.     (
  528.         ioPush();
  529.         ioSeekSet( n.ChildOffsetListOffset );
  530.         (
  531.             for i = 1 to n.ChildCount do
  532.             (
  533.                 local childOffset = ioReadU32();
  534.                 ioPush();
  535.                 ioSeekSet( childOffset );
  536.                 append n.Children (nineNodeRead n vertexBufferOffset textureReferences &nodes);
  537.                 ioPop();  
  538.             )
  539.         )
  540.         
  541.         ioPop();
  542.     )
  543.  
  544.     n;
  545. )
  546.  
  547. fn nineTextureReferencesRead count =
  548. (
  549.     local textureReferences = #();
  550.     for i = 1 to count do
  551.     (
  552.         local textureNameOffset = ioReadU32();
  553.         local field04 = ioReadU32();
  554.         local textureName = undefined;
  555.         if ( textureNameOffset != 0 ) then
  556.         (
  557.             ioPush();
  558.             ioSeekSet( TextureNameOffset );
  559.             textureName = ioReadString();
  560.             ioPop();
  561.         )
  562.         
  563.         textureReferences[i] = textureName;
  564.     )
  565.     
  566.     textureReferences;
  567. )
  568.  
  569. fn nineModelRead =
  570. (
  571.     local mdl = nineModel();
  572.     mdl.Field00 = ioReadU32();
  573.     mdl.VertexBufferSize = ioReadU32();
  574.     mdl.TextureReferenceCount = ioReadU32();
  575.     mdl.SkinBoneCount = ioReadU32();
  576.     mdl.RootNodeOffset = ioReadU32();
  577.     mdl.VertexBufferOffset = ioReadU32();
  578.     mdl.TextureReferencesOffset = ioReadU32();
  579.     mdl.SkinBoneMapOffset = ioReadU32();
  580.     mdl.Field20 = ioReadU32();
  581.     mdl.Field24 = ioReadU32();
  582.     mdl.Field28 = ioReadU32();
  583.     mdl.Field2C = ioReadU32();
  584.     mdl.Field30 = ioReadU32();
  585.     
  586.     if ( mdl.TextureReferencesOffset != 0 ) then
  587.     (
  588.         ioPush();
  589.         ioSeekSet( mdl.TextureReferencesOffset );
  590.         mdl.TextureReferences = nineTextureReferencesRead( mdl.TextureReferenceCount );
  591.         ioPop();
  592.     )
  593.     
  594.     local nodes = #();
  595.     
  596.     if ( mdl.RootNodeOffset != 0 ) then
  597.     (
  598.         ioPush();
  599.         ioSeekSet( mdl.RootNodeOffset );
  600.         mdl.RootNode = nineNodeRead undefined mdl.VertexBufferOffset mdl.TextureReferences &nodes;
  601.         ioPop();
  602.     )
  603.     
  604.     if ( mdl.SkinBoneMapOffset != 0 ) then
  605.     (
  606.         ioPush();
  607.         ioSeekSet( mdl.SkinBoneMapOffset );
  608.         for i = 1 to mdl.SkinBoneCount do
  609.         (
  610.             mdl.SkinBoneMap[i] = ioReadU32();
  611.         )
  612.         ioPop();
  613.     )
  614.     
  615.     -- Set up weights
  616.     if ( cfg_EnableSkin ) then
  617.     (
  618.         for n in nodes do
  619.         (
  620.             for m in n.Meshes do
  621.             (
  622.                 if ( m.VertexBlendWeights.Count > 0 ) then 
  623.                 (                
  624.                     resumeEditing();
  625.                     max modify mode;
  626.                     
  627.                     select m.MaxMesh;
  628.                     local skinMod = skin();
  629.                     addModifier m.MaxMesh skinMod;
  630.                     
  631.                     -- Add used bones to the skin modifier
  632.                     for j = 1 to mdl.SkinBoneMap.Count do
  633.                     (
  634.                         _skinOps_AddBone skinMod nodes[mdl.SkinBoneMap[j]].MaxBone 0;
  635.                     )
  636.                     
  637.                     _modPanel_SetCurrentObject skinMod;
  638.                     for j = 1 to m.VertexCount do
  639.                        _skinOps_ReplaceVertexWeights skinMod j m.VertexBlendIndices[j] m.VertexBlendWeights[j];
  640.                 )   
  641.             )
  642.         )
  643.     )
  644.     
  645.     m;
  646. )
  647.  
  648. fn nineAssetRead =
  649. (
  650.     ioPushBase();
  651.     
  652.     local a = nineAsset();
  653.     a.Magic = ioReadU32();
  654.     a.Version = ioReadU32();
  655.     a.Field08 = ioReadU32();
  656.     a.Field0C = ioReadU32();
  657.     a.ContentOffset = ioReadU32();
  658.     
  659.     if ( a.ContentOffset != 0 ) then
  660.     (
  661.         ioPush();
  662.         ioSeekSet( a.ContentOffset );
  663.         case ( a.Magic ) of
  664.         (
  665.             0x004C444D: a.Content = nineModelRead();
  666.         )
  667.         ioPop();
  668.     )
  669.     
  670.     ioPopBase();
  671.     
  672.     a;
  673. )
  674.  
  675. fn nineArchiveRead =
  676. (
  677.     local lowestOffset = 0x7FFFFFFF;
  678.  
  679.     while ( true ) do
  680.     (
  681.         if ( ioTell() >= lowestOffset ) then
  682.             exit;
  683.     
  684.         local offset = ioReadU32();
  685.         local size = ioReadU32();
  686.  
  687.         if ( offset != 0 and size != 0 ) then
  688.         (
  689.             ioPush();
  690.             ioSeekSet( offset );
  691.             local asset = nineAssetRead();
  692.             ioPop();
  693.         )
  694.  
  695.         if ( offset < lowestOffset ) then
  696.             lowestOffset = offset;
  697.     )
  698. )
  699.  
  700.  
  701. fn main =
  702. (
  703.     clearListener();
  704.     
  705.     --local filePath = @"D:\Users\smart\Desktop\s013.bin.1.mdl";
  706.     --local filePath = @"D:\Users\smart\Downloads\SMT NINE Models\Models\item\ITEMALL.BIN";
  707.     local filePath = ioSelectOpenFile "SMT NINE model" #("BIN", "MMX");
  708.     if ( filePath != undefined ) then
  709.     (
  710.         ioOpenFile( filePath );
  711.         
  712.         local ext = getFilenameType( filePath );
  713.         if ( ext == ".BIN" ) then
  714.         (
  715.             nineArchiveRead();
  716.         )
  717.         else if ( ext == ".MMX" ) then
  718.         (
  719.             nineAssetRead();
  720.         )
  721.     )
  722.     
  723.     OK
  724. )
  725.  
  726. main();