include "ogre/lib/ogreSkeletonLib_usefulfns.ms" include "ogre/lib/ogrebipedlib.ms" ---------------------------------------------------------------------------------------- -- ----------------------------------- WRITE MESH ----------------------------------- -- ---------------------------------------------------------------------------------------- ----------------------------------------------------------------- -- Global 'variables' -- There is an array with vertices datas for each submesh -- There is also an array made up of faces. ----------------------------------------------------------------- verticesArrays=#() ; facesArrays=#() ; boneAssignments=#() ; submeshesId=#() ; materialName = "" ; -- verticesArrays[i] will describe the subMesh number i and its elements will be ogreVertices where -- ogreVert = #(x,y,z,nx,ny,nz,r,g,b,a,u1,v1,u2,v2....) -- ----- -------- ------- --------------- -- Pos Nmal RGBA UVs sets -- RGBA being the vertex color when relevant (Optional) -- A vertex can contain multiple UVs sets (Optional) -- facesArrays[i] is an array of Point3 describing the subMesh i. Each Point3 contains vertices indices for a face that is gonna be exported -- boneAssignments[i] describes the bones assignements for subMesh i. It is an array of triplets like #(vertexIndex,boneIndex,weight) -- submeshesId is the list of material Ids -- materialName is the name that Ogre will use ---------------------------------------------------------------- -- exploreMesh returns a string which is "OK" or an error message -- if there are warnings, it displays message boxes. ----------------------------------------------------------------- function exploreMesh pmesh exportUV exportColours= ( local material, answer, m ; answer = "" ; m = snapShotAsMesh pmesh ; -- first, is a material defined ? material = pmesh.material ; if (material == undefined) then answer = "This mesh doesn't have any material, please apply one\n" ; else -- then, are UVW coords set up ? if (exportUV and getNumTVerts m == 0) then answer = "This mesh must have UVW coords in order to be exported" ; if (answer == "") then answer = "OK" ; delete m ; answer ; ) ---------------------------------------------------------------- -- returns the correct normal for the vertex -- according to smoothing groups ----------------------------------------------------------------- function getVertexNormalAccordingToSmoothingGroups selectedMesh faceIndex vertexIndex = ( local normal; local faceSmoothingGroup = getFaceSmoothGroup selectedMesh faceIndex if faceSmoothingGroup == 0 then ( -- if not smooth use face normal normal = getFaceNormal selectedMesh faceIndex ) else ( local vertexIndexes = getFace selectedMesh faceIndex; local vI = vertexIndexes[vertexIndex] local n = [0, 0, 0] -- point3 for adjoiningFaceIndex in (meshop.getFacesUsingVert selectedMesh vI) do ( sg = getFaceSmoothGroup selectedMesh adjoiningFaceIndex; and_sg = bit.and sg faceSmoothingGroup ; if (and_sg != 0) then n += getFaceNormal selectedMesh adjoiningFaceIndex ; ) normal = normalize n; ) normal; ) function tabEquals tab1 tab2 = ( if (tab1.count != tab2.count) then return false; for i=1 to tab1.count do if (tab1[i] != tab2[i]) then return false; return true; ) function doesVertexExistAlready searchTable vertexIndex vertexNormal vertexColorIndex vertexAlphaIndex UVs exportUV exportColor = ( local start_uvs; vertex = #(); --format "vertex a tester % % \n" vertexIndex vertexNormal; if (searchTable[vertexIndex]==undefined) then return 0; for vertex in searchTable[vertexIndex] do ( if (vertex[2]!=vertexNormal) then continue; if (exportColor) then ( if (vertex[3]!=vertexColorIndex) then continue; if (vertex[4]!=vertexAlphaIndex) then continue; start_uvs = 4; ) else ( start_uvs = 2; ) if (exportUV) then ( local equal = true; for i=1 to UVs.count do ( if (vertex[start_uvs+i]!=UVs[i]) then ( equal = false; exit; ) ) if (not equal) then continue; ) return vertex[1] ; ) return 0; ) ---------------------------------------------------------------------------- -- Retrieves al the datas which wil be used -- tmesh is the mesh object -- flipyz = true if you want coords to fit in OGRE. -- flipNormal = true if you want to flip normals -- scale : the scale factor -- exportUV = true if you want to export texture -- numUVsets : number of texture coordinates to export (if exportUV is true, the minimum is 1. if exportUV is false, this parameter is irrelevant) -- exportColor = true if you want to export vertices colors -- sk : the skin modifier (may be undefined) -- phy : the physique modifier (may be undefined) -- stores datas in verticesArrays and facesArrays. ---------------------------------------------------------------------------- function getDatas tmesh flipyz scale flipNormal exportUV numUVsets exportColours exportHelpers sk phy = ( local face; --index of the current face local localVertexIndex; --index of the current vertex (relative to the current face) ie : 1, 2 or 3 local vertexNormal; --normal of the current vertex (Point3) local vertexPosition; --position of the current vertex (Point3) local faceVerticesIndices; --indices of the vertex for the current face (Point3) local vertexIndex; --index of the current vertex (in the mesh) local matId; --material Id of the current face local numFaces; --number of faces in the mesh local faceVertexColorIndices; --indices of the vertices for the current face in the vertex color table of the mesh (Point3) local vertexColorIndex; --index of the current vertex in the vertex color table of the mesh local vertexColor; --vertex color for the current vertex (color) local faceVertexAlphaIndices; --indices of the vertices for the current face in the vertex alpha table of the mesh (Point3) local vertexAlpha; --vertex alpha of the current alpha local vertexAlphaIndex; --index of the current vertex in the vertex alpha map channel (-2) local ogreFace; --indices of the vertices for the current face (references the list of vertices that is gonna be exported, not the vertices of the original mesh) local vertexWeightCount; --number of bones influencing the current vertex local vertexWeight; --current weight local searchTable ; local k ; local rootId ; local UVcoords; -- will contain the texture coordinates for the current vertex. its size will be numUVsets*2 if exportUV is true. -- searchTables will contain a searchTable for every subMesh. -- searchTable will be the current table for the current subMesh. -- Every vertex will be stored here to check for duplicates. searchTable=#() ; searchTables=#() ; -- initialisation of the current ogre face as a vector ogreFace=Point3 12 12 12 ; -- Data arrays init. verticesArrays=#() ; facesArrays=#() ; boneAssignments = #() ; submeshesId = #() ; UVcoords=#() ; -- compute bones list for the model. BonesList=#() computeBonesList phy sk exportHelpers ; numFaces = (getNumFaces tmesh); -- For each face for face = 1 to numFaces do -- LOOP on FACES -- ( OgreExportObject.exportProgress.value = (100.0*face/numFaces); faceVerticesIndices = getFace tmesh face ; matId = getFaceMatId tmesh face ; -- Vertex Color Face if (exportColours) then ( faceVertexColorIndices = meshOp.getMapFace tmesh 0 face ; -- 0 is the vertex color channel faceVertexAlphaIndices = meshOp.getMapFace tmesh -2 face ; -- -2 is the vertex alpha channel ) else ( faceVertexColorIndices = Point3 1 1 1 ; faceVertexAlphaIndices = Point3 1 1 1 ; ) -- For each vertex whose face is made up of. for localVertexIndex=1 to 3 do -- LOOP on VERTICES -- ( vertexIndex = (int) (faceVerticesIndices[localVertexIndex]) ; vertexColorIndex = (int) (faceVertexColorIndices[localVertexIndex]) ; vertexAlphaIndex = (int) (faceVertexAlphaIndices[localVertexIndex]); vertexNormal = getVertexNormalAccordingToSmoothingGroups tmesh face localVertexIndex; -- flip normal capability if (flipNormal) then ( vertexNormal = vertexNormal * -1 ) -- we retrieve datas. it depends on options. -- UV face if (exportUV) then ( UVcoords=#(); for ch=1 to numUVsets do ( local vertInds = meshOp.getMapFace tmesh ch face ; local UVW = meshOp.getMapVert tmesh ch vertInds[localVertexIndex] ; -- retrieve the UV for the corresponding channel. append UVcoords UVW[1]; append UVcoords UVW[2]; -- don't care about the W coordinate ) ) else ( UVcoords=#(); ) -- we try to find the corresponding searchtable. if (searchTables[matId] == undefined ) then searchTables[matId]=#() ; -- we found a new subMesh, create the searchTable for it searchTable = searchTables[matId] ; -- set the searchTable to the current subMesh newVertex = 1 ; ogreVertNum = 1; -- Maybe this vertex has already been found. -- So we use searchTable. res = doesVertexExistAlready searchTable vertexIndex vertexNormal vertexColorIndex vertexAlphaIndex UVcoords exportUV exportColours; if (res==0) then ( newVertex = 1 ; --format "nouveau vertex % % %\n" vertexIndex vertexNormal UVcoords; ) else ( newVertex = 0; ogreVertNum = res; ) if (newVertex == 1) then -- That is to say it has not been found. ( -- Maybe the material found defines a new submesh... if (verticesArrays[matId] == undefined) then ( format "- Submesh detected: material ID = %\n" matId verticesArrays[matId] = #() ; boneAssignments[matId] = #() ; append submeshesId matId ; ) -- the vertex number for the current submesh must be updated -- vertex number is increased ogreVertNum = verticesArrays[matId].count + 1; -- it is added to the searchTable if (searchTable[vertexIndex]==undefined) then ( searchTable[vertexIndex] = #() ; ) local data = #(); append data ogreVertNum ; n = copy vertexNormal ; append data n ; if (exportColours) then ( append data VertexColorIndex ; append data VertexAlphaIndex ; ) if (exportUV) then ( if (UVcoords.count > 0) then ( for uv=1 to UVcoords.count do append data UVcoords[uv]; ) ) append searchTable[vertexIndex] data ; -- we retrieve data vertexPosition = getVert tmesh faceVerticesIndices[localVertexIndex] ; vertexColor = Point3 0 0 0; vertexAlpha = 255; if (exportColours) then ( vertexColor = (meshOp.getMapVert tmesh 0 vertexColorIndex); vertexAlpha = (meshOp.getMapVert tmesh -2 vertexAlphaIndex)[1]; ) -- change scale vertexPosition = vertexPosition * scale ; -- flip axes if (flipyz) then ( vertTmp = copy vertexPosition ; vertexPosition[2] = vertTmp[3] ; vertexPosition[3] = -vertTmp[2] ; nmalTmp = copy vertexNormal ; vertexNormal[2] = nmalTmp[3] ; vertexNormal[3] = -nmalTmp[2] ; ) -- store the vertex in verticesArrays vertexData = #(vertexPosition[1],vertexPosition[2],vertexPosition[3],vertexNormal[1],vertexNormal[2],vertexNormal[3],vertexColor[1],vertexColor[2],vertexColor[3],vertexAlpha) ; if (exportUV) then ( for ch=1 to numUVsets do ( append vertexData UVcoords[1+(ch-1)*2]; append vertexData UVcoords[2+(ch-1)*2]; ) ) append verticesArrays[matId] vertexData ; -- Vertex is added to datas -- And now, bone assignments. (if a skin modifier is present) -- It seems that there are issues when just few vertices have bone assignments. -- So there is at least the root assignment. if (sk != undefined) then ( vertexWeightCount = skinOps.getVertexWeightCount sk vertexIndex ; if (vertexWeightCount > 4) then ( if (not g_MAX) then ( format "*** vertex % has more than 4 bones assigned...\n" vertexIndex; ) ) for k=1 to vertexWeightCount do ( bid = skinOps.getVertexWeightBoneID sk vertexIndex k ; bname = skinOps.getBoneName sk bid 1 ; bname = replaceSpaces bname; vertexWeight = skinOps.getVertexWeight sk vertexIndex k ; id_bone = findItem BonesList bname; if (id_bone != 0) then append boneAssignments[matId] #(ogreVertNum-1,id_bone-1,vertexWeight) ; ) -- assignment to the root bone. if (vertexWeightCount==0) then ( -- gets the root Id: rootId=getRootsId sk rootname = skinOps.getBoneName sk rootId[1] 1 ; id_bone = findItem BonesList rootname ; if (id_bone != 0) then append boneAssignments[matId] #(ogreVertNum-1,id_bone-1,1) ; ) ) -- same thing with physique modifier if defined if (phy != undefined) then ( vertexWeightCount = physiqueOps.getVertexBoneCount $ vertexIndex ; if (vertexWeightCount > 4) then ( if (not g_MAX) then ( format "*** vertex % has more than 4 bones assigned...\n" vertexIndex; ) ) for k=1 to vertexWeightCount do ( bone = physiqueOps.getVertexBone $ vertexIndex k vertexWeight = physiqueOps.getVertexWeight $ vertexIndex k -- search the bone number bname = replaceSpaces bone.name; id_bone = findItem BonesList bname ; if (id_bone!=0) then append boneAssignments[matId] #(ogreVertNum-1,id_bone-1,vertexWeight) ; ) -- assignment to the first bone if the vertex was not assigned. if (vertexWeightCount==0) then ( -- gets the root Id: append boneAssignments[matId] #(ogreVertNum-1,0,1) ; ) ) ) ogreFace[localVertexIndex] = ogreVertNum - 1; ) -- flip normal capability if (flipNormal) then ( faceTmp = copy ogreFace ; ogreFace[2] = faceTmp[3] ; ogreFace[3] = faceTmp[2] ; ) if (facesArrays[matId] == undefined) then facesArrays[matId] = #() ; append facesArrays[matId] #(ogreFace[1],ogreFace[2],ogreFace[3]) ; -- Face is added to datas ) ) ------------------------------------------------- -- writes in the mesh.xml file -- outName : filename -- exportUV = true if you want to export texture -- numUVsets : number of UVs sets per vertex to be exported (only relevant if exportUV = true) -- exportColor = true if you want to export vertices colors -- material : material used by the mesh -- Uses the arrays verticesArrays and facesArrays ------------------------------------------------- function writeM exportUV numUVsets exportColours material outName = ( local a,v,f,submatname,hasSkeleton,outFile,hasColours,matId ; hasSkeleton = false ; texCoordString = "" ; if (exportUV) then ( texCoordString = "texture_coords=\"" + (numUVsets as string) + "\" " ; for num=1 to numUVsets do ( texCoordString = texCoordString + "texture_coords_dimensions_" + ((num-1) as string) + "=\"2\" "; -- I really don't care about the W coordinates ) ) hasColours = "false" ; if (exportColours) then hasColours = "true" ; -- the final file is created if (g_MAX) then ( ClearListener(); if (g_MAX_use_listener) then format("%\n") (outName + ".mesh.xml"); outFile = listener; ) else ( outFile = createfile (outName + ".mesh.xml") ; ) -- writes the header format("\n") to:outFile ; -- submeshes start format("\t\n") to:outFile ; -- for each submesh for matId in submeshesId do ( -- Do we need 32-bit indexes? use32bitindexes = "false"; if arrayLength verticesArrays[matId] > 65535 then use32bitindexes = "true"; -- get the name of the sub material if needed. submatname = replacespaces material.name ; if (classof material == MultiMaterial) then ( if (material.materialList[matId]==undefined) then ( msg = ""; format "You are using in your mesh a material Id (%) that does not exist in your MultiMaterial (%)\nMaterial information won't be properly exported." matId submatname to:msg ; messageBox msg; ) else ( submatname += "/" + replacespaces material.materiallist[matId].name ; ) ) -- HELLO ! -- --------------------------------------------------------------------------------- -- IF YOU COME HERE BECAUSE YOUR OBJECT FAILED EXPORTING, MAYBE THAT'S BECAUSE -- -- YOU USE MATERIAL ID IN YOUR MESH THAT DOESN'T EXIST IN YOUR MULTIMATERIAL -- --------------------------------------------------------------------------------- format("\t\t\n") submatname use32bitindexes to:outFile ; if (not g_MAX) then format "- writing faces...\n" format("\t\t\t\n") (arraylength facesArrays[matId]) to:outFile; -- for each face for f in facesArrays[matId] do ( format("\t\t\t\t\n") ((int)f[1]) ((int)f[2]) ((int)f[3]) to:outFile ; ) format("\t\t\t\n") to:outFile ; if (not g_MAX) then format "- writing vertices...\n" format("\t\t\t\n") (arrayLength verticesArrays[matId] ) to:outFile; format("\t\t\t\t\n") hasColours TexCoordString to:outFile ; -- for each vertex for v in verticesArrays[matId] do ( format("\t\t\t\t\t\n") to:outFile ; format("\t\t\t\t\t\t\n") v[1] v[2] v[3] to:outFile ; format("\t\t\t\t\t\t\n") v[4] v[5] v[6] to:outFile ; if (exportUV) then ( for ch=1 to numUVsets do format("\t\t\t\t\t\t\n") v[11+((ch-1)*2)] (1 - v[12+((ch-1)*2)]) to:outFile ; ) if (exportColours) then ( color_string = (v[7] as string) + " " + (v[8] as string) + " " + (v[9] as string) + " " +(v[10] as string); format("\t\t\t\t\t\t\n") color_string to:outFile ; ) format("\t\t\t\t\t\n") to:outFile ; ) format("\t\t\t\t\n") to:outFile ; format("\t\t\t\n") to:outFile ; -- and now bone assignments (and skeleton), if there is at least one element in boneAssignments array. if ((arrayLength boneAssignments[matId]) != 0) then ( hasSkeleton = true ; if (not g_MAX) then format "- writing bone assignments...\n" format("\t\t\t\n") to:outFile ; for a in boneAssignments[matId] do ( format("\t\t\t\t\n") a[1] a[2] a[3] to:outFile ; ) format("\t\t\t\n") to:outFile ; ) -- submesh end format("\t\t\n") to:outFile ; ) -- submeshes end format("\t\n") to:outFile ; -- Skeleton link if there is at least one bone assignement. if (hasSkeleton) then ( t = filterstring outName "\\" ; format ("\t\n") (t[arrayLength t] + ".skeleton") to:outFile ; ) format("\n") to: outFile ; if (not g_MAX) then ( close outFile ; ) else ( if (g_MAX_use_listener) then format("\n") to: outFile; ) ) --------------------------------- -- writes the mesh: main function --------------------------------- function writeMesh pmesh exportOptions out_name = ( local m,sk,outFile,message,phy ; m = snapshotAsMesh pmesh ; -- tries to find errors message = exploreMesh pmesh exportOptions.exportUV exportOptions.exportColours; if (message != "OK") then ( MessageBox ("\n There is a problem with your mesh:\n" + message + "\n\nOperation aborted") ; delete m ; return false ; ) else ( format "\n\n" format "------------------------------------------\n" format "------- OGRE Mesh Exporter Log -------\n" format "----- -----\n" -- get the skin modifier ( may be undefined ) -- and physique modifier phy = getPhysique pmesh ; sk = getSkin pmesh; if (sk != undefined) then format "Skin modifier detected.\n" if (phy != undefined) then format "Physique modifier detected.\n" -- if not undefined, skin modifier is selected in modifier tab. Or there will be an error. if (sk != undefined) then ( -- in order to perform, skin should be opened max modify mode ; modPanel.setCurrentObject pmesh.modifiers[#Skin] ; ) -- physique if (phy != undefined) then ( -- in order to perform, skin should be opened max modify mode ; modPanel.setCurrentObject pmesh.modifiers[#Physique] ; --physiqueOps.setInitialPose pmesh true ; ) OgreExportObject.exportProgress.value = 0; -- retieving material if (pmesh.material != undefined) then ( materialName = pmesh.material.name ; replaceSpaces materialName ; ) else materialName = pmesh.name + "Material" ; format "Material name exported : \n- %/*** \n" materialName ; -- retrieving all datas format "Retrieving vertices and faces data : \n" ; getDatas m exportOptions.flipyz exportOptions.scale exportOptions.flipNormal exportOptions.exportUV exportOptions.UVchannels exportOptions.exportColours exportOptions.exportHelpers sk phy; -- writing in the file format "Writing in file %.mesh.xml : \n" out_name ; WriteM exportOptions.exportUV exportOptions.UVchannels exportOptions.exportColours pmesh.material out_name ; if (not g_MAX) then format "Export successful.\n" delete m ; if (not g_MAX) then ( format "----- -----\n" format "---------- END ---------\n" format "------------------------------------------\n" ) --MessageBox ("Exporting mesh successful !") ; OgreExportObject.exportProgress.value = 100; ) return true ; )