-- Script to import M2 files found in the mpq files of world of warcraft -- into GMax or 3d studio max. The script loads vertices with uv coords -- and submeshes as found in the M2 file. Textures are not loaded but can be -- assigned in a later step manually. The submeshes are created with dummy cubes -- as bones for skinning. -- INSTALLATION -- Place me in 3dsmax7\stdplugs\stdscripts\ -- restart 3ds max, find WOW menu on main menu bar -- If menu item don't work normaly or do not exists use RunScript button from MaxScript menu and run this scipt file. -- UI work and animation bug fixed by me (aka DeLazarus), April 2006. -- Modifications was tested only on 3ds max 7 -- Some models imports v. Be brary slowly. Be brave :) -- Injoy! -- v2.6.4 19.06.2009 -- GLOBALS AND STRUCTURES --global filename = "c:\\tmp\\Horse.m2" --HighElfMale_Warrior.m2" --Ghoul.m2" global filename = "c:\\temp\\Banshee.m2"--"D:\\mpq\\succubus\\Succubus.m2" --HighElfMale_Warrior.m2" --Ghoul.m2" -- there are no any warrnings of situation like this: LoadAnimation=true LoadBones=false, UI must work over this -- and btw some models do not load if bones are not loaded. That is why I froze its check box global LoadBones = true global LoadAnimation = true global frameEnd = 10 global head global bstream global step global verts_read global views_read global view_inds_read global view_tris_read global bones_read global name_read global sequences_read global animations_read fn InitLoader = ( verts_read = #() views_read = #() view_inds_read = #() view_tris_read = #() bones_read = #() name_read = "" sequences_read = #() animations_read = #() ) struct WOW2_Header ( magic,version,namelen,ofsname, un1,nGlobalSequences,ofsGlobalSequences,nAnimations, ofsAnimations,nC,ofsC,nD,ofsD,nBones,ofsBones,nF,ofsF, nVertices,ofsVertices,nViews,ofsViews,nG,ofsG,nTextures, ofsTextures,nH,ofsH,nI,ofsI,nJ,ofsJ,nK,ofsK,nX,ofsX, nBoneGroups,ofsBoneGroups,nTexLookup,ofsTexLookup,nL,ofsL,nM,ofsM,nN, ofsN,n14floats,nBoundingTriangles,ofsBoundingTriangles, nBoundingVertices,ofsBoundingVertices,nBoundingNormals, ofsBoundingNormals,nO,ofsO,nP,ofsP,nQ,ofsQ,nR,ofsR,nS, ofsS,nT,ofsT,nU,ofsU,nV,ofsV --nG Magic1 ofsG Magic2 ) struct WOW2_Vertex ( pos,bw1,bw2,bw3,bw4,bi1,bi2,bi3,bi4,normal,uv,n2floats ) struct WOW2_Views ( nindex,ofsnindex, ntris,ofsntris,nverts,ofsnverts, nsubmesh,ofsnsubmesh,ntextures,ofsntextures,unknown1, ind,tri -- loaded vert and tri index ) -- nAnimations struct WOW2_Animations ( animid,startseq,endseq,speed,unknown1,unknown2,unknown3, unknown4,unknown5,bbox,radius,unknown6,unknown7 ) -- the actual animation info used for different animation types struct WOW2_Anim ( type,flags,linetypes,linetypeofs,frames,framesofs,data,dataofs ) -- bones including animation data struct WOW2_Bones ( geosetanim,flags,parentbone,unknown1,geoset, trans,rot,scale,pivot,maxname ) struct WOW2_BoneWeightIndex ( cnt,bw,bi ) -- one submesh part with its verts stored in vs, faces in fs, textures in ts -- and boneidexweights in bs, bones holds bone raw data struct WOW2_Submesh ( id,ofsvert,nverts,oftri,tris,unknown1,unknown2, unknown3,unknown4,n3floats1,n3floats2, vs,fs,ts,bs,bones ) struct WOW2_Texture ( flags,submesh1,submesh2,color,texpass,texunit,unknown1, lookupindex,texunit2,lightemitt ) struct WOW2_Texturefile ( -- type: --0 Texture given in filename --1 Body + clothes --2 Cape --6 Hair, beard --8 Tauren fur --11 Skin for creatures type,flags,namelen,ofsname ) fn echo msg = ( format "%\n" (msg) to:listener ) fn ReadFixedString bstream fixedLen= ( local str = "" for i = 1 to fixedLen do ( str += bit.intAsChar (ReadByte bstream #unsigned) ) str ) fn SkipBytes bstream count= ( local unknown case count of ( 2: unknown = ReadShort bstream #unsigned 4: unknown = ReadLong bstream #unsigned default: ( for i = 1 to count do ( unknown = ReadByte bstream #unsigned ) ) ) ) fn LongToString num= ( local str = "" for i = 1 to 4 do ( str += bit.intAsChar (bit.and num 0xff) -- num = bit.shift num -8 num /= 256 ) str ) fn Short2Float s = ( if s>0 then return s-32767.0 else return s+32767.0 ) fn WOW2_Open fname = ( bstream = fopen fname "rb" head = WOW2_Header () ) fn WOW2_Close = ( step = "Close" fclose bstream ) fn WOW2_Read_Header = ( if head == undefined or bstream == undefined then echo "Nothing to read" format "reading\n" to:listener step = "Read header" head.magic = ReadLong bstream #unsigned echo ("4cc: "+(LongToString head.magic)) head.version = ReadLong bstream #unsigned echo ("Version: "+(head.version as string)) if(head.version < 200 or head.version > 260) then messagebox ("Version missmatch script working is not guaranteed for models of version "+ head.version as string) title:"Warning" head.namelen = ReadLong bstream #unsigned --echo ("Name len:"+ (head.namelen as string)) head.ofsname = ReadLong bstream #unsigned --echo ("Name offs:"+ head.ofsname as string) head.un1 = ReadLong bstream #unsigned --echo (LongToString head.un1) --echo ("before glob ftell: "+(ftell bstream) as string) head.nGlobalSequences = ReadLong bstream #unsigned --echo ("Global seq:"+head.nGlobalSequences as string) head.ofsGlobalSequences = ReadLong bstream #unsigned --echo ("Global seq ofs:"+ head.ofsGlobalSequences as string) --echo ("before anims: "+(ftell bstream) as string) head.nAnimations = ReadLong bstream #unsigned --echo ("Anims :"+ head.nAnimations as string) head.ofsAnimations = ReadLong bstream #unsigned --echo ("Anims ofs:" + head.ofsAnimations as string) head.nC = ReadLong bstream #unsigned --echo (LongToString head.nC) head.ofsC = ReadLong bstream #unsigned --echo ("ofsC:" + head.ofsC as string) head.nD = ReadLong bstream #unsigned --echo (LongToString head.nD) head.ofsD = ReadLong bstream #unsigned --echo ("ofsD:" + head.ofsD as string) head.nBones = ReadLong bstream --echo ("Bones:"+head.nBones as string) head.ofsBones = ReadLong bstream #unsigned --echo ("Bones ofs:"+head.ofsBones as string) head.nF = ReadLong bstream #unsigned --echo ("nF:" + head.nF as string) head.ofsF = ReadLong bstream #unsigned --echo ("ofsF:" + head.ofsF as string) --echo ("before verts ftell: "+(ftell bstream) as string) head.nVertices = ReadLong bstream #unsigned --echo ("Vertices:"+head.nVertices as string) head.ofsVertices = ReadLong bstream #unsigned --echo ("Vertices of:"+head.ofsVertices as string) head.nViews = ReadLong bstream #unsigned --echo ("Views:"+head.nViews as string) head.ofsViews = ReadLong bstream #unsigned --echo ("ofsViews:"+head.ofsViews as string) head.nG = ReadLong bstream #unsigned head.ofsG = ReadLong bstream #unsigned --echo ("ofsG:"+head.ofsG as string) head.nTextures = ReadLong bstream #unsigned --echo ("Textures:"+head.nTextures as string) head.ofsTextures = ReadLong bstream #unsigned --echo ("ofsTex:"+head.ofsTextures as string) head.nH = ReadLong bstream #unsigned head.ofsH = ReadLong bstream #unsigned --echo ("ofsH:"+head.ofsH as string) head.nI = ReadLong bstream #unsigned head.ofsI = ReadLong bstream #unsigned --echo ("ofsI:"+head.ofsI as string) head.nJ = ReadLong bstream #unsigned head.ofsJ = ReadLong bstream #unsigned --echo ("ofsJ:"+head.ofsJ as string) head.nK = ReadLong bstream #unsigned head.ofsK = ReadLong bstream #unsigned --echo ("ofsK:"+head.ofsK as string) head.nX = ReadLong bstream #unsigned head.ofsX = ReadLong bstream #unsigned --echo ("ofsX:"+head.ofsX as string) head.nBoneGroups = ReadLong bstream #unsigned head.ofsBoneGroups = ReadLong bstream #unsigned echo ("BoneGroups:"+head.nBoneGroups as string) head.nTexLookup = ReadLong bstream #unsigned --echo ("TexLookup:"+head.nTexLookup as string) head.ofsTexLookup = ReadLong bstream #unsigned --echo ("ofsTexlkup:"+head.ofsTexLookup as string) head.nL = ReadLong bstream #unsigned head.ofsL = ReadLong bstream #unsigned --echo ("ofsL:"+head.ofsL as string) head.nM = ReadLong bstream #unsigned head.ofsM = ReadLong bstream #unsigned --echo ("ofsM:"+head.ofsM as string) head.nN = ReadLong bstream #unsigned head.ofsN = ReadLong bstream #unsigned ---echo ("ofsN:"+head.ofsN as string) head.n14floats = undefined for i = 1 to 14 do ( undef = ReadFloat bstream ) head.nBoundingTriangles = ReadLong bstream #unsigned head.ofsBoundingTriangles = ReadLong bstream #unsigned --echo ("ofsBoundTri:"+head.ofsBoundingTriangles as string) head.nBoundingVertices = ReadLong bstream #unsigned head.ofsBoundingVertices = ReadLong bstream #unsigned --echo ("ofsBoundingVerts:"+head.ofsBoundingVertices as string) head.nBoundingNormals = ReadLong bstream #unsigned head.ofsBoundingNormals = ReadLong bstream #unsigned --echo ("ofsBoundNormals:"+head.ofsBoundingNormals as string) head.nO = ReadLong bstream #unsigned head.ofsO = ReadLong bstream #unsigned --echo ("ofsO:"+head.ofsO as string) head.nP = ReadLong bstream #unsigned head.ofsP = ReadLong bstream #unsigned --echo ("ofsP:"+head.ofsP as string) head.nQ = ReadLong bstream #unsigned head.ofsQ = ReadLong bstream #unsigned --echo ("ofsQ:"+head.ofsQ as string) head.nR = ReadLong bstream #unsigned head.ofsR = ReadLong bstream #unsigned --echo ("ofsR:"+head.ofsR as string) head.nS = ReadLong bstream #unsigned head.ofsS = ReadLong bstream #unsigned --echo ("ofsS:"+head.ofsS as string) head.nT = ReadLong bstream #unsigned head.ofsT = ReadLong bstream #unsigned --echo ("ofsT:"+head.ofsT as string) head.nU = ReadLong bstream #unsigned head.ofsU = ReadLong bstream #unsigned --echo ("ofsU:"+head.ofsU as string) head.nV = ReadLong bstream #unsigned head.ofsV = ReadLong bstream #unsigned --echo ("ofsV:"+head.ofsV as string) echo "---- Header finished ----" ok ) fn WOW2_Read_Name = ( step = "Read Name" if (fseek bstream head.ofsname #seek_set ) then ( name_read = (ReadFixedString bstream head.namelen) echo name_read ) else echo "unable to read name" ) fn WOW2_Read_Verts = ( step = "Read Verts" if (fseek bstream head.ofsVertices #seek_set ) then ( step = "Read verts prep" for i=1 to head.nVertices do ( local vert = WOW2_Vertex () local v4 = [0.0,0.0,0.0] local v3 = [0.0,0.0,0.0] local v2 = [0.0,0.0,0.0] local v1 = [0.0,0.0] v4.x = ReadFloat bstream v4.y = ReadFloat bstream v4.z = ReadFloat bstream vert.pos = v4 vert.bw1 = ReadByte bstream #unsigned vert.bw2 = ReadByte bstream #unsigned vert.bw3 = ReadByte bstream #unsigned vert.bw4 = ReadByte bstream #unsigned vert.bi1 = ReadByte bstream #unsigned vert.bi2 = ReadByte bstream #unsigned vert.bi3 = ReadByte bstream #unsigned vert.bi4 = ReadByte bstream #unsigned v3.x = ReadFloat bstream v3.y = ReadFloat bstream v3.z = ReadFloat bstream vert.normal = v3 v2.x = ReadFloat bstream v2.y = ReadFloat bstream v2.z = 0.0 --is empty (0.0) vert.uv = v2 v1.x = ReadFloat bstream v1.y = ReadFloat bstream vert.n2floats = v1 append verts_read vert ) -- echo ("Verts read: " + verts_read.count as string ) ) else echo "unable to read vertices" ) fn WOW2_Read_Views = ( step = "Read Views" if (fseek bstream head.ofsViews #seek_set ) then ( for i=1 to head.nViews do ( local view = WOW2_Views () view.nindex = ReadLong bstream #unsigned view.ofsnindex = ReadLong bstream #unsigned view.ntris = ReadLong bstream #unsigned view.ofsntris = ReadLong bstream #unsigned view.nverts = ReadLong bstream #unsigned view.ofsnverts = ReadLong bstream #unsigned view.nsubmesh = ReadLong bstream #unsigned view.ofsnsubmesh = ReadLong bstream #unsigned view.ntextures = ReadLong bstream #unsigned view.ofsntextures = ReadLong bstream #unsigned view.unknown1 = ReadLong bstream #unsigned append views_read view step = "Read Views Mod 3" if((mod (view.ntris) 3) != 0.0 )then echo (" View["+i as string+"].ntris is not a multiple of 3!") if true then --i == 1 then ( echo ("\nView nind : "+view.nindex as string) echo ("View ofsind : "+view.ofsnindex as string) echo ("View ntris : "+view.ntris as string) echo ("View ofsntris : "+view.ofsntris as string) echo ("View nverts: "+view.nverts as string) echo ("View ofsnverts : "+view.ofsnverts as string) echo ("View nsubm : "+view.nsubmesh as string) echo ("View ntex : "+view.ntextures as string) ) ) ) else echo "unable to read views" step = "Read View index lists" --load tri and vert index lists for i=1 to views_read.count do ( local ind = #() local tri = #() step = "Read View index" if (fseek bstream (views_read[i].ofsnindex) #seek_set ) then ( for j = 1 to views_read[i].nindex do ( local x = ReadShort bstream #unsigned append ind x ) views_read[i].ind = ind ) else echo "unable to read view indices" step = "Read View faces" if (fseek bstream views_read[i].ofsntris #seek_set ) then ( for j= 1 to views_read[i].ntris do ( local x = ReadShort bstream #unsigned append tri x ) views_read[i].tri = tri ) else echo "unable to read view faces" ) ) /* fn WOW2_Read_Bone_Groups = ( --nBoneGroups,ofsBoneGroups bonegroups = #() --echo ("bonegroups:"+head.nBoneGroups as string) if (fseek bstream head.ofsBoneGroups #seek_set ) then ( for i = 1 to head.nBoneGroups do ( local id = (ReadShort bstream) --echo ("bonegroupID:"+id as string) append bonegroups id ) ) return bonegroups ) */ fn WOW2_Create_Bones bonearr = ( step = "Bone creation" -- previous bone must have been created for i = 1 to bonearr.count do ( Dummy position:(bonearr[i].pivot) isSelected:on name:(bonearr[i].maxname) $.boxsize = [0.05,0.05,0.05] --$.pos.controller = TCB_position () $.rotation.controller = Local_Euler_XYZ () --$.scale.controller = TCB_scale () if (bonearr[i].parentbone >= 0) then ( $.parent = getNodeByName \ (bonearr[(bonearr[i].parentbone + 1)].maxname) \ exact:true -- echo ($.parent as string) ) ) ) -- read bone animation data frames -- bone arrays should be already filled -- @param filled WOW2_Bones array -- @TODO finish this function fn WOW2_CreateBoneScaleAnim ba = ( --echo(ba.maxname) if ba.scale.frames > 0 then ( step = "Framesoffset reading" if (fseek bstream ba.scale.framesofs #seek_set ) then ( local t = #() local maxx = 0 local x = 0 currobj = getNodeByName (ba.maxname) exact:true step = "Reading Translation frames" for j = 1 to ba.scale.frames do ( append t (ReadLong bstream ) if t[j] > maxx then maxx = t[j] ) step = "Dataoffset reading" if (fseek bstream ba.scale.dataofs #seek_set ) then ( --echo ("max Scale Anim ="+maxx as string) if maxx > frameEnd then frameEnd = maxx step = "Reading Scale data" animationRange = interval 10 maxx with animate on ( for j = 1 to ba.scale.data do ( --step = "1" local v3 = [0.0,0.0,0.0] v3.x = (ReadFloat bstream ) v3.y = (ReadFloat bstream ) v3.z = (ReadFloat bstream ) --step = "2" if( j > 1 ) then -- let him to create start keys himself ( addNewKey currobj.scale.controller t[j] currobj.scale.controller.keys[currobj.scale.controller.keys.count].value = currobj.scale.controller.keys[1].value ) in coordsys local at time (t[j]) currobj.scale = v3 ) ) ) else echo "Failed to read bstream start for bone scale frames" ) else echo "Failed to read bstream start for bone scale data" ) ) -- read bone animation data frames -- bone arrays should be already filled -- @param filled WOW2_Bones array -- @TODO finish this function fn WOW2_CreateBoneTransAnim ba = ( if ba.trans.frames > 0 then ( step = "Framesoffset reading" if (fseek bstream ba.trans.framesofs #seek_set ) then ( local t = #() local maxx = 0 local x = 0 currobj = getNodeByName (ba.maxname) exact:true step = "Reading Translation frames" for j = 1 to ba.trans.frames do ( append t (ReadLong bstream ) if t[j] > maxx then maxx = t[j] ) step = "Dataoffset reading" if (fseek bstream ba.trans.dataofs #seek_set ) then ( --echo ("max Translate Anim ="+maxx as string) if maxx > frameEnd then frameEnd = maxx step = "Reading Translation data" animationRange = interval 10 maxx with animate on ( for j = 1 to ba.trans.data do ( --step = "1" local v3 = [0.0,0.0,0.0] v3.x = (ReadFloat bstream ) v3.y = (ReadFloat bstream ) v3.z = (ReadFloat bstream ) --step = "2" if( j > 1 ) then ( addNewKey currobj.pos.controller.X_position.controller t[j] addNewKey currobj.pos.controller.Y_position.controller t[j] addNewKey currobj.pos.controller.Z_position.controller t[j] currobj.pos.controller.X_position.keys[currobj.pos.controller.X_position.keys.count].value = currobj.pos.controller.X_position.keys[1].value currobj.pos.controller.Y_position.keys[currobj.pos.controller.Y_position.keys.count].value = currobj.pos.controller.Y_position.keys[1].value currobj.pos.controller.Z_position.keys[currobj.pos.controller.Z_position.keys.count].value = currobj.pos.controller.Z_position.keys[1].value ) in coordsys local at time (t[j]) currobj.pos = v3 ) ) ) else echo "Failed to read bstream start for bone translation frames" ) else echo "Failed to read bstream start for bone translation data" ) ) -- read bone animation data frames -- bone arrays should be already filled -- @param filled WOW2_Bones array -- @TODO finish this function fn WOW2_CreateBoneRotateAnim ba = ( if ba.rot.frames > 0 then ( step = "Framesoffset reading" if (fseek bstream ba.rot.framesofs #seek_set ) then ( local t = #() local maxx = 0 local x = 0 currobj = getNodeByName (ba.maxname) exact:true step = "Reading Rotation frames" for j = 1 to ba.rot.frames do ( append t (ReadLong bstream ) if t[j] > maxx then maxx = t[j] ) step = "Dataoffset reading" if (fseek bstream ba.rot.dataofs #seek_set ) then ( --echo ("max Rotate Anim ="+maxx as string) if maxx > frameEnd then frameEnd = maxx step = "Reading Rotation data" animationRange = interval 10 maxx with animate on ( for j = 1 to ba.rot.data do ( step = "1" local v3 = [0.0,0.0,0.0] local deg = 0 local q = quat deg v3 q.x = Short2Float(ReadShort bstream)--(ReadFloat bstream ) q.y = Short2Float(ReadShort bstream)--(ReadFloat bstream ) q.z = Short2Float(ReadShort bstream)--(ReadFloat bstream ) q.w = Short2Float(ReadShort bstream)--(ReadFloat bstream ) step = "2" local b = (quatToEuler q) if b.x > 360 or b.y > 360 or b.z > 360 then echo ("oversized:"+q as string + " = "+ (quatToEuler q) as string) if( j > 1 ) then ( addNewKey currobj.rotation.controller.Local_X_Rotation.controller t[j] addNewKey currobj.rotation.controller.Local_Y_Rotation.controller t[j] addNewKey currobj.rotation.controller.Local_Z_Rotation.controller t[j] currobj.rotation.controller.local_x_rotation.keys[currobj.rotation.controller.local_x_rotation.keys.count].value = currobj.rotation.controller.local_x_rotation.keys[1].value currobj.rotation.controller.local_y_rotation.keys[currobj.rotation.controller.local_y_rotation.keys.count].value = currobj.rotation.controller.local_Y_rotation.keys[1].value currobj.rotation.controller.local_z_rotation.keys[currobj.rotation.controller.local_z_rotation.keys.count].value = currobj.rotation.controller.local_Z_rotation.keys[1].value ) in coordsys local at time (t[j]) currobj.rotation = q ) ) --echo "-----------#########------------------" ) else echo "Failed to read bstream start for bone rotation frames" ) else echo "Failed to read bstream start for bone rotation data" ) ) fn WOW2_Create_BoneAnimations ba = ( echo "Trying create Bone Animations" for i = 1 to ba.count do ( step = "Compare of Data and Frame counts" if ba[i].trans.frames != ba[i].trans.data then echo ("Translate frames not even on bone #" + i as string) WOW2_CreateBoneTransAnim (ba[i]) if ba[i].rot.frames != ba[i].rot.data then echo ("Rotate frames not even on bone #" + i as string) WOW2_CreateBoneRotateAnim (ba[i]) if ba[i].scale.frames != ba[i].scale.data then echo ("Scale frames not even on bone #" + i as string) -- if ba[i].scale.frames > 0 then -- echo ("bone scaling found on bone "+ ba[i].maxname) WOW2_CreateBoneScaleAnim (ba[i]) animationRange = interval 0 frameEnd ) echo "Trying create Bone Animations finished" ) -- read bone animation information -- ofsets and types for the animations -- identical for scale, rotate, translate -- the final data is found starting at dataofs -- expects the bstream pointer to be at the correct position -- @see WOW2_ReadBones -- @return A filled WOW2_Anim structure fn WOW2_Read_BoneAnim = ( local a = WOW2_Anim () a.type = (ReadShort bstream ) a.flags = (ReadShort bstream ) a.linetypes = (ReadLong bstream ) a.linetypeofs = (ReadLong bstream ) a.frames = (ReadLong bstream ) a.framesofs = (ReadLong bstream ) a.data = (ReadLong bstream ) a.dataofs = (ReadLong bstream ) return a ) fn WOW2_Read_Bones = ( step = "Read Views" if ( head.nBones <= 0 ) then -- static models do not have bones ( echo "--model without bones !" return true ) local bonearr = #() if (fseek bstream head.ofsBones #seek_set ) then ( for i = 1 to head.nBones do ( step = ("Reading Bone #"+ i as string) local bone = WOW2_Bones () local piv = [0.0,0.0,0.0] bone.geosetanim = (ReadLong bstream ) bone.flags = (ReadLong bstream ) bone.parentbone = (ReadShort bstream ) -- -1 or bone # (0 is first) bone.unknown1 = (ReadShort bstream ) --bone.unknown2 = (ReadLong bstream) bone.geoset = (ReadLong bstream ) step = ("Reading Bone #"+ i as string + " anims") bone.trans = WOW2_Read_BoneAnim () bone.rot = WOW2_Read_BoneAnim () bone.scale = WOW2_Read_BoneAnim () piv.x = (ReadFloat bstream ) piv.y = (ReadFloat bstream ) piv.z = (ReadFloat bstream ) bone.pivot = piv bone.maxname = ("bone_"+ i as string + "_" + bone.flags as string) step = ("Appending Bone #"+ i as string) append bonearr bone ) ) else echo "unable to read bones" join bones_read bonearr -- add bones to global bones array --WOW2_Read_Bone_Groups () -- not needed at the moment WOW2_Create_Bones bonearr return bonearr ) fn WOW2_Create_Faces sm view = ( step = "Init" sm.fs = #() -- faces sm.vs = #() -- verts sm.ts = #() -- uvs sm.bs = #() -- boneindexweight per vertex --step = "Create Faces" sm.bones = #() -- bones --echo ("t ofs "+(sm.oftri as string)+" tot tris: "+(sm.tris as string)) --if (fseek bstream (view.ofsntris + sm.oftri) #seek_set ) then --( --local done = 0 local up = undefined try( up = sm.tris as integer -1 --echo ("/3 check :"+((up+1)/3) as string + " mod "+(mod (up+1) 3)as string) if((mod (up+1) 3) != 0.0 )then ( echo ("#ERROR sm.tris not a multiple of 3:"+(up as string)) return 0 ) )catch ( echo ("#ERROR sm.tris is strange:"+(up as string)) return 0 ) -- else -- echo "#INFO sm.tris check passed!" try( local ofs = sm.oftri as integer --echo ("oftri = "+ ofs as string) for i=1 to (up) by 3 do ( try ( /* for (size_t k=0, b=p.indexStart; k