/* Corsix and fneep's RGM Tools for Company of Heroes Copyright (C) 2007 Corsix and fneep This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* This file loads RGM files into max and also handles the GUI parts of the script. Version history: 0.1 (Oct 8th 2006): - Initial release - Loads vertex X,Y,Z and faces 0.11 (Feb 19th 2007): - Bugfix and tweaks - Loads Material IDs - Parses Texture chunks and spits out data into listener 0.12 (Feb 23th 2007): - Textures loaded 0.15 (Mar 1st 2007): - Loads meshes as seperate objects - Bugfixes and tweaks 0.151 (Mar 1st 2007): - Fixed bug where script did not load infantry models 0.152 (Mar 3rd 2007): - Minor cleanup and commented - XREF warning messages added 0.16 (Mar 18th 2007): - Loading of FOLDTRIM chunks added - Fixed bug where only first mesh chunk was loaded 0.17 (Mar 23rd 2007): - Added directory and recursive directory imports - Fixed bug where texture paths were loaded incorrectly 0.20 (May 30rd 2007): - Full vertex loading capabilities prep added */ include "Corsix_Chunky.ms" -- include Corsix's chunky library ClearListener() -- Clear the listener window to make for easier reading of data printed by script. /* Gets the filename of the ini file for this script */ fn Corsix_RGMImportIni = ( local ini_dir = getINISetting (getMAXIniFile()) "Directories" "Startup Scripts" return ini_dir + "\\Corsix_RGM_Import.ini" ) /* Handles a DATADATA chunk from an RGM file oRgm - the RGM file oChunk - the DATADATA chunk returns - nothing */ fn Corsix_RgmIntoMax_Mesh_DataData oRgm oChunk = ( fseek oRgm.fFile (oChunk.iDataPosition + 1) #seek_set -- jump to chunk /* Objects */ struct sGlobalMeshInfo -- holds global mesh data to compare to and collect from ( iVertCount = 0, aVertArray = #(), aFaceArray = #() ) struct sObjectID -- holds data for the Object identifiers ( iVertCount = 0, aVertArray = #(), aUVArray = #(), iFaceCount = 0, aFaceList = #() ) struct sObjectStruct -- holds data for a single object ( sObjectName = "", sOIDStruct = sObjectID() ) global oMeshInfo = sGlobalMeshInfo() -- holds all mesh data local iObjectCount = ReadLong oRgm.fFile #unsigned -- number of separate objects local aObjectList = #() for i=1 to iObjectCount do ( local oObject = sObjectStruct() oObject.sOIDStruct.iFaceCount = (ReadLong oRgm.fFile #unsigned)/3 -- number of faces as the verts that make them. Meshes are triangles so divide by 3 for i=1 to oObject.sOIDStruct.iFaceCount do ( local aFace = point3 0 0 0 aFace.x = (ReadShort oRgm.fFile) + 1 -- vertex ID's given as vertnumber - 1 because of the way that C++ handles arrays (the exporter is in C++). To convert to maxscript, add one. aFace.z = (ReadShort oRgm.fFile) + 1 aFace.y = (ReadShort oRgm.fFile) + 1 append oObject.sOIDStruct.aFaceList [aFace.x, aFace.y, aFace.z] ) fseek oRgm.fFile 13 #seek_cur -- skip unknown local iStrLen = ReadLong oRgm.fFile #unsigned oObject.sObjectName = Corsix_ReadStringN oRgm.fFile iStrLen append aObjectList oObject ) /* Per-Vertex Component Data */ local iComponentCount = ReadLong oRgm.fFile #unsigned struct sPerVertStruct ( iVertComponent = 0, iUnknown = 0, iDataType = 0 ) local aComponentVector = #() for i=1 to iComponentCount do ( oComponent = sPerVertStruct() oComponent.iVertComponent = ReadLong oRgm.fFile #unsigned oComponent.iUnknown = ReadLong oRgm.fFile #unsigned -- This number should usually be three. Its current purpose is unknown oComponent.iDataType = ReadLong oRgm.fFile #unsigned append aComponentVector oComponent ) Print aComponentVector as string /* Per-Vertex Data */ struct sVertStruct ( p3Position = point3 0 0 0, iBoneIndex = 0, iBoneWeight = 0, iNormal = 0, iBiNormal = 0, iTangent = 0, iDiffuseColour = color 0 0 0 0, iSpecularColour = color 0 0 0 0, p3UVCh1 = point3 0 0 0, p3UVCh2 = point3 0 0 0, p3UVCh3 = point3 0 0 0 ) local iVertCount = ReadLong oRgm.fFile #unsigned local iVertexSize = ReadLong oRgm.fFile #unsigned -- number of bytes taken up by each vertex on disk. for i=1 to iVertCount do ( local oVertex = sVertStruct() for oComponent in aComponentVector do ( case oComponent.iVertComponent of ( /* 0 = Position */ 0: ( oVertex.p3Position.x = -(ReadFloat oRgm.fFile) oVertex.p3Position.z = ReadFloat oRgm.fFile oVertex.p3Position.y = -(ReadFloat oRgm.fFile) ) /* 1 = Bone Index */ 1: ( oVertex.iBoneIndex = ReadLong oRgm.fFile #unsigned ) /* 2 = Bone Weight */ 2: ( oVertex.iBoneWeight = ReadLong oRgm.fFile #unsigned ) /* 3 = Normal */ 3: ( oVertex.iNormal = ReadLong oRgm.fFile #unsigned ) /* 4 = BiNormal */ 4: ( oVertex.iBiNormal = ReadLong oRgm.fFile #unsigned ) /* 5 = Tangent */ 5: ( oVertex.iTangent = ReadLong oRgm.fFile #unsigned ) /* 6 = Diffuse Vertex Colour */ 6: ( oVertex.iDiffuseColour.r = ReadByte oRgm.fFile oVertex.iDiffuseColour.g = ReadByte oRgm.fFile oVertex.iDiffuseColour.b = ReadByte oRgm.fFile oVertex.iDiffuseColour.a = ReadByte oRgm.fFile ) /* 7 = Specular Vertex Colour */ 7: ( oVertex.iSpecularColour.r = ReadByte oRgm.fFile oVertex.iSpecularColour.g = ReadByte oRgm.fFile oVertex.iSpecularColour.b = ReadByte oRgm.fFile oVertex.iSpecularColour.a = ReadByte oRgm.fFile ) /* 8 = UV Channel 1 */ 8: ( if oComponent.iDataType == 3 then ( oVertex.p3UVCh1.x = ReadFloat oRgm.fFile oVertex.p3UVCh1.y = ReadFloat oRgm.fFile if oVertex.p3UVCh1.y < 0 then ( oVertex.p3UVCh1.y * -1 ) ) else ( oVertex.p3UVCh1.x = ReadLong oRgm.fFile ) ) /* 9 = UV Channel 2 */ 9: ( if oComponent.iDataType == 3 then ( oVertex.p3UVCh2.x = ReadFloat oRgm.fFile oVertex.p3UVCh2.y = ReadFloat oRgm.fFile if oVertex.p3UVCh2.y < 0 then ( oVertex.p3UVCh2.y * -1 ) ) else ( oVertex.p3UVCh2.x = ReadLong oRgm.fFile ) ) /* 10 = UV Channel 3 */ 10: ( if oComponent.iDataType == 3 then ( oVertex.p3UVCh3.x = ReadFloat oRgm.fFile oVertex.p3UVCh3.y = ReadFloat oRgm.fFile if oVertex.p3UVCh3.y < 0 then ( oVertex.p3UVCh3.y * -1 ) ) else ( oVertex.p3UVCh3.x = ReadLong oRgm.fFile ) ) ) ) append oMeshInfo.aVertArray oVertex ) Print oMeshInfo.aVertArray as string local iVertUnknown = ReadLong oRgm.fFile /* Faces and Material IDs */ local iFaceCount = ReadLong oRgm.fFile #unsigned FaceUnknown = ReadLong oRgm.fFile FaceUnknown = ReadLong oRgm.fFile iFaceCount = iFaceCount / 3 for i=1 to iFaceCount do ( local aFace = point3 0 0 0 aFace.x = (ReadShort oRgm.fFile) + 1 aFace.z = (ReadShort oRgm.fFile) + 1 aFace.y = (ReadShort oRgm.fFile) + 1 append oMeshInfo.aFaceArray [aFace.x, aFace.y, aFace.z] ) local iStrLen = ReadLong oRgm.fFile #unsigned sMaterialName = Corsix_ReadStringN oRgm.fFile iStrLen local iMatIDFace = 0 iMatIDFace = findItem aMatIDArray sMaterialName /* Organise the verts for the per object mesh construction */ for oTempObject in aObjectList do ( aRelativeFaceArray = #() for i=1 to oTempObject.sOIDStruct.aFaceList.count do ( local aVert = oMeshInfo.aFaceArray[i] -- find the vert print i as string Print oMeshInfo as string print aVert as string ----------[ X Vert ]---------- aRelativeVert = oMeshInfo.aVertArray[aVert.x].p3Position local bTestVar = false -- Kind of liked a hacked finditem routine (structures in arrays. Nasty, I know, but I had to do it) for i=1 to oTempObject.sOIDStruct.aVertArray.count do ( if oTempObject.sOIDStruct.aVertArray[i].p3Position == oMeshInfo.aVertArray[aVert.x] then ( bTestVar = true ) ) if bTestVar = false then ( append oTempObject.sOIDStruct.aVertArray aRelativeVert -- and send it to the correct object structure append oTempObject.sOIDStruct.aUVArray oMeshInfo.aVertArray[aVert.x].p3UVCh1 -- and same for the UV ) ----------[ Y Vert ]---------- aRelativeVert = oMeshInfo.aVertArray[aVert.y].p3Position local bTestVar = false for i=1 to oTempObject.sOIDStruct.aVertArray.count do ( if oTempObject.sOIDStruct.aVertArray[i].p3Position == oMeshInfo.aVertArray[aVert.x] then ( bTestVar = true ) ) if bTestVar = false then ( append oTempObject.sOIDStruct.aVertArray aRelativeVert -- and send it to the correct object structure append oTempObject.sOIDStruct.aUVArray oMeshInfo.aVertArray[aVert.y].p3UVCh1 -- and same for the UV ) ----------[ Z Vert ]---------- aRelativeVert = oMeshInfo.aVertArray[aVert.z].p3Position local bTestVar = false for i=1 to oTempObject.sOIDStruct.aVertArray.count do ( if oTempObject.sOIDStruct.aVertArray[i].p3Position == oMeshInfo.aVertArray[aVert.x] then ( bTestVar = true ) ) if bTestVar = false then ( append oTempObject.sOIDStruct.aVertArray aRelativeVert -- and send it to the correct object structure append oTempObject.sOIDStruct.aUVArray oMeshInfo.aVertArray[aVert.z].p3UVCh1 -- and same for the UV ) print oTempObject as string ) for oFace in oTempObject.sOIDStruct.aFaceList do ( iRelativeFace = point3 0 0 0 -- new face for i=1 to oTempObject.sOIDStruct.aVertArray.count do ( if oTempObject.sOIDStruct.aVertArray[i].p3Position == oMeshInfo.aVertArray[oFace.x] then ( iRelativeFace.x = i ) if oTempObject.sOIDStruct.aVertArray[i].p3Position == oMeshInfo.aVertArray[oFace.y] then ( iRelativeFace.y = i ) if oTempObject.sOIDStruct.aVertArray[i].p3Position == oMeshInfo.aVertArray[oFace.z] then ( iRelativeFace.z = i ) ) append aRelativeFaceArray iRelativeFace ) oTempObject.sOIDStruct.aFaceList = aRelativeFaceArray ) /* Construct Meshes */ for oTempObject in aObjectList do ( oMesh = mesh vertices:(oTempObject.sOIDStruct.aVertArray) faces:(oTempObject.sOIDStruct.aFaceList) -- construct mesh. oMesh = current mesh handle. oMesh.name = oTempObject.sObjectName -- set object name oMesh.wireColor = (color 0 0 0) -- set wire colour to black oMesh.material = mCorsixMultiMat -- assign material update oMesh deselect oMesh for i = 1 to oMesh.numfaces do ( oFace = (getFace oMesh i) setFaceSmoothGroup oMesh i 0 -- clear smoothing groups (o = none) setFaceMatID oMesh i iMatIDFace -- set the material ID ) meshop.weldVertsByThreshold oMesh oMesh.verts 0.00001 -- weld our new mesh Print ("Mesh: " + oMesh.name + " built!") ) ) /* Handles a FOLDTRIM/DATADATA chunk from an RGM file oRgm - the RGM file oChunk - the DATADATA chunk sName - the name of the mesh returns - nothing */ fn Corsix_RgmIntoMax_FoldTrim_DataData oRgm oChunk sName = ( fseek oRgm.fFile (oChunk.iDataPosition) #seek_set -- jump to chunk /* Per-Vertex Component Data */ local iComponentCount = ReadLong oRgm.fFile #unsigned struct sPerVertStruct ( iVertComponent = 0, iUnknown = 0, iDataType = 0 ) local aComponentVector = #() for i=1 to iComponentCount do ( oComponent = sPerVertStruct() oComponent.iVertComponent = ReadLong oRgm.fFile #unsigned oComponent.iUnknown = ReadLong oRgm.fFile #unsigned -- This number should usually be three. Its current purpose is unknown oComponent.iDataType = ReadLong oRgm.fFile #unsigned append aComponentVector oComponent ) Print aComponentVector as string /* Per-Vertex Data */ struct sVertStruct ( p3Position = point3 0 0 0, iBoneIndex = 0, iBoneWeight = 0, iNormal = 0, iBiNormal = 0, iTangent = 0, iDiffuseColour = color 0 0 0 0, iSpecularColour = color 0 0 0 0, p3UVCh1 = point3 0 0 0, p3UVCh2 = point3 0 0 0, p3UVCh3 = point3 0 0 0 ) local aVerticies = #() local iVertCount = ReadLong oRgm.fFile #unsigned local iVertexSize = ReadLong oRgm.fFile #unsigned -- number of bytes taken up by each vertex on disk. for i=1 to iVertCount do ( local oVertex = sVertStruct() for oComponent in aComponentVector do ( case oComponent.iVertComponent of ( /* 0 = Position */ 0: ( oVertex.p3Position.x = -(ReadFloat oRgm.fFile) oVertex.p3Position.z = ReadFloat oRgm.fFile oVertex.p3Position.y = -(ReadFloat oRgm.fFile) ) /* 1 = Bone Index */ 1: ( oVertex.iBoneIndex = ReadLong oRgm.fFile #unsigned ) /* 2 = Bone Weight */ 2: ( oVertex.iBoneWeight = ReadLong oRgm.fFile #unsigned ) /* 3 = Normal */ 3: ( oVertex.iNormal = ReadLong oRgm.fFile #unsigned ) /* 4 = BiNormal */ 4: ( oVertex.iBiNormal = ReadLong oRgm.fFile #unsigned ) /* 5 = Tangent */ 5: ( oVertex.iTangent = ReadLong oRgm.fFile #unsigned ) /* 6 = Diffuse Vertex Colour */ 6: ( oVertex.iDiffuseColour.r = ReadByte oRgm.fFile oVertex.iDiffuseColour.g = ReadByte oRgm.fFile oVertex.iDiffuseColour.b = ReadByte oRgm.fFile oVertex.iDiffuseColour.a = ReadByte oRgm.fFile ) /* 7 = Specular Vertex Colour */ 7: ( oVertex.iSpecularColour.r = ReadByte oRgm.fFile oVertex.iSpecularColour.g = ReadByte oRgm.fFile oVertex.iSpecularColour.b = ReadByte oRgm.fFile oVertex.iSpecularColour.a = ReadByte oRgm.fFile ) /* 8 = UV Channel 1 */ 8: ( if oComponent.iDataType == 3 then ( oVertex.p3UVCh1.x = ReadFloat oRgm.fFile oVertex.p3UVCh1.y = ReadFloat oRgm.fFile ) else ( oVertex.p3UVCh1.x = ReadLong oRgm.fFile ) ) /* 9 = UV Channel 2 */ 9: ( if oComponent.iDataType == 3 then ( oVertex.p3UVCh2.x = ReadFloat oRgm.fFile oVertex.p3UVCh2.y = ReadFloat oRgm.fFile ) else ( oVertex.p3UVCh2.x = ReadLong oRgm.fFile ) ) /* 10 = UV Channel 3 */ 10: ( if oComponent.iDataType == 3 then ( oVertex.p3UVCh3.x = ReadFloat oRgm.fFile oVertex.p3UVCh3.y = ReadFloat oRgm.fFile ) else ( oVertex.p3UVCh3.x = ReadLong oRgm.fFile ) ) ) ) append aVerticies oVertex ) Print aVerticies as string fseek oRgm.fFile 8 #seek_cur -- skip unknown /* Faces and Material IDs */ local aFaces = #() local iVertsPerFace = ReadLong oRgm.fFile -- number of verts in a face local iFaceCount = ReadLong oRgm.fFile iFaceCount = iFaceCount / iVertsPerFace for i=1 to iFaceCount do ( local aFace = point3 0 0 0 aFace.x = (ReadShort oRgm.fFile) + 1 aFace.z = (ReadShort oRgm.fFile) + 1 aFace.y = (ReadShort oRgm.fFile) + 1 append aFaces [aFace.x, aFace.y, aFace.z] ) local iStrLen = ReadLong oRgm.fFile #unsigned sMaterialName = Corsix_ReadStringN oRgm.fFile iStrLen local iMatIDFace = 0 iMatIDFace = findItem aMatIDArray sMaterialName /* Construct Mesh */ /* oMesh = mesh vertices:aVerticies faces:aFaces -- construct mesh. oMesh.name = sName -- set object name oMesh.wireColor = (color 0 0 0) -- set wire colour to black oMesh.material = mCorsixMultiMat -- assign material update oMesh deselect oMesh for i = 1 to oMesh.numfaces do ( oFace = (getFace oMesh i) setFaceSmoothGroup oMesh i 0 -- clear smoothing groups (o = none) setFaceMatID oMesh i iMatIDFace -- set the material ID ) meshop.weldVertsByThreshold oMesh oMesh.verts 0.00001 -- weld our new mesh Print ("Mesh: " + oMesh.name + " built!") */ ) /* Handles a FOLDMRGM chunk from an RGM file oRgm - the RGM file oChunk - the FOLDMRGM chunk returns - nothing */ fn Corsix_RgmIntoMax_FoldMrgm oRgm oChunk = ( iDataDataCount = 0 local i = 1 while i <= oChunk.iChildCount do ( case oChunk.aChildren[i].sType of ( "DATADATA": ( if iDataDataCount == 0 then ( Corsix_RgmIntoMax_Mesh_DataData oRgm oChunk.aChildren[i] iDataDataCount = 1 ) ) ) i += 1 ) ) /* Handles a FOLDMGRP chunk from an RGM file (Mesh Group) oRgm - the RGM file oChunk - the FOLDMGRP chunk returns - nothing */ fn Corsix_RgmIntoMax_FoldMgrp oRgm oChunk = ( local i = 1 while i <= oChunk.iChildCount do ( case oChunk.aChildren[i].sType of ( "FOLDMESH": Corsix_RgmIntoMax_FoldMesh oRgm oChunk.aChildren[i] ) i += 1 ) ) /* Handles a FOLDMESH chunk from an RGM file oRgm - the RGM file oChunk - the FOLDMESH chunk returns - nothing */ fn Corsix_RgmIntoMax_FoldMesh oRgm oChunk = ( local i = 1 while i <= oChunk.iChildCount do ( case oChunk.aChildren[i].sType of ( "FOLDMGRP": Corsix_RgmIntoMax_FoldMgrp oRgm oChunk.aChildren[i] "FOLDMRGM": Corsix_RgmIntoMax_FoldMrgm oRgm oChunk.aChildren[i] "FOLDTRIM": Corsix_RgmIntoMax_FoldTrim oRgm oChunk.aChildren[i] ) i += 1 ) ) /* Handles a FOLDTRIM chunk from an RGM file oRgm - the RGM file oChunk - the FOLDMESH chunk returns - nothing */ fn Corsix_RgmIntoMax_FoldTrim oRgm oChunk = ( iDataDataCount = 0 local i = 1 while i <= oChunk.iChildCount do ( case oChunk.aChildren[i].sType of ( "DATADATA": if iDataDataCount == 0 then ( Corsix_RgmIntoMax_FoldTrim_DataData oRgm oChunk.aChildren[i] oChunk.sName iDataDataCount = 1 ) ) i += 1 ) ) /* Handles a FOLDSKEL chunk from an RGM file (Skeleton data) oRgm - the RGM file oChunk - the FOLDSKEL chunk returns - nothing */ fn Corsix_RgmIntoMax_FoldMesh_FoldSkel oRgm oChunk = ( local i = 1 while i <= oChunk.iChildCount do ( case oChunk.aChildren[i].sType of ( "DATABONE": Corsix_RgmIntoMax_FoldMesh_FoldSkel_DataBone oRgm oChunk.aChildren[i] ) i += 1 ) ) /* Handles a DATABONE chunk from an RGM file (Bone data) oRgm - the RGM file oChunk - the DATABONE chunk sName - the name of the bone returns - nothing */ fn Corsix_RgmIntoMax_FoldMesh_FoldSkel_DataBone oRgm oChunk sName = ( fseek oRgm.fFile (oChunk.iDataPosition + 1) #seek_set -- jump to chunk ) /* Handles a FOLDMTRL chunk from an RGM file oRgm - the RGM file oChunk - the FOLDMTRL chunk returns - nothing */ fn Corsix_RgmIntoMax_FoldMtrl oRgm oChunk = ( /* Handles a DATAINFO chunk from an RGM file (Shader Names) oRgm - the RGM file oChunk - the DATAINFO chunk returns - nothing */ fn Corsix_RgmIntoMax_FoldMtrl_DataInfo oRgm oChunk = ( fseek oRgm.fFile oChunk.iDataPosition #seek_set -- jump to chunk local iStrLen = ReadLong oRgm.fFile #unsigned sShaderName = Corsix_ReadStringN oRgm.fFile iStrLen -- read the shader name print (" Shader: " + sShaderName as string + "\n") -- and spit it inot the listener ) /* Handles a DATAVAR chunk from an RGM file (Material Variables) oRgm - the RGM file oChunk - the DATAVAR chunk returns - nothing */ fn Corsix_RgmIntoMax_FoldMtrl_DataVar oRgm oChunk = ( fseek oRgm.fFile oChunk.iDataPosition #seek_set -- jump to chunk local iStrLen = ReadLong oRgm.fFile #unsigned sTexType = Corsix_ReadStringN oRgm.fFile iStrLen Print (" Texture type: " + sTexType as string) fseek oRgm.fFile 4 #seek_cur -- skip unknown 4 bytes local iStrLen = ReadLong oRgm.fFile #unsigned sTexPath = Corsix_ReadStringN oRgm.fFile iStrLen if sTexType != "camouflagecolour" and sTexType != "teamcolour" and sTexType != "diffuse_offsetu" and sTexType != "diffuse_offsetv" and sTexType != "dirtvisibility" and sTexType != "diffuseOffsetScale" and sTexType != "material_specular" and sTexType != "material_specularExp" then -- these ones don't have texture paths. Just colour values, offset values etc. ( Print (" Path: " + sTexPath as string + "\n") ) texturepath = (sCohPath as string + "\\DataSrc\\" + sModFolder as string + "\\" + sTexPath + ".tga") -- construct the texture path texture_map = bitmaptexture filename:texturepath -- new bitmap texture to hold our newly read path case sTexType of ( "diffusetex": oMaterial.diffusetex = texture_map -- only handle the ones that have texture paths "normalmap": oMaterial.normalmap = texture_map "teamtex": oMaterial.teamtex = texture_map "occlusiontex": oMaterial.occlusiontex = texture_map "glosstex": oMaterial.glosstex = texture_map "speculartex": oMaterial.speculartex = texture_map ) global mCorsixMaterial = standardMaterial diffuseMap: oMaterial.diffusetex name:(aMatIDArray[aMatIDArray.count] as string) specularMap:oMaterial.speculartex glossinessMap:oMaterial.glosstex showInViewport:true mCorsixMultiMat[mCorsixMultiMat.numsubs] = mCorsixMaterial mCorsixMultiMat.names[mCorsixMultiMat.numsubs] = aMatIDArray[aMatIDArray.count] setMeditMaterial 1 mCorsixMultiMat -- set mCorsixMultiMat to slot one in the ME ) local i = 1 while i <= oChunk.iChildCount do ( case oChunk.aChildren[i].sType of ( "DATAVAR": Corsix_RgmIntoMax_FoldMtrl_DataVar oRgm oChunk.aChildren[i] "DATAINFO": Corsix_RgmIntoMax_FoldMtrl_DataInfo oRgm oChunk.aChildren[i] ) i += 1 ) ) /* Handles a FOLDMODL chunk from an RGM file oRgm - the RGM file oChunk - the FOLDMODL chunk returns - nothing */ fn Corsix_RgmIntoMax_FoldModl oRgm oChunk = ( local i = 1 local iMatID = 0 while i <= oChunk.iChildCount do ( case oChunk.aChildren[i].sType of ( "FOLDMESH": Corsix_RgmIntoMax_FoldMesh oRgm oChunk.aChildren[i] "FOLDSKEL": Corsix_RgmIntoMax_FoldMesh oRgm oChunk.aChildren[i] "FOLDMTRL": ( iMatID += 1 Print "----------------------------------------------" print (" Material ID Name: " + oChunk.aChildren[i].sName as string) append aMatIDArray oChunk.aChildren[i].sName print (" Material ID: " + iMatID as string) struct sShaderTexturesStruct ( diffusetex = noMaterial(), -- noMaterial() will set the texture to 'none in the ME. Other wise we will get undefined errors teamtex = noMaterial(), normalmap = noMaterial(), occlusiontex = noMaterial(), glosstex = noMaterial(), speculartex = noMaterial() ) global oMaterial = sShaderTexturesStruct() -- an object to hold each material as we read them Corsix_RgmIntoMax_FoldMtrl oRgm oChunk.aChildren[i] -- handle the FOLDMTRL and its sub chunks mCorsixMultiMat.numsubs += 1 -- another one please! Print "----------------------------------------------" ) ) i += 1 ) ) /* Handles an RGM file oRgm - the RGM file returns - nothing */ fn Corsix_RgmIntoMax oRgm = ( local i = 1 while i <= oRgm.iChunkCount do ( case oRgm.aChunks[i].sType of ( "FOLDMODL": Corsix_RgmIntoMax_FoldModl oRgm oRgm.aChunks[i] ) i += 1 ) ) /* Cleans up the scene after import */ fn Corsix_RgmIntoMax_SceneCleanup oRgm = ( mCorsixMultiMat.numsubs -= 1 -- remove empty multimaterial stub viewport.setLayout #layout_1 -- set all sorts of viewport related things viewport.setType #view_persp_user viewport.SetRenderLevel #smooth viewport.SetShowEdgeFaces true max tool zoomextents all if iDataDataCount != 0 then ( Print (sModelName as string + " imported successfully!") ) else ( messagebox "All meshes X-Reffed. No meshes to be loaded in file." title:"RGM importer" ) ) /* Cleans up the scene after directory and recursive directory import */ fn Corsix_RgmIntoMax_SceneCleanup_DirImport oRgm = ( mCorsixMultiMat.numsubs -= 1 -- remove empty multimaterial stub viewport.setLayout #layout_1 -- set all sorts of viewport related things viewport.setType #view_persp_user viewport.SetRenderLevel #smooth viewport.SetShowEdgeFaces true max tool zoomextents all if iDataDataCount != 0 then ( Print (sModelName as string + " imported successfully!") ) else ( (Print "Import failed. All meshes X-REFFED. No meshes to load in file: " + sModelName as string) ) ) /* Recursively gets all RGM files under the root directory (from maxscript docs. No use in reinventing the wheel) */ fn Corsix_RgmIntoMax_RecDirFileFind dirRecDir = ( aDirectories = GetDirectories (dirRecDir + "/*") for d in aDirectories do ( join aDirectories (GetDirectories (d + "/*")) ) aFiles = #() for f in aDirectories do ( join aFiles (getFiles (f + "*.rgm")) ) return aFiles ) /* Graphical user interface stuff */ utility Corsix_RGM_Import "RGM Import" width:166 height:137 ( button btn_RGM_Import "Import RGM" pos:[13,5] width:140 height:21 toolTip:"Import an RGM file" button btn_Dir_Import "RGM Directory Import" pos:[13,32] width:140 height:21 toolTip:"Import all RGM files in a folder" button btn_RecDir_Import "Recursive Directory Import" pos:[13,58] width:140 height:21 toolTip:"Import RGM files from a directory recursively" button btn_Set_CoH_Directory "Set CoH Dir" pos:[13,84] width:140 height:21 toolTip:"Set the location of your Company of Heroes directory" button btn_Set_Mod_Directory "Set Mod Dir" pos:[13,110] width:140 height:21 toolTip:"Set the location of your mod directory" on btn_RGM_Import pressed do ( ClearListener() global sModelName = "" global iDataDataCount = 0 -- global variable to check if there are any DATADATA chunks in a file global aMatIDArray = #() -- global array to hold materials and their IDs global mCorsixMultiMat = MultiMaterial numsubs:1 -- a nice new multimaterial global sCohPath = getINISetting (Corsix_RGMImportIni()) "Directories" "Company_Of_Heroes" -- load various bits of info from the ini file global sModFolder = getINISetting (Corsix_RGMImportIni()) "Directories" "Mod_Folder" global sLastFile = getINISetting (Corsix_RGMImportIni()) "Files" "Last_File" local sFilename = getOpenFileName caption:"Select a RGM file to import" filename:sLastFile types:"RGM (*.rgm)|*.rgm" if sFilename != undefined then ( setINISetting (Corsix_RGMImportIni()) "Files" "Last_File" sFilename sModelName = getFilenameFile sFilename local oRgm = Corsix_Chunky() -- Yay! New object! if (oRgm.loadFromFile sFilename) == false then -- Boo. We failed. ( messagebox "Unable to load file" ) else ( resetMaxFile #noPrompt -- reset max if sCohPath != undefined then ( local sSavePath = getSavePath caption:"Select a where you want to save your file" initialDir:sCohPath if sSavePath != undefined then ( Makedir (sSavePath + "Model\\") Makedir (sSavePath + "Animations\\") Corsix_RgmIntoMax oRgm -- IMPORT! Corsix_RgmIntoMax_SceneCleanup oRGM -- contains all the post import functions SaveMaxfile (sSavePath + "Model\\Reference.max") ) else ( messagebox "The model will be loaded but not saved" title:"RGM importer" -- Ah! The joys of messageboxes! Corsix_RgmIntoMax oRgm Corsix_RgmIntoMax_SceneCleanup oRGM ) ) else ( messagebox "Please locate your Company of Heroes directory and try again" title:"RGM importer" ) ) ) ) on btn_Dir_Import pressed do ( ClearListener() global sModelName = "" global iDataDataCount = 0 -- global variable to check if there are any DATADATA chunks in a file global aMatIDArray = #() -- global array to hold materials and their IDs global mCorsixMultiMat = MultiMaterial numsubs:1 -- a nice new multimaterial global sCohPath = getINISetting (Corsix_RGMImportIni()) "Directories" "Company_Of_Heroes" -- load various bits of info from the ini file global sModFolder = getINISetting (Corsix_RGMImportIni()) "Directories" "Mod_Folder" global sLastFile = getINISetting (Corsix_RGMImportIni()) "Files" "Last_File" local sRgmImportFolder = getSavePath caption:"Locate folder to import RGMs from..." initialDir:sCohPath local sRgmSaveFolder = getSavePath caption:"Locate location to save loaded files..." initialDir:sCohPath if sRgmImportFolder != undefined and sRgmSaveFolder != undefined then ( aRgmImportFiles = getFiles (sRgmImportFolder + "\\*.RGM") for fFile in aRgmImportFiles do ( sModelName = getFilenameFile fFile local oRgm = Corsix_Chunky() if (oRgm.loadFromFile fFile) == false then -- Boo. We failed. ( messagebox "Unable to load file" ) else -- it worked ( resetMaxFile #noPrompt if sCohPath != undefined then ( Makedir (sRgmSaveFolder + "\\" + sModelName + "\\") Makedir (sRgmSaveFolder + "\\" + sModelName + "\\Model\\") Makedir (sRgmSaveFolder + "\\" + sModelName + "\\Animations\\") Corsix_RgmIntoMax oRgm -- IMPORT! Corsix_RgmIntoMax_SceneCleanup_DirImport oRGM -- contains directory import specific cleanup functions SaveMaxfile (sRgmSaveFolder + "\\" + sModelName + "\\Model\\Reference.max") Print "\n" ) else ( messagebox "Please locate your Company of Heroes directory and try again" title:"RGM importer" ) ) ) resetMaxFile #noPrompt messagebox "All models imported and saved successfully!" title:"Directory Import" ) else ( messagebox "Please locate both the folder to import and the folder to save to and try again." title:"Directory Import" ) ) on btn_RecDir_Import pressed do ( ClearListener() global sModelName = "" global iDataDataCount = 0 -- global variable to check if there are any DATADATA chunks in a file global aMatIDArray = #() -- global array to hold materials and their IDs global mCorsixMultiMat = MultiMaterial numsubs:1 -- a nice new multimaterial global sCohPath = getINISetting (Corsix_RGMImportIni()) "Directories" "Company_Of_Heroes" -- load various bits of info from the ini file global sModFolder = getINISetting (Corsix_RGMImportIni()) "Directories" "Mod_Folder" global sLastFile = getINISetting (Corsix_RGMImportIni()) "Files" "Last_File" local sRgmImportFolder = getSavePath caption:"Locate top level folder to import RGMs from..." initialDir:sCohPath local sRgmSaveFolder = getSavePath caption:"Locate location to save loaded files..." initialDir:sCohPath if sRgmImportFolder != undefined and sRgmSaveFolder != undefined then ( local aRgmImportFiles = Corsix_RgmIntoMax_RecDirFileFind sRgmImportFolder for fFile in aRgmImportFiles do ( sModelName = getFilenameFile fFile local oRgm = Corsix_Chunky() if (oRgm.loadFromFile fFile) == false then -- Boo. We failed. ( messagebox "Unable to load file" ) else -- it worked ( resetMaxFile #noPrompt if sCohPath != undefined then ( Makedir (sRgmSaveFolder + "\\" + sModelName + "\\") Makedir (sRgmSaveFolder + "\\" + sModelName + "\\Model\\") Makedir (sRgmSaveFolder + "\\" + sModelName + "\\Animations\\") Corsix_RgmIntoMax oRgm -- IMPORT! Corsix_RgmIntoMax_SceneCleanup_DirImport oRGM -- contains directory import specific cleanup functions SaveMaxfile (sRgmSaveFolder + "\\" + sModelName + "\\Model\\Reference.max") Print "\n" ) else ( messagebox "Please locate your Company of Heroes directory and try again" title:"RGM importer" ) ) ) resetMaxFile #noPrompt messagebox "All models imported and saved successfully!" title:"Recursive Directory Import" ) else ( messagebox "Please locate both the folder to import and the folder to save to and try again." title:"Recursive Directory Import" ) ) on btn_Set_CoH_Directory pressed do ( local sCohPath = getSavePath caption:"Locate Company of Heroes directory" if sCohPath != undefined then ( setINISetting (Corsix_RGMImportIni()) "Directories" "Company_Of_Heroes" sCohPath ) ) on btn_Set_Mod_Directory pressed do ( local sCohFolder = getINISetting (Corsix_RGMImportIni()) "Directories" "Company_Of_Heroes" local sModFolder = getSavePath "Locate mod directory" sCohFolder if sModFolder != undefined then ( local aModFolder = filterString sModFolder "\\" sModFolder = aModFolder[aModFolder.count] setINISetting (Corsix_RGMImportIni()) "Directories" "Mod_Folder" sModFolder ) ) )