using UnityEngine; using System.Collections.Generic; using System.IO; using System.Linq; using UnityEditor; using System; namespace uSrcTools { [System.Serializable] public class SourceStudioModel// : MonoBehaviour { public string curModelName; public studiohdr_t mdlHeader; public vvdheader vvdHeader; public vtxHeader vtxHeader; public int lodLevel=0; int skin; int numSkinRefs; public int submeshCount=0; public Material tempMat; public int vertCount; public Vector3[] vertArray; public Vector3[] Normals; public Vector2[] UV; public BoneWeight[] boneWeights; public int[] indexArray; public Dictionary trisArrays; public studiobone_t[] mdlBones; public studiobodypart[] mdlBodyParts; public vtxBodypartHeader[] vtxBodyParts; public studiotexture_t[] mdlTextures; public string[] mdlTexturePaths; public short[] mdlSkinFamilies; public Transform[] Bones; Mesh modelMesh; bool used; public bool loaded=false; public bool drawArmature=false; Material[] TempMats; public SourceStudioModel Load(string path, Func openFileCallback) { curModelName = path; //studiobodypart[] mdlBodyParts; if (!ParseMdl (path, openFileCallback)) { return null; } LoadSkin (0); //public int vertCount; //Vector3[] vertArray; //Vector3[] Normals; //Vector2[] UV; //int[] indexArray; ParseVvd (path, openFileCallback); ParseVtx (path, openFileCallback); loaded = true; return this; } /* public void GetInstance(GameObject go, bool skinned) { BuildMeshObject (curModelName, go,skinned); } public void GetInstance(GameObject go) { BuildMeshObject (curModelName, go,false); }*/ public void GetInstance(GameObject go, bool skinned,int bp) { BuildMeshObject (curModelName, go, skinned,bp); } public void OnDrawGizmos() { /*for (int i=0; i=0) { bone.transform.SetParent(Bones[mdlBones[i].parent]); } else { bone.transform.SetParent(go.transform); } Vector3 temp=Vector3.zero; //if(i==0) temp=new Vector3(mdlBones[i].pos.x,mdlBones[i].pos.z,mdlBones[i].pos.y); //else // temp=new Vector3(mdlBones[i].pos.x,mdlBones[i].pos.y,-mdlBones[i].pos.z); bone.transform.localPosition=temp * SourceImportConfig.WorldScale; Vector3 rot=new Vector3(-mdlBones[i].rot.x*Mathf.Rad2Deg,-mdlBones[i].rot.z*Mathf.Rad2Deg,-mdlBones[i].rot.y*Mathf.Rad2Deg); bone.transform.localEulerAngles=rot; Bones[i]=bone.transform; } if (skinned) { go.AddComponent ().mesh = modelMesh; SkinnedMeshRenderer smr = go.AddComponent (); smr.material = tempMat; smr.sharedMesh = modelMesh; smr.bones=Bones; smr.rootBone=Bones[0]; smr.updateWhenOffscreen=true; } else { go.AddComponent ().mesh = modelMesh; go.AddComponent ().material = tempMat; } return; } //========================================================== Bones = new Transform[mdlHeader.bonesnum]; for (int i=0; i=0) { bone.transform.SetParent(Bones[mdlBones[i].parent]); } else { bone.transform.SetParent(go.transform); } Vector3 temp=Vector3.zero; //if(i==0) temp=new Vector3(mdlBones[i].pos.x,mdlBones[i].pos.z,mdlBones[i].pos.y); //else // temp=new Vector3(mdlBones[i].pos.x,mdlBones[i].pos.y,-mdlBones[i].pos.z); bone.transform.localPosition=temp* SourceImportConfig.WorldScale; Vector3 rot=new Vector3(-mdlBones[i].rot.x*Mathf.Rad2Deg,-mdlBones[i].rot.z*Mathf.Rad2Deg,-mdlBones[i].rot.y*Mathf.Rad2Deg); bone.transform.localEulerAngles=rot; Bones[i]=bone.transform; } //============================================================================================ string materialName=""; /*if(mdlTexturePaths.Length==1) { materialName += mdlTexturePaths[0]; materialName += mdlTextures[mdlBodyParts[0].models[0].meshes[0].material].textureName; } else { string path = ResourceManager.GetPath ("materials/"+mdlTexturePaths[0] +mdlTextures[mdlBodyParts[0].models[0].meshes[0].material].textureName+".vmt"); if(path==null) { Debug.Log ("Try second path"); path = ResourceManager.GetPath ("materials/"+mdlTexturePaths[1] +mdlTextures[mdlBodyParts[0].models[0].meshes[0].material].textureName+".vmt"); if(path!=null) { materialName=mdlTexturePaths[1] +mdlTextures[mdlBodyParts[0].models[0].meshes[0].material].textureName; } } } if (uSrcSettings.Inst.textures) tempMat = ResourceManager.Inst.GetMaterial (materialName); else tempMat = Test.Inst.testMaterial;*/ //TODO: restore mat system var matPath = AssetDatabase.FindAssets("DefaultBspMaterial"); var assetPath = AssetDatabase.GUIDToAssetPath(matPath[0]); tempMat = AssetDatabase.LoadAssetAtPath(assetPath); //============================================================================================ //GameObject testMesh = new GameObject (curModelName); //testMesh.transform.position = position; modelMesh = new Mesh (); modelMesh.name = curModelName; modelMesh.vertices = vertArray; modelMesh.normals = Normals; modelMesh.uv = UV; modelMesh.boneWeights = boneWeights; //====================================================== Matrix4x4[] bindPoses = new Matrix4x4[Bones.Length]; for (int i = 0; i < bindPoses.Length; i++) { //Bones[i].localPosition = Vector3.zero; bindPoses[i] = Bones[i].worldToLocalMatrix * go.transform.localToWorldMatrix; } modelMesh.bindposes = bindPoses; //==================================================================== //Debug.Log (indexArray.Length+" indices"); modelMesh.triangles = indexArray; /* int numMeshes = vtxBodyParts [0].models [0].lods [lodLevel].numMeshes; modelMesh.subMeshCount = numMeshes; int indexCount = 0; int indexOffset = 0; for(int i=0; i ().mesh = modelMesh; SkinnedMeshRenderer smr = go.AddComponent (); smr.material = tempMat; smr.sharedMesh = modelMesh; smr.bones=Bones; smr.rootBone=Bones[0]; smr.updateWhenOffscreen=true; } else { go.AddComponent ().mesh = modelMesh; go.AddComponent ().material = tempMat; } for (int i=0; i ().mesh = mesh; //meshObj.AddComponent ().material = tempMat; } } }*/ used = true; } void BuildMeshObject(string modelName, GameObject go, bool skinned,int bp) { if (!loaded) { Debug.LogWarning("Can't get Instance of model "+modelName+" because it's not loaded"); return; } if(skinned) { Bones = new Transform[mdlHeader.bonesnum]; for (int i=0; i=0) { bone.transform.SetParent(Bones[mdlBones[i].parent]); } else { bone.transform.SetParent(go.transform); } Vector3 temp=Vector3.zero; //if(i==0) temp=new Vector3(mdlBones[i].pos.x,mdlBones[i].pos.z,mdlBones[i].pos.y); //else // temp=new Vector3(mdlBones[i].pos.x,mdlBones[i].pos.y,-mdlBones[i].pos.z); bone.transform.localPosition=temp*SourceImportConfig.WorldScale; Vector3 rot=new Vector3(-mdlBones[i].rot.x*Mathf.Rad2Deg,-mdlBones[i].rot.z*Mathf.Rad2Deg,-mdlBones[i].rot.y*Mathf.Rad2Deg); bone.transform.localEulerAngles=rot; Bones[i]=bone.transform; } } if(!used) { modelMesh = new Mesh (); modelMesh.name = curModelName; modelMesh.vertices = vertArray; if(modelMesh.vertices.Length==0) Debug.LogWarning ("Error with model "+modelName); modelMesh.normals = Normals; modelMesh.uv = UV; modelMesh.boneWeights = boneWeights; modelMesh.subMeshCount = submeshCount; //Debug.Log ("submeshCount " + submeshCount); //Debug.Log ("indexCount "+indexArray.Length); //Debug.Log ("Bodypart count "+vtxBodyParts.Length); int curmeshId=0; int curIndexOffset = 0; if(TempMats==null) TempMats = new Material[submeshCount]; //for(int bpId=0; bpId(assetPath); TempMats[curmeshId] = tempMat; } for(int stripGroupId=0; stripGroupId(); if(mf == null) { mf = go.AddComponent(); } mf.sharedMesh = modelMesh; MeshRenderer mr = go.GetComponent (); if(mr == null) { mr = go.AddComponent(); } mr.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.TwoSided; //Making model shadows two-sided for better quality. modelMesh.RecalculateBounds (); mr.materials = TempMats; mr.lightmapIndex = 255; used = true; } void LoadSkin(int skinId) { skin = skinId; int skinTableOffset=numSkinRefs * skinId; for(int i=0; i openFileCallback) { BinaryReader BR = new BinaryReader (openFileCallback(name)); //studiohdr_t Header = ReadHeader (BR); mdlHeader = ReadHeader (BR); if (new string(mdlHeader.id) != "IDST") { Debug.LogWarning ("Header id is not IDST"); BR.BaseStream.Close (); return false; } mdlBones = ReadStudioBones (BR,mdlHeader.boneoffs,mdlHeader.bonesnum); mdlTextures = ReadStudioTextures(BR,mdlHeader.textureoffs,mdlHeader.texturenum); mdlTexturePaths = ReadTexturePaths (BR, mdlHeader.texturediroffs, mdlHeader.texturedirnum); numSkinRefs = mdlHeader.skinrefnum; mdlSkinFamilies = ReadSkinFamilies (BR,mdlHeader.skinfamilyoffs, mdlHeader.skinfamilynum,mdlHeader.skinrefnum); mdlBodyParts = ReadMdlBodyParts (BR, mdlHeader.bodypartoffs, mdlHeader.bodypartnum); //setRootLOD (mdlHeader, lodLevel); BR.BaseStream.Dispose (); return true; } void setRootLOD(studiohdr_t hdr, int lod) { if (hdr.numAllowedRootLods > 0 && lod >= hdr.numAllowedRootLods) { lod=hdr.numAllowedRootLods-1; } int vertexOffset=0; for (int bpId=0; bpId openFileCallback) { path = path.Replace (".mdl", ".vvd"); //_vertArray = null; //_Normals = null; //_UV = null; BinaryReader BR = new BinaryReader (openFileCallback(path)); /*vvdheader */vvdHeader = ReadVvdHeader (BR); //VvdHeader = header; vertexFileFixup[] fixupTable = null; if (vvdHeader.numFixup > 0) { //Debug.Log ("VVD file have "+vvdHeader.numFixup +" fixups"); BR.BaseStream.Seek(vvdHeader.fixupTableStart, SeekOrigin.Begin); fixupTable=new vertexFileFixup[vvdHeader.numFixup]; for (int i=0; i 0) { vertCount = vvdHeader.numLODVertexes [lodLevel]; //int vertCount = vvdHeader.numLODVertexes [0]; //_vertArray = ParseFixup (BR, vvdHeader.fixupTableStart, vvdHeader.numFixup, vvdHeader.vertexDataStart, vvdHeader.tangentDataStart, // out _Normals, out _UV, vertCount); ReadVvdVertexes(BR,vvdHeader.vertexDataStart,vertCount,fixupTable); // Debug.Log("VertCount "+vertCount+" vertArrayLength "+vertArray.Length); } else { Debug.LogWarning("VVD file numLODs is 0"); } BR.BaseStream.Dispose (); } vvdheader ReadVvdHeader(BinaryReader br) { vvdheader hdr = new vvdheader (); hdr.id = br.ReadChars(4); hdr.version = br.ReadInt32 (); hdr.checksum = br.ReadInt32 (); hdr.numLODs = br.ReadInt32 (); // Debug.Log ("VDD header numLODs is "+hdr.numLODs); hdr.numLODVertexes = new int[]{ br.ReadInt32 (),br.ReadInt32 (),br.ReadInt32 (),br.ReadInt32 (), br.ReadInt32 (),br.ReadInt32 (),br.ReadInt32 (),br.ReadInt32 ()}; hdr.numFixup = br.ReadInt32 (); hdr.fixupTableStart = br.ReadInt32 (); hdr.vertexDataStart = br.ReadInt32 (); hdr.tangentDataStart = br.ReadInt32 (); return hdr; } void ReadVvdVertexes(BinaryReader br, int vertOffs, int vertCount, vertexFileFixup[] fixupTable) { if (fixupTable == null) { boneWeights = new BoneWeight[vertCount]; vertArray = new Vector3[vertCount]; Normals = new Vector3[vertCount]; UV = new Vector2[vertCount]; br.BaseStream.Seek (vertOffs, SeekOrigin.Begin); for (int i=0; i VertexView = new List(); List NormalView = new List(); List UVView = new List(); List _boneWeights = new List (); //int target=0; //int vertexArrayOffset=0; for (int i=0; i VertexView = new List(); List NormalView = new List(); List UVView = new List(); List _boneWeights = new List (); _Normals = null;//new Vector3[vertCount]; _UV = null;//new Vector2[vertCount]; int vertexArrayOffset=0; vertexFileFixup[] fixupTable; if (fixupCount == 0) { BR.BaseStream.Seek(VertexOffs, SeekOrigin.Begin); for (int i=0; i openFileCallback) { path = path.Replace (".mdl", ".dx90.vtx"); //_indexArray = null; BinaryReader BR = new BinaryReader (openFileCallback(path)); /*vtxheader*/ vtxHeader = ReadVtxHeader (BR); //VtxHeader = header; if (vtxHeader.numLODs > 0) { /*vtxBodypartHeader[]*/ vtxBodyParts = ReadVtxBodyParts (BR, vtxHeader.bodyPartOffset, vtxHeader.numBobyParts); indexArray = BuildIndices (vtxBodyParts); } BR.BaseStream.Dispose (); } vtxHeader ReadVtxHeader(BinaryReader BR) { vtxHeader hdr = new vtxHeader (); hdr.version = BR.ReadInt32 (); hdr.vertCacheSize=BR.ReadInt32 (); hdr.maxBonePerStrip=BR.ReadInt16 (); hdr.maxBonePerTri=BR.ReadInt16 (); hdr.maxBonePerVert=BR.ReadInt32 (); hdr.checksum = BR.ReadInt32 (); hdr.numLODs = BR.ReadInt32 (); hdr.materialReplacementListOffset=BR.ReadInt32 (); hdr.numBobyParts=BR.ReadInt32 (); hdr.bodyPartOffset=BR.ReadInt32 (); return hdr; } vtxBodypartHeader[] ReadVtxBodyParts (BinaryReader br, int offs,int count) { vtxBodypartHeader[] bp = new vtxBodypartHeader[count]; for (int i=0; i0) { bp[i].models = ReadVtxModels(br, offs+(i*8), bp[i]); } else Debug.LogWarning("VTX Body part "+ i+" models count is 0"); } return bp; } vtxModelHeader[] ReadVtxModels(BinaryReader br, int offset, vtxBodypartHeader bodypart) { vtxModelHeader[] mh = new vtxModelHeader[bodypart.numModels]; for (int i=0; i0) { mh[i].lods = ReadVtxModelLods(br, bodypart.modelsOffset + offset + (i*8), mh[i],i); } else Debug.LogWarning("VTX model "+ i+" LODs count is 0"); } return mh; } vtxModelLODheader[] ReadVtxModelLods(BinaryReader br, int offset, vtxModelHeader model,int modelIndex) { vtxModelLODheader[] mlods = new vtxModelLODheader[model.numLODs]; for (int i=0; i0) { mlods[i].meshes = ReadVtxMeshes(br, model.LODOffset+ offset + (i*12), mlods[i]); } else Debug.LogWarning("VTX model "+modelIndex+" lod "+ i+" mesh count is 0"); } return mlods; } vtxMeshHeader[] ReadVtxMeshes(BinaryReader br, int offset, vtxModelLODheader lod) { vtxMeshHeader[] ms = new vtxMeshHeader[lod.numMeshes]; for (int i=0; i0) { ms[i].stripGroups = ReadVtxStripGroups(br, lod.meshOffset+ offset + (i*9), ms[i]); } //else // Debug.LogWarning("VTX mesh "+ i+" numStripGroups is 0"); } return ms; } vtxStripGroupHeader[] ReadVtxStripGroups(BinaryReader br, int offset,vtxMeshHeader mesh) { vtxStripGroupHeader[] sg = new vtxStripGroupHeader[mesh.numStripGroups]; for (int i=0; i0) { sg[i].verts = ReadVtxVerts(br, mesh.stripGroupHeaderOffset+ offset + (i*25),sg[i]); } if(sg[i].numIndices>0) { br.BaseStream.Seek (mesh.stripGroupHeaderOffset + offset + (i*25)+sg[i].indexOffs,SeekOrigin.Begin); for(int j=0; j0) { sg[i].strips = ReadVtxStrips(br, mesh.stripGroupHeaderOffset+ offset + (i*25), sg[i]); } //sg[i].strips = ReadStrips(br, mesh.stripGroupHeaderOffset+ offset + (i*25), sg[i]); //sg[i].verts = ReadVtxVerts(br, mesh.stripGroupHeaderOffset+ offset + (i*25),sg[i]); //br.BaseStream.Seek (mesh.stripGroupHeaderOffset + offset + (i*25)+sg[i].indexOffs,SeekOrigin.Begin); //for(int j=0; j= vvdHeader.numLODs) lodLevel = (vvdHeader.numLODs - 1); int indexCount = IterateStripGroups (lodLevel, bodyParts[0]); // Debug.Log ("indexCount "+indexCount); int[] indices=new int[indexCount]; int indexOffset=0; submeshCount = 0; //for(int bpId=0; bpId= vvdHeader.numLODs) lodLevel = (vvdHeader.numLODs - 1); int indexCount = IterateStripGroups (lodLevel, vtxBodyPart); //Debug.Log ("indexCount "+indexCount); int[] indices=new int[indexCount]; int indexOffset=0; //studiobodypart mdlBodypart = mdlBodyParts[bpId]; for(int modelId=0; modelId0) { vtxModelLODheader lodheader=model.lods[lodID]; foreach(vtxMeshHeader mesh in lodheader.meshes) { foreach(vtxStripGroupHeader stripGroup in mesh.stripGroups) { //Debug.Log ("Strip group num indices "+stripGroup.numIndices); indices+=stripGroup.numIndices; } } } else { Debug.LogWarning ("model.lods.Length < 0 or lodID is -1"); } } return indices; } } }