/*
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,
iVectorStorageType = 0,
iDataType = 0
)
local aComponentVector = #()
for i=1 to iComponentCount do
(
oComponent = sPerVertStruct()
oComponent.iVertComponent = ReadLong oRgm.fFile #unsigned
oComponent.iVectorStorageType = ReadLong oRgm.fFile #unsigned
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.
oMeshInfo.iVertCount = iVertCount
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
b0 = ReadByte #unsigned
b1 = ReadByte #unsigned
b2 = ReadByte #unsigned
b3 = ReadByte #unsigned
f0=(float)b0/255.f;
f1=(float)b1/255.f;
f2=(float)b2/255.f;
f3=(float)b3/255.f;
f3=1.f - f3;
U = f0+(f2/32.f);
V = f1+(f3/32.f);
*/
8:
(
case oComponent.iDataType of
(
2:
(
iByte0 = (ReadByte oRgm.fFile #unsigned) as float
iByte1 = (ReadByte oRgm.fFile #unsigned) as float
iByte2 = (ReadByte oRgm.fFile #unsigned) as float
iByte3 = (ReadByte oRgm.fFile #unsigned) as float
Print ("iByte0: " + iByte0 as string)
Print ("iByte1: " + iByte1 as string)
Print ("iByte2: " + iByte2 as string)
Print ("iByte3: " + iByte3 as string)
fFloat0 = iByte0/255.0
fFloat1 = iByte1/255.0
fFloat2 = iByte2/255.0
fFloat3 = iByte3/255.0
fFloat3 = 1.0 - fFloat3
Print ("fFloat0: " + fFloat0 as string)
Print ("fFloat1: " + fFloat1 as string)
Print ("fFloat2: " + fFloat2 as string)
Print ("fFloat3: " + fFloat3 as string)
oVertex.p3UVCh1.x = fFloat0 + (fFloat2/32.0)
oVertex.p3UVCh1.y = fFloat1 + (fFloat3/32.0)
Print ("oVertex.p3UVCh1.x: " + oVertex.p3UVCh1.x as string)
Print ("oVertex.p3UVCh1.y: " + oVertex.p3UVCh1.y as string)
)
3:
(
oVertex.p3UVCh1.x = ReadFloat oRgm.fFile
oVertex.p3UVCh1.y = ReadFloat oRgm.fFile
)
)
)
/*
9 = UV Channel 2
*/
9:
(
case oComponent.iDataType of
(
2:
(
iByte0 = (ReadByte oRgm.fFile #unsigned) as float
iByte1 = (ReadByte oRgm.fFile #unsigned) as float
iByte2 = (ReadByte oRgm.fFile #unsigned) as float
iByte3 = (ReadByte oRgm.fFile #unsigned) as float
fFloat0 = iByte0/255.0
fFloat1 = iByte1/255.0
fFloat2 = iByte2/255.0
fFloat3 = iByte3/255.0
fFloat3 = 1.0 - fFloat3
oVertex.p3UVCh1.x = fFloat0 + (fFloat2/32.0)
oVertex.p3UVCh1.y = fFloat1 + (fFloat3/32.0)
)
3:
(
oVertex.p3UVCh2.x = ReadFloat oRgm.fFile
oVertex.p3UVCh2.y = ReadFloat oRgm.fFile
)
)
)
/*
10 = UV Channel 3
*/
10:
(
case oComponent.iDataType of
(
2:
(
iByte0 = (ReadByte oRgm.fFile #unsigned) as float
iByte1 = (ReadByte oRgm.fFile #unsigned) as float
iByte2 = (ReadByte oRgm.fFile #unsigned) as float
iByte3 = (ReadByte oRgm.fFile #unsigned) as float
fFloat0 = iByte0/255.0
fFloat1 = iByte1/255.0
fFloat2 = iByte2/255.0
fFloat3 = iByte3/255.0
fFloat3 = 1.0 - fFloat3
oVertex.p3UVCh1.x = fFloat0 + (fFloat2/32.0)
oVertex.p3UVCh1.y = fFloat1 + (fFloat3/32.0)
)
3:
(
oVertex.p3UVCh1.x = ReadFloat oRgm.fFile
oVertex.p3UVCh1.y = ReadFloat 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
Each object contains a list of faces.
Each of these faces contains 3 indexes to verticies in the global vertex list.
We want to copy these verticies to the local vertex/UV list and update the index to be into the local list.
*/
local aVertexIdMap = #()
for itrObject in aObjectList do
(
-- The object should already be set to this, but make sure:
itrObject.sOIDStruct.iVertCount = 0
itrObject.sOIDStruct.aVertArray = #()
itrObject.sOIDStruct.aUVArray = #()
-- Set the mapping to indicate that no global verticies have equivalent local verticies
for i=1 to oMeshInfo.iVertCount do
(
aVertexIdMap[i] = 0
)
for i=1 to itrObject.sOIDStruct.iFaceCount do
(
local iGlobalVertId = 0
local iLocalVertId = 0
-----[ X ]-----
iGlobalVertId = itrObject.sOIDStruct.aFaceList[i].x -- Get the first global vertex index (the x component of the face)
iLocalVertId = aVertexIdMap[iGlobalVertId] -- See if that vertex has been mapped to a local one
if iLocalVertId == 0 then -- If it hasn't, then we need to map it:
(
append itrObject.sOIDStruct.aVertArray oMeshInfo.aVertArray[iGlobalVertId].p3Position -- copy over position
append itrObject.sOIDStruct.aUVArray oMeshInfo.aVertArray[iGlobalVertId].p3UVCh1 -- copy over UV
itrObject.sOIDStruct.iVertCount = itrObject.sOIDStruct.iVertCount + 1 -- guess what? we have a new vertex
iLocalVertId = itrObject.sOIDStruct.iVertCount -- we now have a local vertex ID (the vertex we just copied)
aVertexIdMap[iGlobalVertId] = iLocalVertId -- update the mapping to show the global vertex has an equivalent local one
)
itrObject.sOIDStruct.aFaceList[i].x = iLocalVertId -- Change the global index to a local index
-----[ Y ]-----
iGlobalVertId = itrObject.sOIDStruct.aFaceList[i].y -- Get the second global vertex index (the y component of the face)
iLocalVertId = aVertexIdMap[iGlobalVertId] -- See if that vertex has been mapped to a local one
if iLocalVertId == 0 then -- If it hasn't, then we need to map it:
(
append itrObject.sOIDStruct.aVertArray oMeshInfo.aVertArray[iGlobalVertId].p3Position -- copy over position
append itrObject.sOIDStruct.aUVArray oMeshInfo.aVertArray[iGlobalVertId].p3UVCh1 -- copy over UV
itrObject.sOIDStruct.iVertCount = itrObject.sOIDStruct.iVertCount + 1 -- guess what? we have a new vertex
iLocalVertId = itrObject.sOIDStruct.iVertCount -- we now have a local vertex ID (the vertex we just copied)
aVertexIdMap[iGlobalVertId] = iLocalVertId -- update the mapping to show the global vertex has an equivalent local one
)
itrObject.sOIDStruct.aFaceList[i].y = iLocalVertId -- Change the global index to a local index
-----[ Z ]-----
iGlobalVertId = itrObject.sOIDStruct.aFaceList[i].z -- Get the third global vertex index (the z component of the face)
iLocalVertId = aVertexIdMap[iGlobalVertId] -- See if that vertex has been mapped to a local one
if iLocalVertId == 0 then -- If it hasn't, then we need to map it:
(
append itrObject.sOIDStruct.aVertArray oMeshInfo.aVertArray[iGlobalVertId].p3Position -- copy over position
append itrObject.sOIDStruct.aUVArray oMeshInfo.aVertArray[iGlobalVertId].p3UVCh1 -- copy over UV
itrObject.sOIDStruct.iVertCount = itrObject.sOIDStruct.iVertCount + 1 -- guess what? we have a new vertex
iLocalVertId = itrObject.sOIDStruct.iVertCount -- we now have a local vertex ID (the vertex we just copied)
aVertexIdMap[iGlobalVertId] = iLocalVertId -- update the mapping to show the global vertex has an equivalent local one
)
itrObject.sOIDStruct.aFaceList[i].z = iLocalVertId -- Change the global index to a local index
)
)
/*
Construct Meshes
*/
for oTempObject in aObjectList do
(
Print oTempObject as string
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
setMesh oMesh tverts:oTempObject.sOIDStruct.aUVArray -- setMesh oMesh mesh tverts:oTempObject.sOIDStruct.aUVArray
buildTVFaces oMesh
for i = 1 to oMesh.numfaces do
(
oFace = (getFace oMesh i)
setTVFace oMesh i oFace.x oFace.y oFace.z
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 = ReadFloat oRgm.fFile
oVertex.p3UVCh1.y = ReadFloat 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
)
)
)/*
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,
iVectorStorageType = 0,
iDataType = 0
)
local aComponentVector = #()
for i=1 to iComponentCount do
(
oComponent = sPerVertStruct()
oComponent.iVertComponent = ReadLong oRgm.fFile #unsigned
oComponent.iVectorStorageType = ReadLong oRgm.fFile #unsigned
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.
oMeshInfo.iVertCount = iVertCount
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
b0 = ReadByte #unsigned
b1 = ReadByte #unsigned
b2 = ReadByte #unsigned
b3 = ReadByte #unsigned
f0=(float)b0/255.f;
f1=(float)b1/255.f;
f2=(float)b2/255.f;
f3=(float)b3/255.f;
f3=1.f - f3;
U = f0+(f2/32.f);
V = f1+(f3/32.f);
*/
8:
(
case oComponent.iDataType of
(
2:
(
iByte0 = (ReadByte oRgm.fFile #unsigned) as float
iByte1 = (ReadByte oRgm.fFile #unsigned) as float
iByte2 = (ReadByte oRgm.fFile #unsigned) as float
iByte3 = (ReadByte oRgm.fFile #unsigned) as float
Print ("iByte0: " + iByte0 as string)
Print ("iByte1: " + iByte1 as string)
Print ("iByte2: " + iByte2 as string)
Print ("iByte3: " + iByte3 as string)
fFloat0 = iByte0/255.0
fFloat1 = iByte1/255.0
fFloat2 = iByte2/255.0
fFloat3 = iByte3/255.0
fFloat3 = 1.0 - fFloat3
Print ("fFloat0: " + fFloat0 as string)
Print ("fFloat1: " + fFloat1 as string)
Print ("fFloat2: " + fFloat2 as string)
Print ("fFloat3: " + fFloat3 as string)
oVertex.p3UVCh1.x = fFloat0 + (fFloat2/32.0)
oVertex.p3UVCh1.y = fFloat1 + (fFloat3/32.0)
Print ("oVertex.p3UVCh1.x: " + oVertex.p3UVCh1.x as string)
Print ("oVertex.p3UVCh1.y: " + oVertex.p3UVCh1.y as string)
)
3:
(
oVertex.p3UVCh1.x = ReadFloat oRgm.fFile
oVertex.p3UVCh1.y = ReadFloat oRgm.fFile
)
)
)
/*
9 = UV Channel 2
*/
9:
(
case oComponent.iDataType of
(
2:
(
iByte0 = (ReadByte oRgm.fFile #unsigned) as float
iByte1 = (ReadByte oRgm.fFile #unsigned) as float
iByte2 = (ReadByte oRgm.fFile #unsigned) as float
iByte3 = (ReadByte oRgm.fFile #unsigned) as float
fFloat0 = iByte0/255.0
fFloat1 = iByte1/255.0
fFloat2 = iByte2/255.0
fFloat3 = iByte3/255.0
fFloat3 = 1.0 - fFloat3
oVertex.p3UVCh1.x = fFloat0 + (fFloat2/32.0)
oVertex.p3UVCh1.y = fFloat1 + (fFloat3/32.0)
)
3:
(
oVertex.p3UVCh2.x = ReadFloat oRgm.fFile
oVertex.p3UVCh2.y = ReadFloat oRgm.fFile
)
)
)
/*
10 = UV Channel 3
*/
10:
(
case oComponent.iDataType of
(
2:
(
iByte0 = (ReadByte oRgm.fFile #unsigned) as float
iByte1 = (ReadByte oRgm.fFile #unsigned) as float
iByte2 = (ReadByte oRgm.fFile #unsigned) as float
iByte3 = (ReadByte oRgm.fFile #unsigned) as float
fFloat0 = iByte0/255.0
fFloat1 = iByte1/255.0
fFloat2 = iByte2/255.0
fFloat3 = iByte3/255.0
fFloat3 = 1.0 - fFloat3
oVertex.p3UVCh1.x = fFloat0 + (fFloat2/32.0)
oVertex.p3UVCh1.y = fFloat1 + (fFloat3/32.0)
)
3:
(
oVertex.p3UVCh1.x = ReadFloat oRgm.fFile
oVertex.p3UVCh1.y = ReadFloat 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
Each object contains a list of faces.
Each of these faces contains 3 indexes to verticies in the global vertex list.
We want to copy these verticies to the local vertex/UV list and update the index to be into the local list.
*/
local aVertexIdMap = #()
for itrObject in aObjectList do
(
-- The object should already be set to this, but make sure:
itrObject.sOIDStruct.iVertCount = 0
itrObject.sOIDStruct.aVertArray = #()
itrObject.sOIDStruct.aUVArray = #()
-- Set the mapping to indicate that no global verticies have equivalent local verticies
for i=1 to oMeshInfo.iVertCount do
(
aVertexIdMap[i] = 0
)
for i=1 to itrObject.sOIDStruct.iFaceCount do
(
local iGlobalVertId = 0
local iLocalVertId = 0
-----[ X ]-----
iGlobalVertId = itrObject.sOIDStruct.aFaceList[i].x -- Get the first global vertex index (the x component of the face)
iLocalVertId = aVertexIdMap[iGlobalVertId] -- See if that vertex has been mapped to a local one
if iLocalVertId == 0 then -- If it hasn't, then we need to map it:
(
append itrObject.sOIDStruct.aVertArray oMeshInfo.aVertArray[iGlobalVertId].p3Position -- copy over position
append itrObject.sOIDStruct.aUVArray oMeshInfo.aVertArray[iGlobalVertId].p3UVCh1 -- copy over UV
itrObject.sOIDStruct.iVertCount = itrObject.sOIDStruct.iVertCount + 1 -- guess what? we have a new vertex
iLocalVertId = itrObject.sOIDStruct.iVertCount -- we now have a local vertex ID (the vertex we just copied)
aVertexIdMap[iGlobalVertId] = iLocalVertId -- update the mapping to show the global vertex has an equivalent local one
)
itrObject.sOIDStruct.aFaceList[i].x = iLocalVertId -- Change the global index to a local index
-----[ Y ]-----
iGlobalVertId = itrObject.sOIDStruct.aFaceList[i].y -- Get the second global vertex index (the y component of the face)
iLocalVertId = aVertexIdMap[iGlobalVertId] -- See if that vertex has been mapped to a local one
if iLocalVertId == 0 then -- If it hasn't, then we need to map it:
(
append itrObject.sOIDStruct.aVertArray oMeshInfo.aVertArray[iGlobalVertId].p3Position -- copy over position
append itrObject.sOIDStruct.aUVArray oMeshInfo.aVertArray[iGlobalVertId].p3UVCh1 -- copy over UV
itrObject.sOIDStruct.iVertCount = itrObject.sOIDStruct.iVertCount + 1 -- guess what? we have a new vertex
iLocalVertId = itrObject.sOIDStruct.iVertCount -- we now have a local vertex ID (the vertex we just copied)
aVertexIdMap[iGlobalVertId] = iLocalVertId -- update the mapping to show the global vertex has an equivalent local one
)
itrObject.sOIDStruct.aFaceList[i].y = iLocalVertId -- Change the global index to a local index
-----[ Z ]-----
iGlobalVertId = itrObject.sOIDStruct.aFaceList[i].z -- Get the third global vertex index (the z component of the face)
iLocalVertId = aVertexIdMap[iGlobalVertId] -- See if that vertex has been mapped to a local one
if iLocalVertId == 0 then -- If it hasn't, then we need to map it:
(
append itrObject.sOIDStruct.aVertArray oMeshInfo.aVertArray[iGlobalVertId].p3Position -- copy over position
append itrObject.sOIDStruct.aUVArray oMeshInfo.aVertArray[iGlobalVertId].p3UVCh1 -- copy over UV
itrObject.sOIDStruct.iVertCount = itrObject.sOIDStruct.iVertCount + 1 -- guess what? we have a new vertex
iLocalVertId = itrObject.sOIDStruct.iVertCount -- we now have a local vertex ID (the vertex we just copied)
aVertexIdMap[iGlobalVertId] = iLocalVertId -- update the mapping to show the global vertex has an equivalent local one
)
itrObject.sOIDStruct.aFaceList[i].z = iLocalVertId -- Change the global index to a local index
)
)
/*
Construct Meshes
*/
for oTempObject in aObjectList do
(
Print oTempObject as string
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
setMesh oMesh tverts:oTempObject.sOIDStruct.aUVArray -- setMesh oMesh mesh tverts:oTempObject.sOIDStruct.aUVArray
buildTVFaces oMesh
for i = 1 to oMesh.numfaces do
(
oFace = (getFace oMesh i)
setTVFace oMesh i oFace.x oFace.y oFace.z
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 = ReadFloat oRgm.fFile
oVertex.p3UVCh1.y = ReadFloat 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
)
)
)