--( -- getNodeByName gMax= (maxVersion())[1]<=4200 grabListenerPath= getDir #scripts -- or specify your own path, like "c:\\program files\\autodesk\\3ds max\\scripts" global checksum global jmsFilepath aboutString = "Copyright (C) 2006 Adam Papamarcos\n"+ \ "\n"+ \ "Further contributions by:\n"+ \ "\tTheGhost (Adapted for HaloCE)\n"+ \ "\tCtrlAltDestroy\n"+ \ "\tChoking Victem\n"+ \ "\tbobbysoon" fn dlgAbout = ( messagebox aboutString title:"About JMS Exporter, as of version 1.0.4e" ) --*************************************************************************** --* * --* JMS Exporter 1.0.4e * --* * --* for 3ds Max v5+ and gmax v1.2 * --* * --*************************************************************************** --* Export Features: * --* - all types of model geometry * --* - perfect texture coordinates * --* - regions * --* - proper, well-calculated vertex normals * --* - all nodes and markers (for weapons, vehicles, etc.) * --* - biped systems or bones for character models * --* - vertex weights for fully rigged model! * --* - from gmax / 3ds max version independent * --*-------------------------------------------------------------------------* --* Instructions: Check the checkbox captioned "Export vertex weights" if * --* you are exporting a rigged model. Select the method to export the JMS * --* data, either writing to a JMS file or streaming through the listener * --* (for gmax). Click the "Export JMS Data" button to begin. * --*-------------------------------------------------------------------------* --* Copyright (C) 2006 Adam Papamarcos (mailto:papamarcos@gmail.com) * --* This program is free software; you can redistribute it and/or modify it * --* under the terms of the GNU General Public License as published by the * --* Free Software Foundation; either version 2 of the License, or (at your * --* option) any later version. This program 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 General Public License for more details. A full copy of this * --* license is available at http://www.gnu.org/licenses/gpl.txt. * --*-------------------------------------------------------------------------* fn timeString ts = -- ts == timeStamp ( et= ts/1000 -- et= seconds m=(floor (et/60)) as integer if m>0 then ( ms=(m as string) + " minute" if m>1 then ms=ms+"s" ) else ms="" s=(floor (et-(m*60))) as integer if s>0 then ( ss=(s as string) + " second" if s>1 then ss=ss+"s" ) et="" if m>0 then et=et+ms if m>0 and s>0 then et=et+", " if s>0 then et=et+ss if m==0 and s==0 then et="instantaneous" return et ) fn getFaceSmoothGroupB obj face = ( local sgroup_val = getFaceSmoothGroup obj face local sg_bitarray = #{} if sgroup_val < 0 do ( sg_bitarray[32] = true sgroup_val -= 2^31 ) for i = 1 to 31 do ( sg_bitarray[i] = (mod sgroup_val 2 > .5) sgroup_val /= 2 ) sg_bitarray as array ) if undefined != roJmsExporter then if roJmsExporter.open then destroyDialog roJmsExporter --) rollout roJmsExporter "JMS Model Exporter" width:500 ( --( button btPickJmsFilepath "..." width:490 edittext etChecksum "Checksum: " across:4 width:200 button go_button "Export JMS Data" toolTip:" Ready when you are " offset:[80,0] button btAbout "About" align:#right offset:[60,0] height:14 button btEdit "v1.0.4e" align:#right toolTip:" NO! " height:14 listBox lbObjects "Export Objects" width:90 height:9 across:3 listBox lbChecksum "Checksum" width:90 height:9 offset:[-60,0] listBox lbJmsFilepath "JmsFilepath" width:280 height:9 offset:[-120,0] button btGetObjInfo "GetObjInfo" across:2 enabled:false offset:[250,-145] height:16 button btSetObjInfo "SetObjInfo" align:#right offset:[0,-145] height:16 local dataPath fn setProp k v = ( fileProperties.deleteProperty #custom k fileProperties.addProperty #custom k v v ) fn getProp k ifNot:"" = ( i=fileProperties.findProperty #custom k if i>0 then fileProperties.getPropertyValue #custom i else ifNot ) fn setObjProp o kk vv = setUserProp o kk vv fn getObjProp o s ifNot:"" = ( -- getUserProp is broken, so... upb=filterString (getUserPropBuffer o) "\r\n" for kv in upb do ( i=findString kv " = " if s == (subString kv 1 (i-1)) then return (subString kv (i+3) -1) ) return ifNot ) fn getDataPath p = if (dataIndex= findString p "\\data\\") != undefined then subString p (dataIndex+6) -1 else p fn showJmsFilepath = ( if isKindOf jmsFilepath String then ( btPickJmsFilepath.text= getDataPath jmsFilepath if btPickJmsFilepath.text != jmsFilepath then dataPath= btPickJmsFilepath.text ) else ( btPickJmsFilepath.text= "undefined" dataPath= undefined ) ) fn pickJmsFilepath = ( output_name= jmsFilepath if output_name == "" or output_name == undefined then output_name= "C:\\Program Files\\Microsoft Games\\Halo Custom Edition\\data\\" else ( fp= getFilenamePath output_name while 0 == (getDirectories (fp+"*")).count do ( fp= getFilenamePath (trimRight fp "\\") format "fp= %\n" fp ) output_name= fp ) output_name = getSaveFileName caption:"Select File to Export" \ filename: output_name \ types:"BlueStreak Model Exporter (*.jms)|*.jms|All Files (*.*)|*.*|" if output_name != undefined then ( setProp "jmsFilepath" (jmsFilepath= output_name) showJmsFilepath() ) return output_name ) local all_objects_array, all_object_names fn objHasInfo o = ( if ""!=getObjProp o "checksum" then return true if not gMax then if ""!=getObjProp o "jmsFilepath" then return true return false ) local getObjInfo fn refreshObjList = ( c= 0 infoObj= undefined objList= #() chkList= #() jmsList= #() for o in all_objects_array do if objHasInfo o then ( c+= 1 if c==1 then infoObj= o append objList ("*"+o.name) append chkList (getObjProp o "checksum") append jmsList (getDataPath (getObjProp o "jmsFilepath")) ) else ( append objList (" "+o.name) append chkList "" append jmsList "" ) lbObjects.items= objList lbChecksum.items= chkList lbJmsFilepath.items= jmsList if c==1 then getObjInfo infoObj ) on btPickJmsFilepath pressed do pickJmsFilepath() on etChecksum changed s do setProp "checksum" (checksum= s as integer) on etChecksum entered s do etChecksum.text= checksum as string on btAbout pressed do dlgAbout() on btEdit pressed do showSource dlgAbout fn getSceneObjects = ( clearSelection() max select all all_objects_array = selection as array clearSelection() all_object_names= for o in all_objects_array collect o.name return all_object_names ) fn getObjInfo o = ( checksum= getObjProp o "checksum" ifNot:checksum etChecksum.text= checksum as string setProp "checksum" checksum if not gMax then ( jmsFilepath= getObjProp o "jmsFilepath" ifNot:jmsFilepath setProp "jmsFilepath" jmsFilepath showJmsFilepath() ) ) fn setObjInfo o = ( if checksum!=undefined then ( setObjProp o "checksum" checksum setProp "checksum" checksum ) if not gMax then if isKindOf jmsFilepath String then ( setObjProp o "jmsFilepath" jmsFilepath setProp "jmsFilepath" jmsFilepath -- showJmsFilepath() ) refreshObjList() ) on lbObjects selected i do ( lbChecksum.selection= lbJmsFilepath.selection= i btGetObjInfo.enabled= objHasInfo all_objects_array[i] ) on lbChecksum selected i do ( lbObjects.selection= lbJmsFilepath.selection= i btGetObjInfo.enabled= objHasInfo all_objects_array[i] ) on lbJmsFilepath selected i do ( lbObjects.selection= lbChecksum.selection= i btGetObjInfo.enabled= objHasInfo all_objects_array[i] ) on lbObjects doubleclicked i do if btGetObjInfo.enabled then getObjInfo all_objects_array[i] on lbChecksum doubleclicked i do if btGetObjInfo.enabled then getObjInfo all_objects_array[i] on lbJmsFilepath doubleclicked i do if btGetObjInfo.enabled then getObjInfo all_objects_array[i] on btGetObjInfo pressed do getObjInfo all_objects_array[lbObjects.selection] on btSetObjInfo pressed do setObjInfo all_objects_array[lbObjects.selection] on roJmsExporter open do ( getSceneObjects() refreshObjList() if checksum==undefined then checksum= (getProp "checksum" ifNot:"0") as integer etChecksum.text= checksum as string if gMax then ( btPickJmsFilepath.caption= "output to Listener window" btPickJmsFilepath.enabled= false lbJmsFilepath.enabled= false ) else ( if not isKindOf jmsFilepath String then jmsFilepath= getProp "jmsFilepath" showJmsFilepath() ) ) --) on go_button pressed do ( start1= end1= 0 node_objects = #() node_array = #() node_translation = #() node_rotation = #() node_child_indices = #() node_first_child_index = #() node_next_sibling_index = #() marker_array = #() marker_parent_index = #() marker_translation = #() marker_rotation = #() marker_radius = #() geometry_objects = #() geom_parent_index = #() geom_bone_array = #() geom_object_has_skin = #() geom_regions = #() face_shader_index = #() face_region_index = #() vert_pos = #() vert_node0index = #() vert_node1index = #() vert_node1weight = #() vert_normal = #() tvert_pos = #() exportFailed = false sceneParent = undefined nodeParent = undefined numFaces = 0 boneAffectWarning = false objectsInScene = all_objects_array.count for a = 1 to objectsInScene do ( if exportFailed != true then ( objName = all_objects_array[a].name if (substring objName 1 5 as name == "frame" as name) or (substring objName 1 5 as name == "bip01" as name) then ( if (all_objects_array[a].parent == undefined) then ( if sceneParent != undefined then ( messagebox "There are too many actors in the scene! Can not export single model." title:"BlueStreak Error 1" exportFailed = true ) else ( sceneParent = all_objects_array[a] append node_objects all_objects_array[a] currCount = node_objects.count node_objects[currCount].name = "01" + node_objects[currCount].name ) ) else ( testParent = all_objects_array[a].parent i = 1 do ( i += 1 rootParent = testParent testParent = testParent.parent ) while (testParent != undefined) if rootParent != sceneParent then ( messagebox "There are too many actors in the scene! Can not export single model." title:"BlueStreak Error 2" exportFailed = true ) else ( append node_objects all_objects_array[a] currCount = node_objects.count if i < 10 then node_objects[currCount].name = "0" + i as string + node_objects[currCount].name else node_objects[currCount].name = i as string + node_objects[currCount].name ) ) ) else ( if all_objects_array[a].parent != undefined then ( if objName[1] == "#" then ( testParent = all_objects_array[a].parent do ( rootParent = testParent testParent = testParent.parent ) while testParent != undefined if rootParent == sceneParent then append marker_array all_objects_array[a] ) else ( testParent = all_objects_array[a].parent do ( rootParent = testParent testParent = testParent.parent ) while testParent != undefined if rootParent == sceneParent then append geometry_objects all_objects_array[a] ) ) ) ) ) if exportFailed != true then ( if node_objects.count == 0 then ( messageBox "There are no actors to export!" title:"BlueStreak Error 3" exportFailed = true ) else ( if marker_array == undefined and geometry_objects == undefined then ( messageBox "There was no geometry to export." title:"BlueStreak Error 4" exportFailed = true ) ) ) if exportFailed != true then ( -- Sort the nodes the way Halo likes it. The hierarchy level number was added to the beginning of each object's name. Then sort alphabetically. for n = 1 to node_objects.count do ( if node_array.count == 0 then node_array[n] = node_objects[n] else ( added = false for c = 1 to node_array.count do ( if added == false then ( if node_objects[n].name as name < node_array[c].name as name then ( insertItem node_objects[n] node_array c added = true ) else if c == node_array.count then append node_array node_objects[n] ) ) ) ) for n = 1 to node_array.count do node_array[n].name = substring node_array[n].name 3 -1 all_valid_nodes = true deletedName = " " for n = 2 to node_array.count do ( if findItem node_array node_array[n].parent == 0 then ( if all_valid_nodes == true then ( deletedName = node_array[n].name ) node_array[n] = undefined all_valid_nodes = false ) ) if all_valid_nodes == false then ( messageBox ("Can't add frame node \"" + deletedName + "\" because it is hung from a geometry or marker node.") title:"BlueStreak Error" ) for n = node_array.count to 1 by -1 do if node_array[n] == undefined then deleteItem node_array n -- All parent, child, and sibling node arrays are 1-based. When outputting they will be converted to 0-based. for n = 1 to node_array.count do ( temp_child_indices = #() for c = 1 to node_array[n].children.count do ( nodeChild = node_array[n].children[c] if nodeChild != undefined then ( childIndex = findItem node_array nodeChild if childIndex != 0 then append temp_child_indices (childIndex) ) ) node_child_indices[n] = temp_child_indices if node_child_indices[n].count == 0 then node_first_child_index[n] = 0 else ( sort (node_child_indices[n]) node_first_child_index[n] = node_child_indices[n][1] ) ) node_next_sibling_index[1] = 0 for s = 1 to node_child_indices.count do ( if (node_child_indices[s].count < 2 and node_child_indices[s][1] != undefined) then node_next_sibling_index[node_child_indices[s][1]] = 0 else ( for g = 1 to node_child_indices[s].count do if g == node_child_indices[s].count then node_next_sibling_index[node_child_indices[s][g]] = 0 else node_next_sibling_index[node_child_indices[s][g]] = node_child_indices[s][g+1] ) ) for m = marker_array.count to 1 by -1 do ( nodeParent = marker_array[m].parent while (substring nodeParent.name 1 5 as name != "frame" as name) and (substring nodeParent.name 1 5 as name != "bip01" as name) do nodeParent = nodeParent.parent parentIndex = findItem node_array nodeParent if parentIndex == 0 then deleteItem marker_array m else marker_parent_index[m] = parentIndex ) for g = geometry_objects.count to 1 by -1 do ( nodeParent = geometry_objects[g].parent while (substring nodeParent.name 1 5 as name != "frame" as name) and (substring nodeParent.name 1 5 as name != "bip01" as name) do nodeParent = nodeParent.parent parentIndex = findItem node_array nodeParent if parentIndex == 0 then deleteItem geometry_objects g else geom_parent_index[g] = parentIndex ) for n = 1 to node_array.count do ( if node_array[n].parent == undefined then ( if classOf node_array[n] == Biped_Object then ( node_translation[n] = biped.getTransform node_array[n] #pos node_rotation[n] = biped.getTransform node_array[n] #rotation ) else ( node_translation[n] = node_array[n].pos in coordsys parent rot = normalize (node_array[n].rotation) node_rotation[n] = (quat -rot.x -rot.y -rot.z rot.w) ) ) else ( if classOf node_array[n] == Biped_Object then ( m = mesh vertices:#() faces:#() --two temporary meshes that serve as placeholders for the mp = mesh vertices:#() faces:#() --biped bones since these methods can not be evoked on them m.parent = mp mpRot = biped.getTransform node_array[n].parent #rotation mp.rotation = (quat -mpRot.x -mpRot.y -mpRot.z mpRot.w) mp.pos = biped.getTransform node_array[n].parent #pos mRot = biped.getTransform node_array[n] #rotation m.rotation = (quat -mRot.x -mRot.y -mRot.z mRot.w) m.pos = biped.getTransform node_array[n] #pos in coordsys parent node_translation[n] = m.pos in coordsys parent rot = m.rotation node_rotation[n] = normalize (quat -rot.x -rot.y -rot.z rot.w) delete m delete mp ) else ( in coordsys parent node_translation[n] = node_array[n].pos in coordsys parent rot = node_array[n].rotation node_rotation[n] = normalize (quat -rot.x -rot.y -rot.z rot.w) ) ) ) for m = 1 to marker_array.count do ( in coordsys parent marker_translation[m] = marker_array[m].pos in coordsys parent rot = marker_array[m].rotation if isKindOf marker_array[m] Sphere then r=marker_array[m].radius else r=1 marker_rotation[m] = normalize (quat -rot.x -rot.y -rot.z rot.w) marker_radius[m] = r ) ) if exportFailed != true then ( ttm= #() tmesh= #() ttm.count= tmesh.count= geometry_objects.count for g = 1 to geometry_objects.count do ( clearSelection () select geometry_objects[g] ttm[g]= geometry_objects[g].modifiers[#'turn to mesh'] if ttm[g] == undefined then ( ttm[g]= Turn_to_Mesh() addModifier geometry_objects[g] ttm[g] ) tmesh[g] = snapshotAsMesh geometry_objects[g] ) geom_materials= #() for g = 1 to geometry_objects.count do ( mat= geometry_objects[g].material if (classOf mat) == MultiMaterial then ( for mi = 1 to mat.numSubs do ( sm= mat.materialList[mi] if sm!=undefined then ( mName= sm.name if (findItem geom_materials mName) == 0 then append geom_materials mName ) ) ) else if (classOf mat) == StandardMaterial then ( mName= mat.name if (findItem geom_materials mName) == 0 then append geom_materials mName ) ) pushPrompt "shaders..." meshesMissingIDs= #() for g = 1 to geometry_objects.count do ( mat= geometry_objects[g].material fc= tmesh[g].faces.count missingIDs= #() if (classOf mat) == MultiMaterial then ( sia= #() mIdList= mat.materialIdList midc= mIdList.count sia.count= midc for mIdIndex=1 to midc do ( mID= mat.materialIdList[mIdIndex] sm= mat[mID] mName= sm.name si= findItem geom_materials mName sia[mIdIndex]= si-1 ) fsia=#() fsia.count= fc for fi = 1 to fc do ( fID= getFaceMatID tmesh[g] fi siai= findItem mIdList fID if siai>0 then fsia[fi]= sia[siai] else if 0==findItem missingIDs fID then append missingIDs fID -- sm= mat[fID] -- mName= sm.name -- fsia[fi]= (findItem geom_materials mName)-1 ) face_shader_index= face_shader_index + fsia ) else if (classOf mat) == StandardMaterial then ( mName= mat.name sID= (findItem geom_materials mName)-1 face_shader_index= face_shader_index+(for f = 1 to fc collect sID) ) if missingIDs.count>0 then append meshesMissingIDs #(g, missingIDs) ) popPrompt() pushPrompt "indexing regions..." for g = 1 to geometry_objects.count do ( max modify mode modPanel.setCurrentObject ttm[g] ssNames= $.faces.selSetNames for r = 1 to ssNames.count do if findItem geom_regions ssNames[r] == 0 then append geom_regions ssNames[r] ) popPrompt() if meshesMissingIDs.count>0 then ( s= "face ID(s) found that aren't in the MultiMaterial(s):" for mida in meshesMissingIDs do ( meshName= geometry_objects[mida[1]].name meshIDsMissing= mida[2] as string s= s + "\n" + meshName + ": " + meshIDsMissing ) s=s+"\n\nExport aborted" messageBox s title:"Missing material IDs" exportFailed= true ) if not exportFailed then ( if not gMax then if not isKindOf jmsFilepath String then exportFailed= (undefined == pickJmsFilepath()) else if undefined == findString jmsFilepath "\\data\\" then exportFailed= (undefined == pickJmsFilepath()) start1 = timeStamp() if geometry_objects.count != 0 then ( numFaces= 0 vc= 0 for g = 1 to tmesh.count do ( numFaces += getNumFaces tmesh[g] vc+= 3*tmesh[g].faces.count ) DisableSceneRedraw() vert_pos.count= vc tvert_pos.count= vc vert_normal.count= vc vert_node0index.count= vc vert_node1index.count= vc vert_node1weight.count= vc face_region_index.count= numFaces face_shader_index.count= numFaces v = 0 for g = 1 to geometry_objects.count do ( geom_object_has_tverts= (0 < getNumTVerts tmesh[g]) max modify mode modPanel.setCurrentObject ttm[g] -- Turn_to_Mesh modifier applied. -- $ is an Editable_Mesh pushPrompt ($.name+" regions...") face_regionID = #() face_regionID.count= (fc= $.faces.count) for r = 1 to geom_regions.count do if undefined != (rFaces= $.faces[geom_regions[r]]) then for f = 1 to rFaces.count do if face_regionID[ faceIndex = rFaces[f].index ] == undefined then face_regionID[faceIndex] = r - 1 regionsMissing = false for f = 1 to fc do if face_regionID[f] == undefined then regionsMissing= true if regionsMissing then ( regionIndex = findItem geom_regions "unnamed" if regionIndex == 0 then ( append geom_regions "unnamed" regionIndex = geom_regions.count ) for f = 1 to fc do if face_regionID[f] == undefined then face_regionID[f] = regionIndex - 1 ) for f = 1 to fc do (append face_region_index face_regionID[f]) popPrompt() theSkin = geometry_objects[g].modifiers[#'skin'] if theSkin != undefined then ( if theSkin.enabled then ( pushPrompt (geometry_objects[g].name+" weights...") max modify mode modPanel.setCurrentObject theSkin subobjectLevel = 1 numBones = skinOps.getNumberBones theSkin if numBones > 1 then ( geom_object_has_skin[g] = true temp_bone_array = #() for b = 1 to numBones do ( boneName = skinOps.getBoneName theSkin b 0 theNodesArray = getNodeByName boneName exact:true ignoreCase:false all:true if not isKindOf theNodesArray array then theNodesArray= #(theNodesArray) i=1 while i <= theNodesArray.count do if 0==findItem node_array theNodesArray[i] then deleteItem theNodesArray i else i+=1 if theNodesArray.count > 1 then ( messageBox ("Warning: cannot distinguish between nodes with identical names in skin modifier.\n"+geometry_objects[g].name+": "+boneName) title:"BlueStreak Error" exportFailed= true ) nodeNum = findItem node_array theNodesArray[1] if nodeNum == 0 then ( messageBox ("Warning: bone " + boneName + " in skin modifier is not a node.") title:"BlueStreak Error" append temp_bone_array 1 ) else append temp_bone_array nodeNum ) geom_bone_array[g] = temp_bone_array ) popPrompt() ) ) default_node0index = (geom_parent_index[g] - 1) pushPrompt (geometry_objects[g].name+" topology...") face_verts = #() face_verts.count= fc face_tverts = #() face_tverts.count= fc face_SG = #() face_SG.count= fc for f = 1 to fc do ( face_verts[f] = getFace tmesh[g] f face_SG[f] = getFaceSmoothGroupB tmesh[g] f if geom_object_has_tverts then face_tverts[f] = getTVFace tmesh[g] f for vertices = 1 to 3 do ( v += 1 vert_pos[v] = getVert tmesh[g] face_verts[f][vertices] if geom_object_has_skin[g] == true then ( skinNode0 = skinOps.getVertexWeightBoneID theSkin face_verts[f][vertices] 1 weightedNode0Index = geom_bone_array[g][skinNode0] - 1 vert_node0index[v] = weightedNode0Index boneAffectNum = skinOps.getVertexWeightCount theSkin face_verts[f][vertices] if boneAffectNum > 2 do boneAffectWarning = true if boneAffectNum == 1 then ( if boneAffectNum > 2 do boneAffectWarning = true vert_node1index[v] = -1 vert_node1weight[v] = 0 ) else ( skinNode1 = skinOps.GetVertexWeightBoneID theSkin face_verts[f][vertices] 2 weightedNode1Index = geom_bone_array[g][skinNode1] - 1 weightedNode1Weight = skinOps.GetVertexWeight theSkin face_verts[f][vertices] 2 if weightedNode1Weight > 0.5 then ( vert_node0index[v] = weightedNode1Index vert_node1index[v] = weightedNode0Index vert_node1weight[v] = (1.0 - weightedNode1Weight) ) else ( vert_node0index[v] = weightedNode0Index vert_node1index[v] = weightedNode1Index vert_node1weight[v] = weightedNode1Weight ) ) ) else ( vert_node0index[v] = default_node0index vert_node1index[v] = -1 vert_node1weight[v] = 0 ) vNormal = [0,0,0] vNormal += getFaceNormal tmesh[g] f simFaces = meshop.getFacesUsingVert tmesh[g] face_verts[f][vertices] as array del_index = findItem simFaces f deleteItem simFaces del_index for s = 1 to simFaces.count do ( affectNormal= false neiSG = getFaceSmoothGroupB tmesh[g] simFaces[s] for aN = 1 to face_SG[f].count do if not affectNormal then if findItem neiSG face_SG[f][aN] != 0 then affectNormal= true if affectNormal then vNormal+= getFaceNormal tmesh[g] simFaces[s] ) vert_normal[v]= normalize(vNormal) if geom_object_has_tverts then tvert_pos[v] = getTVert tmesh[g] face_tverts[f][vertices] else tvert_pos[v] = [0,0,0] ) ) popPrompt() max create mode clearSelection() ) enableSceneRedraw() if boneAffectWarning == true then messageBox "Warning: some vertices are weighted by more than two bones." title:"BlueStreak Error" ) else ( messageBox "Warning: there was no geometry to export." title:"BlueStreak Error" ) ) for g = 1 to geometry_objects.count do deleteModifier geometry_objects[g] ttm[g] ) if not exportFailed then (-- -- Output JMS text to listener or file -- if gMax then ( ClearListener() jms = listener pushPrompt "Streaming to Listener..." ) else ( jms = createfile jmsFilepath if dataPath != undefined then pushPrompt ("Saving "+dataPath+"...") ) node_count = node_array.count -- Accellerate gMax export by reducing new-line character usage to minimum needed by tool format "%\t%\t%\n" 8200 (etChecksum.text as integer) node_count to:jms for n = 1 to node_count do ( format "%\t" node_array[n].name to:jms format "%\t" (node_first_child_index[n] - 1) to:jms format "%\t" (node_next_sibling_index[n] - 1) to:jms format "%\t%\t%\t%\t" node_rotation[n].x node_rotation[n].y node_rotation[n].z node_rotation[n].w to:jms format "%\t%\t%\n" node_translation[n].x node_translation[n].y node_translation[n].z to:jms ) mat_count = geom_materials.count format "%\n" mat_count to:jms for m = 1 to mat_count do format "%\t%\n" geom_materials[m] "" to:jms marker_count = marker_array.count format "%\n" marker_count to:jms for m = 1 to marker_count do ( format "%\t-1\t" (substring marker_array[m].name 2 -1) to:jms format "%\t" (marker_parent_index[m] - 1) to:jms format "%\t%\t%\t%\t" marker_rotation[m].x marker_rotation[m].y marker_rotation[m].z marker_rotation[m].w to:jms format "%\t%\t%\t" marker_translation[m].x marker_translation[m].y marker_translation[m].z to:jms format "%\n" marker_radius[m] to:jms -- radius working, courtesy of Choking Victem ) region_count = geom_regions.count format "%\n" region_count to:jms for r = 1 to region_count do format "%\n" geom_regions[r] to:jms numVerts = vert_pos.count format "%\n" numVerts to:jms for v = 1 to numVerts do ( format "%\t" vert_node0index[v] to:jms format "%\t%\t%\t" vert_pos[v].x vert_pos[v].y vert_pos[v].z to:jms format "%\t%\t%\t" vert_normal[v].x vert_normal[v].y vert_normal[v].z to:jms format "%\t" vert_node1index[v] to:jms format "%\t" vert_node1weight[v] to:jms format "%\t" tvert_pos[v].x to:jms format "%\t0\n" tvert_pos[v].y to:jms -- w in uvw = 0? ) format "%\n" numFaces to:jms c = 0 for n = 1 to numFaces do ( format "%\t" face_region_index[n] to:jms format "%\t" face_shader_index[n] to:jms format "%\t%\t%\n" c (c+1) (c+2) to:jms c += 3 ) end1 = timeStamp() if not gMax then close jms else ( pushPrompt "Use the dialog window to launch GrabListener. Right click it, and select Open" getOpenFilename caption: "launch GrabListener" \ filename: (grabListenerPath + "\\grabListener.exe") \ types: "*.exe|*.exe" popPrompt() ) popPrompt() )-- -- end check for export failed if exportFailed then ( messageBox "Export module failure" title:"Export" for a = 1 to all_objects_array.count do all_objects_array[a].name = all_object_names[a] ) else ( -- messageBox (timeString (end1-start1)) title:"Export time:" -- if undefined != dataPath then -- runTool dataPath ) ) ) ClearListener() -- if exporter has an error, redraw may be left disabled, so, while isSceneRedrawDisabled() do enableSceneRedraw() -- re-running the script will fix it CreateDialog roJmsExporter -- End of Script --