1437 lines
44 KiB
C#
1437 lines
44 KiB
C#
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<int,int[]> 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<string, Stream> 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<vertArray.Length; i++)
|
||
|
|
{
|
||
|
|
Gizmos.DrawCube(vertArray[i],Vector3.one*0.2f);
|
||
|
|
}*/
|
||
|
|
if (loaded & used & drawArmature)
|
||
|
|
{
|
||
|
|
for(int i=0;i<Bones.Length;i++)
|
||
|
|
{
|
||
|
|
Gizmos.color=Color.white;
|
||
|
|
Gizmos.DrawWireCube(Bones[i].position,Vector3.one*0.02f);
|
||
|
|
if(mdlBones[i].parent!=-1)
|
||
|
|
{
|
||
|
|
Gizmos.color=Color.yellow;
|
||
|
|
Gizmos.DrawLine(Bones[i].position,Bones[mdlBones[i].parent].position);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void BuildMeshObjectOLD(string modelName, GameObject go, bool skinned)
|
||
|
|
{
|
||
|
|
if (!loaded)
|
||
|
|
{
|
||
|
|
Debug.LogWarning("Can't get Instance of model "+modelName+" because it's not loaded");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
if(used)
|
||
|
|
{
|
||
|
|
Bones = new Transform[mdlHeader.bonesnum];
|
||
|
|
for (int i=0; i<mdlHeader.bonesnum; i++)
|
||
|
|
{
|
||
|
|
GameObject bone = new GameObject(mdlBones[i].pszName);
|
||
|
|
if(mdlBones[i].parent>=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<MeshFilter> ().mesh = modelMesh;
|
||
|
|
SkinnedMeshRenderer smr = go.AddComponent<SkinnedMeshRenderer> ();
|
||
|
|
smr.material = tempMat;
|
||
|
|
smr.sharedMesh = modelMesh;
|
||
|
|
smr.bones=Bones;
|
||
|
|
smr.rootBone=Bones[0];
|
||
|
|
smr.updateWhenOffscreen=true;
|
||
|
|
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
go.AddComponent<MeshFilter> ().mesh = modelMesh;
|
||
|
|
go.AddComponent<MeshRenderer> ().material = tempMat;
|
||
|
|
}
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
//==========================================================
|
||
|
|
Bones = new Transform[mdlHeader.bonesnum];
|
||
|
|
for (int i=0; i<mdlHeader.bonesnum; i++)
|
||
|
|
{
|
||
|
|
GameObject bone = new GameObject(mdlBones[i].pszName);
|
||
|
|
if(mdlBones[i].parent>=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<Material>(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<numMeshes; i++)
|
||
|
|
{
|
||
|
|
indexOffset=indexCount;//vtxBodyParts [0].models [0].lods [lodLevel].meshes[i].stripGroups[0].strips[0].indexOffset;
|
||
|
|
indexCount = vtxBodyParts [0].models [0].lods [lodLevel].meshes[i].stripGroups[0].strips[0].numIndices;
|
||
|
|
int[] tempIndex = new int[indexCount];
|
||
|
|
System.Buffer.BlockCopy(indexArray,indexOffset*4,tempIndex,0,indexCount*4);
|
||
|
|
Debug.Log("Mesh "+i+" index count is "+indexCount+" index offset "+indexOffset);
|
||
|
|
modelMesh.SetTriangles(tempIndex, i);
|
||
|
|
}
|
||
|
|
*/
|
||
|
|
//modelMesh.subMeshCount = 1;
|
||
|
|
/*int indexCount = indexArray.Length;
|
||
|
|
|
||
|
|
int[] tempIndex = new int[indexCount];
|
||
|
|
System.Buffer.BlockCopy(indexArray,0,tempIndex,0,indexCount*4);
|
||
|
|
//modelMesh.SetTriangles(tempIndex, 0);
|
||
|
|
modelMesh.triangles = tempIndex;*/
|
||
|
|
//===================================================================
|
||
|
|
|
||
|
|
modelMesh.RecalculateBounds ();
|
||
|
|
//modelMesh.Optimize ();
|
||
|
|
|
||
|
|
if (skinned)
|
||
|
|
{
|
||
|
|
go.AddComponent<MeshFilter> ().mesh = modelMesh;
|
||
|
|
SkinnedMeshRenderer smr = go.AddComponent<SkinnedMeshRenderer> ();
|
||
|
|
smr.material = tempMat;
|
||
|
|
smr.sharedMesh = modelMesh;
|
||
|
|
smr.bones=Bones;
|
||
|
|
smr.rootBone=Bones[0];
|
||
|
|
smr.updateWhenOffscreen=true;
|
||
|
|
} else
|
||
|
|
{
|
||
|
|
go.AddComponent<MeshFilter> ().mesh = modelMesh;
|
||
|
|
go.AddComponent<MeshRenderer> ().material = tempMat;
|
||
|
|
}
|
||
|
|
|
||
|
|
for (int i=0; i<mdlHeader.bonesnum; i++)
|
||
|
|
{
|
||
|
|
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);
|
||
|
|
Bones[i].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);
|
||
|
|
Bones[i].transform.localEulerAngles=rot;
|
||
|
|
}
|
||
|
|
|
||
|
|
//tempMat = new Material (Shader.Find("Diffuse"));
|
||
|
|
|
||
|
|
/*for (int i=0; i<mdlBodyParts.Length; i++)
|
||
|
|
{
|
||
|
|
GameObject bodyPartObj=new GameObject(mdlBodyParts[i].name);
|
||
|
|
bodyPartObj.transform.SetParent(go.transform);
|
||
|
|
|
||
|
|
for (int m=0; m<mdlBodyParts[i].models.Length; m++)
|
||
|
|
{
|
||
|
|
GameObject modelObj=new GameObject(mdlBodyParts[i].models[m].name);
|
||
|
|
modelObj.transform.SetParent(bodyPartObj.transform);
|
||
|
|
|
||
|
|
for (int meshId=0; meshId<mdlBodyParts[i].models[m].meshnum; meshId++)
|
||
|
|
{
|
||
|
|
GameObject meshObj=new GameObject("Mesh "+meshId);
|
||
|
|
meshObj.transform.SetParent(modelObj.transform);
|
||
|
|
|
||
|
|
//Mesh mesh = new Mesh ();
|
||
|
|
//mesh.name = mdlBodyParts[i].models[m].name+" Mesh "+meshId;
|
||
|
|
|
||
|
|
//mesh.vertices = vertArray;
|
||
|
|
//mesh.normals = Normals;
|
||
|
|
//mesh.uv = UV;
|
||
|
|
//Debug.Log (indexArray.Length+" indices");
|
||
|
|
//mesh.triangles = indexArray;
|
||
|
|
|
||
|
|
//meshObj.AddComponent<MeshFilter> ().mesh = mesh;
|
||
|
|
//meshObj.AddComponent<MeshRenderer> ().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<mdlHeader.bonesnum; i++)
|
||
|
|
{
|
||
|
|
GameObject bone = new GameObject(mdlBones[i].pszName);
|
||
|
|
if(mdlBones[i].parent>=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<vtxBodyParts.Length; bpId++)
|
||
|
|
//{
|
||
|
|
int bpId=0;
|
||
|
|
|
||
|
|
vtxBodypartHeader vtxBodyPart = vtxBodyParts[bpId];
|
||
|
|
studiobodypart mdlBodyPart = mdlBodyParts[bpId];
|
||
|
|
for(int modelId=0; modelId<vtxBodyPart.models.Length; modelId++)
|
||
|
|
{
|
||
|
|
vtxModelHeader vtxModel = vtxBodyPart.models[modelId];
|
||
|
|
studiomodel mdlModel=mdlBodyPart.models[modelId];
|
||
|
|
|
||
|
|
vtxModelLODheader _lod = vtxModel.lods[lodLevel];
|
||
|
|
|
||
|
|
for(int meshId=0; meshId<_lod.numMeshes; meshId++)
|
||
|
|
{
|
||
|
|
vtxMeshHeader vtxMesh=_lod.meshes[meshId];
|
||
|
|
studiomesh mdlMesh=mdlModel.meshes[meshId];
|
||
|
|
|
||
|
|
int materialId=mdlMesh.material+(numSkinRefs*skin);
|
||
|
|
string material=mdlTextures[mdlSkinFamilies[materialId]].textureName;
|
||
|
|
//Debug.Log ("Mesh "+curmeshId+" material is "+material);
|
||
|
|
|
||
|
|
if(TempMats[curmeshId]==null)
|
||
|
|
{
|
||
|
|
/*string materialName=ResourceManager.FindModelMaterialFile(material,mdlTexturePaths);
|
||
|
|
|
||
|
|
if(materialName!=null)
|
||
|
|
TempMats[curmeshId] = ResourceManager.Inst.GetMaterial(materialName);
|
||
|
|
else
|
||
|
|
TempMats[curmeshId] = ResourceManager.Inst.GetMaterial(material);*/
|
||
|
|
|
||
|
|
//TPDO: restore mat find
|
||
|
|
var matPath = AssetDatabase.FindAssets("DefaultBspMaterial");
|
||
|
|
var assetPath = AssetDatabase.GUIDToAssetPath(matPath[0]);
|
||
|
|
tempMat = AssetDatabase.LoadAssetAtPath<Material>(assetPath);
|
||
|
|
TempMats[curmeshId] = tempMat;
|
||
|
|
}
|
||
|
|
|
||
|
|
for(int stripGroupId=0; stripGroupId<vtxMesh.numStripGroups; stripGroupId++)
|
||
|
|
{
|
||
|
|
vtxStripGroupHeader stripGroup=vtxMesh.stripGroups[stripGroupId];
|
||
|
|
|
||
|
|
//for(int stripId=0; stripId<stripGroup.numStrips;stripId++)
|
||
|
|
//{
|
||
|
|
//====================
|
||
|
|
//vtxStripGroupHeader stripGroup=vtxBodyParts[0].models[0].lods[lodLevel].meshes[0].stripGroups[0];
|
||
|
|
//vtxStripHeader strip=stripGroup.strips[0];
|
||
|
|
//====================
|
||
|
|
|
||
|
|
//vtxStripHeader strip=stripGroup.strips[stripId];
|
||
|
|
|
||
|
|
//int indexOffset=stripGroup.indexOffs+strip.indexOffset;
|
||
|
|
//int numIndices=strip.numIndices;
|
||
|
|
int indexOffset=curIndexOffset;
|
||
|
|
int numIndices=stripGroup.numIndices*4;
|
||
|
|
|
||
|
|
//Debug.Log("Mesh "+curmeshId+" index count is "+numIndices/4+" index offset "+indexOffset/4);
|
||
|
|
|
||
|
|
int[] tempIndex = new int[stripGroup.numIndices];
|
||
|
|
System.Buffer.BlockCopy(indexArray,indexOffset,tempIndex,0,numIndices);
|
||
|
|
modelMesh.SetTriangles(tempIndex, curmeshId);
|
||
|
|
if(modelMesh.GetTriangles(curmeshId).Length==0)
|
||
|
|
Debug.LogWarning ("Error with model "+modelName+": setting tris for "+curmeshId+" submesh");
|
||
|
|
|
||
|
|
curmeshId++;
|
||
|
|
curIndexOffset+=stripGroup.numIndices*4;
|
||
|
|
//}
|
||
|
|
}
|
||
|
|
}//mesh
|
||
|
|
}//model
|
||
|
|
//}//bp
|
||
|
|
}//!used
|
||
|
|
|
||
|
|
//Vector3 rot=new Vector3(-mdlBones[i].rot.x*Mathf.Rad2Deg,-mdlBones[i].rot.z*Mathf.Rad2Deg,-mdlBones[i].rot.y*Mathf.Rad2Deg);
|
||
|
|
Vector3 rootrot = new Vector3(0,-mdlBones[0].rot.x*Mathf.Rad2Deg,0);
|
||
|
|
|
||
|
|
go.transform.localEulerAngles+=rootrot;
|
||
|
|
|
||
|
|
var mf = go.GetComponent<MeshFilter>();
|
||
|
|
if(mf == null) {
|
||
|
|
mf = go.AddComponent<MeshFilter>();
|
||
|
|
}
|
||
|
|
|
||
|
|
mf.sharedMesh = modelMesh;
|
||
|
|
|
||
|
|
|
||
|
|
MeshRenderer mr = go.GetComponent<MeshRenderer> ();
|
||
|
|
if(mr == null) {
|
||
|
|
mr = go.AddComponent<MeshRenderer>();
|
||
|
|
|
||
|
|
}
|
||
|
|
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<numSkinRefs; i++)
|
||
|
|
{
|
||
|
|
int texId = mdlSkinFamilies[skinTableOffset+i];
|
||
|
|
string textureName = "";
|
||
|
|
if(texId<mdlTexturePaths.Length)
|
||
|
|
textureName += mdlTexturePaths[texId];
|
||
|
|
else
|
||
|
|
textureName += mdlTexturePaths[mdlTexturePaths.Length-1];
|
||
|
|
textureName += mdlTextures [texId].textureName;
|
||
|
|
//LoadMaterial(textureName)
|
||
|
|
//Debug.Log ("Need to load material "+textureName);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
public bool ParseMdl(string name, Func<string, Stream> 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<mdlBodyParts.Length; bpId++)
|
||
|
|
{
|
||
|
|
studiobodypart bodypart = mdlBodyParts [bpId];
|
||
|
|
for (int modelId=0; modelId<bodypart.models.Length; modelId++)
|
||
|
|
{
|
||
|
|
studiomodel model = bodypart.models [modelId];
|
||
|
|
|
||
|
|
int totalMeshVertices = 0;
|
||
|
|
for (int meshId=0; meshId<model.meshnum; meshId++)
|
||
|
|
{
|
||
|
|
studiomesh mesh = model.meshes [meshId];
|
||
|
|
|
||
|
|
mesh.vertexnum=mesh.vertexdata.numLODVertexes[lod];
|
||
|
|
mesh.vertexoffs=totalMeshVertices;
|
||
|
|
totalMeshVertices+=mesh.vertexnum;
|
||
|
|
}
|
||
|
|
|
||
|
|
model.verticesnum=totalMeshVertices;
|
||
|
|
model.verticesoffs=vertexOffset;
|
||
|
|
vertexOffset+=totalMeshVertices;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
Debug.Log ("Vertixes count "+vertexOffset);
|
||
|
|
lodLevel = lod;
|
||
|
|
}
|
||
|
|
|
||
|
|
studiohdr_t ReadHeader(BinaryReader BR)
|
||
|
|
{
|
||
|
|
studiohdr_t hdr = new studiohdr_t ();
|
||
|
|
|
||
|
|
hdr.id = BR.ReadChars(4);
|
||
|
|
hdr.version = BR.ReadInt32 ();
|
||
|
|
hdr.checksum = BR.ReadInt32 ();
|
||
|
|
hdr.Name = new string(BR.ReadChars (64));
|
||
|
|
hdr.Name = hdr.Name.Remove (hdr.Name.IndexOf ('\0'));
|
||
|
|
// Debug.Log("Model "+hdr.Name+" version is "+hdr.version);
|
||
|
|
hdr.length = BR.ReadInt32 ();
|
||
|
|
|
||
|
|
//header01
|
||
|
|
|
||
|
|
hdr.eyeposition = new Vector3(BR.ReadSingle (), BR.ReadSingle (), BR.ReadSingle ());
|
||
|
|
hdr.illumposition = new Vector3(BR.ReadSingle (), BR.ReadSingle (), BR.ReadSingle ());
|
||
|
|
|
||
|
|
hdr.hullmin = new Vector3(BR.ReadSingle (), BR.ReadSingle (), BR.ReadSingle ());
|
||
|
|
hdr.hullmax = new Vector3(BR.ReadSingle (), BR.ReadSingle (), BR.ReadSingle ());
|
||
|
|
|
||
|
|
hdr.view_bbmin = new Vector3(BR.ReadSingle (), BR.ReadSingle (), BR.ReadSingle ());
|
||
|
|
hdr.view_bbmax = new Vector3(BR.ReadSingle (), BR.ReadSingle (), BR.ReadSingle ());
|
||
|
|
|
||
|
|
hdr.flags = BR.ReadInt32 ();
|
||
|
|
|
||
|
|
hdr.bonesnum = BR.ReadInt32 ();
|
||
|
|
hdr.boneoffs = BR.ReadInt32 ();
|
||
|
|
|
||
|
|
hdr.bonecontrollernum = BR.ReadInt32 ();
|
||
|
|
hdr.bonecontrolleroffs = BR.ReadInt32 ();
|
||
|
|
|
||
|
|
hdr.hitboxnum = BR.ReadInt32 ();
|
||
|
|
hdr.hitboxoffs = BR.ReadInt32 ();
|
||
|
|
|
||
|
|
hdr.localanimnum = BR.ReadInt32 ();
|
||
|
|
hdr.localanimoffs = BR.ReadInt32 ();
|
||
|
|
|
||
|
|
hdr.localseqnum = BR.ReadInt32 ();
|
||
|
|
hdr.localseqoffs = BR.ReadInt32 ();
|
||
|
|
|
||
|
|
hdr.activitylistversion = BR.ReadInt32 ();
|
||
|
|
hdr.eventsindexed = BR.ReadInt32 ();
|
||
|
|
|
||
|
|
hdr.texturenum = BR.ReadInt32 ();
|
||
|
|
hdr.textureoffs = BR.ReadInt32 ();
|
||
|
|
|
||
|
|
hdr.texturedirnum = BR.ReadInt32 ();
|
||
|
|
hdr.texturediroffs = BR.ReadInt32 ();
|
||
|
|
|
||
|
|
hdr.skinrefnum = BR.ReadInt32 ();
|
||
|
|
hdr.skinfamilynum = BR.ReadInt32 ();
|
||
|
|
hdr.skinfamilyoffs = BR.ReadInt32 ();
|
||
|
|
|
||
|
|
hdr.bodypartnum = BR.ReadInt32 ();
|
||
|
|
hdr.bodypartoffs = BR.ReadInt32 ();
|
||
|
|
|
||
|
|
hdr.attachmentnum = BR.ReadInt32 ();
|
||
|
|
hdr.attachmentoffs = BR.ReadInt32 ();
|
||
|
|
|
||
|
|
hdr.localnodenum = BR.ReadInt32 ();
|
||
|
|
hdr.localnodeoffs = BR.ReadInt32 ();
|
||
|
|
|
||
|
|
hdr.localnodenameoffs = BR.ReadInt32 ();
|
||
|
|
|
||
|
|
hdr.flexdescnum = BR.ReadInt32 ();
|
||
|
|
hdr.flexdescoffs = BR.ReadInt32 ();
|
||
|
|
|
||
|
|
hdr.flexcontrollernum = BR.ReadInt32 ();
|
||
|
|
hdr.flexcontrolleroffs = BR.ReadInt32 ();
|
||
|
|
|
||
|
|
hdr.flexrulesnum = BR.ReadInt32 ();
|
||
|
|
hdr.flexrulesoffs = BR.ReadInt32 ();
|
||
|
|
|
||
|
|
hdr.ikchainnum = BR.ReadInt32 ();
|
||
|
|
hdr.ikchainoffs = BR.ReadInt32 ();
|
||
|
|
|
||
|
|
hdr.mouthsnum = BR.ReadInt32 ();
|
||
|
|
hdr.mouthsoffs = BR.ReadInt32 ();
|
||
|
|
|
||
|
|
hdr.localposeparamnum = BR.ReadInt32 ();
|
||
|
|
hdr.localposeparamoffs = BR.ReadInt32 ();
|
||
|
|
|
||
|
|
hdr.surfacepropoffs = BR.ReadInt32 ();
|
||
|
|
|
||
|
|
hdr.keyvalueoffs = BR.ReadInt32 ();
|
||
|
|
hdr.keyvaluenum = BR.ReadInt32 ();
|
||
|
|
|
||
|
|
hdr.iklocknum = BR.ReadInt32 ();
|
||
|
|
hdr.iklockoffs = BR.ReadInt32 ();
|
||
|
|
|
||
|
|
hdr.mass = BR.ReadSingle ();
|
||
|
|
|
||
|
|
hdr.contents = BR.ReadInt32 ();
|
||
|
|
|
||
|
|
hdr.includemodelnum = BR.ReadInt32 ();
|
||
|
|
hdr.includemodeloffs = BR.ReadInt32 ();
|
||
|
|
|
||
|
|
hdr.virtualModel = BR.ReadInt32 ();
|
||
|
|
|
||
|
|
hdr.animblocksnameoffs = BR.ReadInt32 ();
|
||
|
|
hdr.animblocksnum = BR.ReadInt32 ();
|
||
|
|
hdr.animblocksoffs = BR.ReadInt32 ();
|
||
|
|
hdr.animblockModel = BR.ReadInt32 ();
|
||
|
|
|
||
|
|
hdr.bonetablenameoffs = BR.ReadInt32 ();
|
||
|
|
|
||
|
|
hdr.vertex_base = BR.ReadInt32 ();
|
||
|
|
hdr.offset_base = BR.ReadInt32 ();
|
||
|
|
|
||
|
|
hdr.directionaldotproduct = BR.ReadByte ();
|
||
|
|
|
||
|
|
hdr.rootLod = BR.ReadByte ();
|
||
|
|
hdr.numAllowedRootLods = BR.ReadByte ();
|
||
|
|
|
||
|
|
BR.BaseStream.Seek (5, SeekOrigin.Current);
|
||
|
|
|
||
|
|
hdr.flexcontrolleruinum = BR.ReadInt32 ();
|
||
|
|
hdr.flexcontrolleruioffs = BR.ReadInt32 ();
|
||
|
|
|
||
|
|
BR.BaseStream.Seek (8,SeekOrigin.Current);
|
||
|
|
|
||
|
|
hdr.studiohdr2offs = BR.ReadInt32 ();
|
||
|
|
|
||
|
|
BR.BaseStream.Seek (4,SeekOrigin.Current);
|
||
|
|
|
||
|
|
return hdr;
|
||
|
|
}
|
||
|
|
|
||
|
|
studiobone_t[] ReadStudioBones(BinaryReader br, int offs, int num)
|
||
|
|
{
|
||
|
|
studiobone_t[] bones = new studiobone_t[num];
|
||
|
|
|
||
|
|
br.BaseStream.Seek (offs, SeekOrigin.Begin);
|
||
|
|
for (int i=0; i<num; i++)
|
||
|
|
{
|
||
|
|
//BR.BaseStream.Seek (offs+(i*216), SeekOrigin.Begin);
|
||
|
|
bones[i] = new studiobone_t();
|
||
|
|
bones[i].sznameindex = br.ReadInt32();
|
||
|
|
bones[i].parent = br.ReadInt32();
|
||
|
|
bones[i].bonecontroller =new int[]{ br.ReadInt32(),br.ReadInt32(),
|
||
|
|
br.ReadInt32(),br.ReadInt32(),br.ReadInt32(),br.ReadInt32() };
|
||
|
|
bones[i].pos = ConvertUtils.ReadVector3( br);
|
||
|
|
bones[i].quat = ConvertUtils.ReadQuat( br);
|
||
|
|
bones[i].rot = ConvertUtils.ReadVector3( br);
|
||
|
|
bones[i].posscale = ConvertUtils.ReadVector3( br);
|
||
|
|
bones[i].rotscale = ConvertUtils.ReadVector3( br);
|
||
|
|
|
||
|
|
bones[i].poseToBone = new float[]{
|
||
|
|
br.ReadSingle(),br.ReadSingle(),br.ReadSingle(),
|
||
|
|
br.ReadSingle(),br.ReadSingle(),br.ReadSingle(),
|
||
|
|
br.ReadSingle(),br.ReadSingle(),br.ReadSingle(),
|
||
|
|
br.ReadSingle(),br.ReadSingle(),br.ReadSingle()};
|
||
|
|
|
||
|
|
bones[i].qAlignment = ConvertUtils.ReadQuat( br);
|
||
|
|
bones[i].flags = br.ReadInt32();
|
||
|
|
bones[i].proctype = br.ReadInt32();
|
||
|
|
bones[i].procindex = br.ReadInt32();
|
||
|
|
bones[i].physicsbone = br.ReadInt32();
|
||
|
|
bones[i].surfacepropidx = br.ReadInt32();
|
||
|
|
bones[i].contents = br.ReadInt32();
|
||
|
|
br.BaseStream.Seek(32,SeekOrigin.Current);
|
||
|
|
}
|
||
|
|
|
||
|
|
for (int i=0; i<num; i++)
|
||
|
|
{
|
||
|
|
bones[i].pszName = ConvertUtils.ReadNullTerminatedString(br,offs+(i*216)+bones[i].sznameindex);
|
||
|
|
}
|
||
|
|
|
||
|
|
return bones;
|
||
|
|
}
|
||
|
|
|
||
|
|
studiobodypart[] ReadMdlBodyParts(BinaryReader br, int offs, int num)
|
||
|
|
{
|
||
|
|
studiobodypart[] bp = new studiobodypart[num];
|
||
|
|
|
||
|
|
br.BaseStream.Seek (offs, SeekOrigin.Begin);
|
||
|
|
// Debug.Log ("numBodyParts: "+num);
|
||
|
|
for (int i=0; i<num; i++)
|
||
|
|
{
|
||
|
|
br.BaseStream.Seek (offs+(i*16), SeekOrigin.Begin);
|
||
|
|
bp[i] = new studiobodypart(br.ReadInt32 (),br.ReadInt32 (),br.ReadInt32 (),br.ReadInt32 ());
|
||
|
|
//bp[i].name = ConvertUtils.ReadNullTerminatedString(BR,offs+(i*16)+bp[i].nameindex);
|
||
|
|
bp[i].models = ReadStudioModels(br, offs+(i*16), bp[i]);
|
||
|
|
}
|
||
|
|
|
||
|
|
for (int i=0; i<num; i++)
|
||
|
|
{
|
||
|
|
bp[i].name = ConvertUtils.ReadNullTerminatedString(br,offs+(i*16)+bp[i].nameindex);
|
||
|
|
}
|
||
|
|
|
||
|
|
return bp;
|
||
|
|
}
|
||
|
|
|
||
|
|
studiomodel[] ReadStudioModels(BinaryReader BR, int offset, studiobodypart bp)
|
||
|
|
{
|
||
|
|
BR.BaseStream.Seek (bp.modelindex+offset, SeekOrigin.Begin);
|
||
|
|
studiomodel[] temp = new studiomodel[bp.nummodels];
|
||
|
|
for (int i=0; i<bp.nummodels; i++)
|
||
|
|
{
|
||
|
|
BR.BaseStream.Seek (bp.modelindex + offset + (i*148), SeekOrigin.Begin);
|
||
|
|
string tempName=new string (BR.ReadChars (64));
|
||
|
|
if(tempName.Contains ('\0'))
|
||
|
|
tempName = tempName.Remove (tempName.IndexOf ('\0'));
|
||
|
|
temp[i] = new studiomodel (tempName, BR.ReadInt32 (), BR.ReadSingle (), BR.ReadInt32 (),
|
||
|
|
BR.ReadInt32 (), BR.ReadInt32 (), BR.ReadInt32 (), BR.ReadInt32 (),
|
||
|
|
BR.ReadInt32 (), BR.ReadInt32 (), BR.ReadInt32 (), BR.ReadInt32 (),new mstudio_modelvertexdata_t(BR.ReadInt32(),BR.ReadInt32()));
|
||
|
|
BR.BaseStream.Seek (32, SeekOrigin.Current);
|
||
|
|
//length 148
|
||
|
|
|
||
|
|
temp[i].meshes = ReadStudioMeshes(BR, bp.modelindex + offset + (i*148), temp[i]);
|
||
|
|
|
||
|
|
}
|
||
|
|
return temp;
|
||
|
|
}
|
||
|
|
|
||
|
|
studiomesh[] ReadStudioMeshes(BinaryReader BR, int offset, studiomodel model)
|
||
|
|
{
|
||
|
|
studiomesh[] temp = new studiomesh[model.meshnum];
|
||
|
|
|
||
|
|
BR.BaseStream.Seek (model.meshoffs + offset, SeekOrigin.Begin);
|
||
|
|
for (int i=0; i<model.meshnum; i++)
|
||
|
|
{
|
||
|
|
//BR.BaseStream.Seek (model.meshoffs + offset + (i*116), SeekOrigin.Begin);
|
||
|
|
temp[i] = new studiomesh(BR.ReadInt32(), BR.ReadInt32(), BR.ReadInt32(),
|
||
|
|
BR.ReadInt32(), BR.ReadInt32(), BR.ReadInt32(),
|
||
|
|
BR.ReadInt32(), BR.ReadInt32(), BR.ReadInt32(),
|
||
|
|
new Vector3(BR.ReadSingle(),BR.ReadSingle(),BR.ReadSingle()),
|
||
|
|
new studio_meshvertexdata(BR.ReadInt32(),
|
||
|
|
new int[]{BR.ReadInt32(),BR.ReadInt32(),BR.ReadInt32(),BR.ReadInt32(),
|
||
|
|
BR.ReadInt32(),BR.ReadInt32(),BR.ReadInt32(),BR.ReadInt32()})
|
||
|
|
);
|
||
|
|
BR.BaseStream.Seek (32, SeekOrigin.Current);
|
||
|
|
}
|
||
|
|
return temp;
|
||
|
|
}
|
||
|
|
|
||
|
|
studiotexture_t[] ReadStudioTextures(BinaryReader br, int offset, int count)
|
||
|
|
{
|
||
|
|
br.BaseStream.Seek (offset, SeekOrigin.Begin);
|
||
|
|
|
||
|
|
studiotexture_t[] st = new studiotexture_t[count];
|
||
|
|
|
||
|
|
for (int i=0; i<count; i++)
|
||
|
|
{
|
||
|
|
st[i] = new studiotexture_t();
|
||
|
|
st[i].name_offset = br.ReadInt32();
|
||
|
|
st[i].flags=br.ReadInt32();
|
||
|
|
st[i].used=br.ReadInt32();
|
||
|
|
st[i].unused=br.ReadInt32();
|
||
|
|
st[i].material=br.ReadInt32();
|
||
|
|
st[i].client_material=br.ReadInt32();
|
||
|
|
br.BaseStream.Seek(40,SeekOrigin.Current);
|
||
|
|
}
|
||
|
|
|
||
|
|
for (int i=0; i<count; i++)
|
||
|
|
{
|
||
|
|
br.BaseStream.Seek(offset + st[i].name_offset + (i*64),SeekOrigin.Begin);
|
||
|
|
st[i].textureName = ConvertUtils.ReadNullTerminatedString(br);
|
||
|
|
//Debug.Log ("Texture "+i+" name is "+st[i].textureName);
|
||
|
|
}
|
||
|
|
|
||
|
|
return st;
|
||
|
|
}
|
||
|
|
|
||
|
|
string[] ReadTexturePaths(BinaryReader br, int offs, int count)
|
||
|
|
{
|
||
|
|
int[] texturePathOffs=new int[count];
|
||
|
|
string[] texturePaths=new string[count];
|
||
|
|
br.BaseStream.Seek (offs, SeekOrigin.Begin);
|
||
|
|
for (int i=0; i<count; i++)
|
||
|
|
{
|
||
|
|
texturePathOffs[i]=br.ReadInt32();
|
||
|
|
}
|
||
|
|
|
||
|
|
for (int i=0; i<count; i++)
|
||
|
|
{
|
||
|
|
string tempStr=ConvertUtils.ReadNullTerminatedString(br,texturePathOffs[i]);
|
||
|
|
tempStr=tempStr.Replace ("\\","/");
|
||
|
|
texturePaths[i]=tempStr;
|
||
|
|
//Debug.Log ("texturePath "+i+" is "+texturePaths[i]);
|
||
|
|
}
|
||
|
|
return texturePaths;
|
||
|
|
}
|
||
|
|
|
||
|
|
short[] ReadSkinFamilies(BinaryReader br,int offs,int count, int refCount)
|
||
|
|
{
|
||
|
|
short[] skinFams = new short[count*refCount];
|
||
|
|
|
||
|
|
br.BaseStream.Seek (offs, SeekOrigin.Begin);
|
||
|
|
for (int i=0; i<count; i++)
|
||
|
|
{
|
||
|
|
//skinFams[i] = new short[refCount];
|
||
|
|
for (int j=0; j<refCount; j++)
|
||
|
|
{
|
||
|
|
short skinRef = br.ReadInt16();
|
||
|
|
//skinFams[i][j]=skinRef;
|
||
|
|
skinFams[(i*refCount)+j] = skinRef;
|
||
|
|
//Debug.Log ("skin family "+i+" ref "+j+" is "+skinRef);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return skinFams;
|
||
|
|
}
|
||
|
|
|
||
|
|
//=============================================================================
|
||
|
|
//===============================VVD===========================================
|
||
|
|
//=============================================================================
|
||
|
|
|
||
|
|
|
||
|
|
public void ParseVvd(string path, Func<string, Stream> 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<vvdHeader.numFixup; i++)
|
||
|
|
{
|
||
|
|
fixupTable[i]=new vertexFileFixup(BR.ReadInt32(),BR.ReadInt32(),BR.ReadInt32());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (vvdHeader.numLODs > 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<vertCount; i++)
|
||
|
|
{
|
||
|
|
BoneWeight bw = new BoneWeight ();
|
||
|
|
bw.weight0 = br.ReadSingle ();
|
||
|
|
bw.weight1 = br.ReadSingle ();
|
||
|
|
bw.weight2 = br.ReadSingle ();
|
||
|
|
bw.boneIndex0 = br.ReadByte ();
|
||
|
|
bw.boneIndex1 = br.ReadByte ();
|
||
|
|
bw.boneIndex2 = br.ReadByte ();
|
||
|
|
/*numbones =*/br.ReadByte ();
|
||
|
|
boneWeights [i] = bw;
|
||
|
|
|
||
|
|
vertArray [i] = ConvertUtils.FlipVector (ConvertUtils.ReadVector3 (br)) * SourceImportConfig.WorldScale;
|
||
|
|
Normals [i] = ConvertUtils.FlipVector (ConvertUtils.ReadVector3 (br));
|
||
|
|
UV [i] = ConvertUtils.ReadVector2 (br);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
List<Vector3> VertexView = new List<Vector3>();
|
||
|
|
List<Vector3> NormalView = new List<Vector3>();
|
||
|
|
List<Vector2> UVView = new List<Vector2>();
|
||
|
|
List<BoneWeight> _boneWeights = new List<BoneWeight> ();
|
||
|
|
//int target=0;
|
||
|
|
//int vertexArrayOffset=0;
|
||
|
|
|
||
|
|
for (int i=0; i<fixupTable.Length; i++)
|
||
|
|
{
|
||
|
|
if(fixupTable[i].lod < lodLevel)
|
||
|
|
continue;
|
||
|
|
|
||
|
|
for (int j=0; j<fixupTable[i].numVertexes; j++)
|
||
|
|
{
|
||
|
|
int vertexViewOffset=(int)(vertOffs+((fixupTable[i].sourceVertexID+j)*48));
|
||
|
|
br.BaseStream.Seek(vertexViewOffset, SeekOrigin.Begin);
|
||
|
|
|
||
|
|
//48 bytes
|
||
|
|
BoneWeight bw = new BoneWeight ();
|
||
|
|
bw.weight0 = br.ReadSingle ();
|
||
|
|
bw.weight1 = br.ReadSingle ();
|
||
|
|
bw.weight2 = br.ReadSingle ();
|
||
|
|
bw.boneIndex0 = br.ReadByte ();
|
||
|
|
bw.boneIndex1 = br.ReadByte ();
|
||
|
|
bw.boneIndex2 = br.ReadByte ();
|
||
|
|
/*numbones =*/br.ReadByte ();
|
||
|
|
_boneWeights.Add (bw);
|
||
|
|
|
||
|
|
VertexView.Add( ConvertUtils.FlipVector (ConvertUtils.ReadVector3 (br)) * SourceImportConfig.WorldScale);
|
||
|
|
NormalView.Add (ConvertUtils.FlipVector (ConvertUtils.ReadVector3 (br)));
|
||
|
|
UVView.Add (ConvertUtils.ReadVector2 (br));
|
||
|
|
|
||
|
|
//vertexArrayOffset++;
|
||
|
|
}
|
||
|
|
//target += fixupTable[i].numVertexes;
|
||
|
|
}
|
||
|
|
Normals = NormalView.ToArray ();
|
||
|
|
UV = UVView.ToArray ();
|
||
|
|
boneWeights = _boneWeights.ToArray ();
|
||
|
|
vertArray = VertexView.ToArray();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/*Vector3[] ParseFixup(BinaryReader BR, int fixupOffs, int fixupCount,int VertexOffs,int tangetnOffs,
|
||
|
|
out Vector3[] _Normals, out Vector2[] _UV, int vertCount)
|
||
|
|
{
|
||
|
|
List<Vector3> VertexView = new List<Vector3>();
|
||
|
|
List<Vector3> NormalView = new List<Vector3>();
|
||
|
|
List<Vector2> UVView = new List<Vector2>();
|
||
|
|
List<BoneWeight> _boneWeights = new List<BoneWeight> ();
|
||
|
|
_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<vertCount; i++)
|
||
|
|
{
|
||
|
|
//int vertexOffs = i*48;
|
||
|
|
//BR.BaseStream.Seek(16,SeekOrigin.Current);
|
||
|
|
BoneWeight bw = new BoneWeight();
|
||
|
|
bw.weight0=BR.ReadSingle();
|
||
|
|
bw.weight1=BR.ReadSingle();
|
||
|
|
bw.weight2=BR.ReadSingle();
|
||
|
|
bw.boneIndex0=BR.ReadByte();
|
||
|
|
bw.boneIndex1=BR.ReadByte();
|
||
|
|
bw.boneIndex2=BR.ReadByte();
|
||
|
|
/*numbones = BR.ReadByte();
|
||
|
|
_boneWeights.Add (bw);
|
||
|
|
VertexView.Add (ConvertUtils.FlipVector(ConvertUtils.ReadVector3(BR))*Settings.Inst.worldScale);
|
||
|
|
NormalView.Add (ConvertUtils.FlipVector(ConvertUtils.ReadVector3(BR)));
|
||
|
|
UVView.Add (ConvertUtils.ReadVector2 (BR));
|
||
|
|
//BR.BaseStream.Seek (8,SeekOrigin.Current);
|
||
|
|
vertexArrayOffset++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
//Debug.Log("FixupCount "+fixupCount+"\n"+
|
||
|
|
// "FixupOffs: "+fixupOffs);
|
||
|
|
|
||
|
|
int target=0;
|
||
|
|
fixupTable=new vertexFileFixup[fixupCount];
|
||
|
|
|
||
|
|
BR.BaseStream.Seek(fixupOffs, SeekOrigin.Begin);
|
||
|
|
for (int i=0; i<fixupCount; i++)
|
||
|
|
{
|
||
|
|
fixupTable[i]=new vertexFileFixup(BR.ReadInt32(),BR.ReadInt32(),BR.ReadInt32());
|
||
|
|
|
||
|
|
//Debug.Log ("Fixup LODs: "+fixupTable[i].lod);
|
||
|
|
//Debug.Log ("sourceVertexID: "+fixupTable[i].sourceVertexID);
|
||
|
|
//Debug.Log ("num vertices: "+fixupTable[i].numVertexes);
|
||
|
|
}
|
||
|
|
|
||
|
|
for (int i=0; i<fixupCount; i++)
|
||
|
|
{
|
||
|
|
if(fixupTable[i].lod < lodLevel)
|
||
|
|
continue;
|
||
|
|
|
||
|
|
for (int j=0; j<fixupTable[i].numVertexes; j++)
|
||
|
|
{
|
||
|
|
int vertexViewOffset=(int)(VertexOffs+((fixupTable[i].sourceVertexID+j)*48));
|
||
|
|
BR.BaseStream.Seek(vertexViewOffset, SeekOrigin.Begin);
|
||
|
|
|
||
|
|
//48 bytes
|
||
|
|
//BR.BaseStream.Seek(16,SeekOrigin.Current);
|
||
|
|
BoneWeight bw = new BoneWeight();
|
||
|
|
bw.weight0=BR.ReadSingle();
|
||
|
|
bw.weight1=BR.ReadSingle();
|
||
|
|
bw.weight2=BR.ReadSingle();
|
||
|
|
bw.boneIndex0=BR.ReadByte();
|
||
|
|
bw.boneIndex1=BR.ReadByte();
|
||
|
|
bw.boneIndex2=BR.ReadByte();
|
||
|
|
/*numbones = BR.ReadByte();
|
||
|
|
_boneWeights.Add (bw);
|
||
|
|
VertexView.Add (ConvertUtils.FlipVector(ConvertUtils.ReadVector3(BR))*Settings.Inst.worldScale);
|
||
|
|
NormalView.Add (ConvertUtils.FlipVector(ConvertUtils.ReadVector3(BR)));
|
||
|
|
UVView.Add (new Vector2(BR.ReadSingle(),BR.ReadSingle()));
|
||
|
|
|
||
|
|
vertexArrayOffset++;
|
||
|
|
}
|
||
|
|
target += fixupTable[i].numVertexes;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
_Normals = NormalView.ToArray ();
|
||
|
|
_UV = UVView.ToArray ();
|
||
|
|
boneWeights = _boneWeights.ToArray ();
|
||
|
|
return VertexView.ToArray();
|
||
|
|
}*/
|
||
|
|
|
||
|
|
//============================================================
|
||
|
|
// VTX
|
||
|
|
//============================================================
|
||
|
|
|
||
|
|
public void ParseVtx(string path, Func<string, Stream> 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; i<count; i++)
|
||
|
|
{
|
||
|
|
br.BaseStream.Seek (offs+(i*8), SeekOrigin.Begin);
|
||
|
|
bp[i] = new vtxBodypartHeader(br.ReadInt32 (),br.ReadInt32 ());
|
||
|
|
if(bp[i].numModels>0)
|
||
|
|
{
|
||
|
|
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; i<bodypart.numModels; i++)
|
||
|
|
{
|
||
|
|
br.BaseStream.Seek (bodypart.modelsOffset + offset + (i*8), SeekOrigin.Begin);
|
||
|
|
mh[i] = new vtxModelHeader (br.ReadInt32 (), br.ReadInt32 ());
|
||
|
|
if(mh[i].numLODs>0)
|
||
|
|
{
|
||
|
|
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; i<model.numLODs; i++)
|
||
|
|
{
|
||
|
|
br.BaseStream.Seek (model.LODOffset + offset + (i*12), SeekOrigin.Begin);
|
||
|
|
mlods[i] = new vtxModelLODheader (br.ReadInt32 (), br.ReadInt32 (),br.ReadSingle());
|
||
|
|
if(mlods[i].numMeshes>0)
|
||
|
|
{
|
||
|
|
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; i<lod.numMeshes; i++)
|
||
|
|
{
|
||
|
|
br.BaseStream.Seek (lod.meshOffset + offset + (i*9), SeekOrigin.Begin);
|
||
|
|
ms[i] = new vtxMeshHeader (br.ReadInt32 (), br.ReadInt32 (),br.ReadByte());
|
||
|
|
|
||
|
|
if(ms[i].numStripGroups>0)
|
||
|
|
{
|
||
|
|
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; i<mesh.numStripGroups; i++)
|
||
|
|
{
|
||
|
|
br.BaseStream.Seek (mesh.stripGroupHeaderOffset + offset + (i*25), SeekOrigin.Begin);
|
||
|
|
sg[i] = new vtxStripGroupHeader (br.ReadInt32 (), br.ReadInt32 (),br.ReadInt32 (),
|
||
|
|
br.ReadInt32 (),br.ReadInt32 (),br.ReadInt32 (),br.ReadByte());
|
||
|
|
//Debug.Log ("Strip group "+i+" vert count is "+sg[i].numVerts);
|
||
|
|
if(sg[i].numVerts>0)
|
||
|
|
{
|
||
|
|
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; j<sg[i].numIndices;j++)
|
||
|
|
sg[i].indexArray[j] = br.ReadUInt16();
|
||
|
|
}
|
||
|
|
if(sg[i].numStrips>0)
|
||
|
|
{
|
||
|
|
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<sg[i].numIndices;j++)
|
||
|
|
// sg[i].indexArray[j] = br.ReadUInt16();
|
||
|
|
}
|
||
|
|
return sg;
|
||
|
|
}
|
||
|
|
|
||
|
|
vtxVertex[] ReadVtxVerts(BinaryReader br, int offset, vtxStripGroupHeader stripGroup)
|
||
|
|
{
|
||
|
|
vtxVertex[] vs = new vtxVertex[stripGroup.numVerts];
|
||
|
|
|
||
|
|
br.BaseStream.Seek (stripGroup.vertOffset + offset, SeekOrigin.Begin);
|
||
|
|
|
||
|
|
for (int i=0; i<stripGroup.numVerts; i++)
|
||
|
|
{
|
||
|
|
//br.BaseStream.Seek (stripGroup.vertOffset + offset + (i*9), SeekOrigin.Begin);
|
||
|
|
vs[i] = new vtxVertex (br.ReadBytes(3), br.ReadByte(),br.ReadUInt16(), br.ReadBytes(3));
|
||
|
|
}
|
||
|
|
return vs;
|
||
|
|
}
|
||
|
|
|
||
|
|
vtxStripHeader[] ReadVtxStrips(BinaryReader br, int offset, vtxStripGroupHeader stripGroup)
|
||
|
|
{
|
||
|
|
vtxStripHeader[] st = new vtxStripHeader[stripGroup.numStrips];
|
||
|
|
|
||
|
|
br.BaseStream.Seek (stripGroup.stripOffset + offset, SeekOrigin.Begin);
|
||
|
|
|
||
|
|
for (int i=0; i<stripGroup.numStrips; i++)
|
||
|
|
{
|
||
|
|
//br.BaseStream.Seek (stripGroup.stripOffset + offset + (i*25), SeekOrigin.Begin);
|
||
|
|
st[i] = new vtxStripHeader (br.ReadInt32 (), br.ReadInt32 (),br.ReadInt32 (),br.ReadInt32 (),
|
||
|
|
br.ReadInt16 (), br.ReadByte(), br.ReadInt32(), br.ReadInt32());
|
||
|
|
}
|
||
|
|
return st;
|
||
|
|
}
|
||
|
|
|
||
|
|
int[] BuildIndices(vtxBodypartHeader[] bodyParts)
|
||
|
|
{
|
||
|
|
if (lodLevel >= 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<bodyParts.Length; bpId++)
|
||
|
|
//{
|
||
|
|
int bpId=0;
|
||
|
|
//Debug.Log("Bp "+bpId+" indexOffset "+indexOffset);
|
||
|
|
vtxBodypartHeader vtxBodypart=bodyParts[bpId];
|
||
|
|
//studiobodypart mdlBodypart = mdlBodyParts[bpId];
|
||
|
|
for(int modelId=0; modelId<vtxBodypart.models.Length; modelId++)
|
||
|
|
{
|
||
|
|
vtxModelHeader vtxModel = vtxBodypart.models[modelId];
|
||
|
|
studiomodel mdlModel=mdlBodyParts[bpId].models[modelId];
|
||
|
|
|
||
|
|
if(lodLevel!=-1)
|
||
|
|
{
|
||
|
|
vtxModelLODheader _lod = vtxModel.lods[lodLevel];
|
||
|
|
//Debug.Log ("Lod meshes "+_lod.meshes.Length);
|
||
|
|
for(int meshId=0; meshId<_lod.numMeshes; meshId++)
|
||
|
|
{
|
||
|
|
vtxMeshHeader vtxMesh=_lod.meshes[meshId];
|
||
|
|
studiomesh mdlMesh=mdlModel.meshes[meshId];
|
||
|
|
|
||
|
|
for(int stripGroupId=0; stripGroupId<vtxMesh.numStripGroups; stripGroupId++)
|
||
|
|
{
|
||
|
|
vtxStripGroupHeader stripGroup=vtxMesh.stripGroups[stripGroupId];
|
||
|
|
vtxVertex[] vertTable = stripGroup.verts;
|
||
|
|
|
||
|
|
for(int i=0; i<stripGroup.numIndices;i++)
|
||
|
|
{
|
||
|
|
int vertTableIndex=stripGroup.indexArray[i];
|
||
|
|
int index = vertTable[vertTableIndex].origMeshVertID + mdlModel.verticesoffs + mdlMesh.vertexoffs;
|
||
|
|
//Debug.Log ("Index "+index);
|
||
|
|
if(index<vertCount)//40500)
|
||
|
|
indices[indexOffset]=index;
|
||
|
|
else
|
||
|
|
indices[indexOffset]=0;
|
||
|
|
indexOffset++;
|
||
|
|
}
|
||
|
|
//submeshCount+=stripGroup.numStrips;
|
||
|
|
//submeshCount++;
|
||
|
|
}
|
||
|
|
submeshCount++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
Debug.LogWarning("Lod level is -1");
|
||
|
|
}
|
||
|
|
//}
|
||
|
|
return indices;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*int[] BuildIndices(vtxBodypartHeader vtxBodyPart, int mdlbpindex)
|
||
|
|
{
|
||
|
|
if (lodLevel >= 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; modelId<vtxBodyPart.models.Length; modelId++)
|
||
|
|
{
|
||
|
|
vtxModelHeader vtxModel = vtxBodyPart.models[modelId];
|
||
|
|
studiomodel mdlModel=mdlBodyParts[mdlbpindex].models[modelId];
|
||
|
|
|
||
|
|
if(lodLevel!=-1)
|
||
|
|
{
|
||
|
|
vtxModelLODheader _lod = vtxModel.lods[lodLevel];
|
||
|
|
for(int meshId=0; meshId<_lod.numMeshes; meshId++)
|
||
|
|
{
|
||
|
|
vtxMeshHeader vtxMesh=_lod.meshes[meshId];
|
||
|
|
studiomesh mdlMesh=mdlModel.meshes[meshId];
|
||
|
|
|
||
|
|
for(int stripGroupId=0; stripGroupId<vtxMesh.numStripGroups; stripGroupId++)
|
||
|
|
{
|
||
|
|
vtxStripGroupHeader stripGroup=vtxMesh.stripGroups[stripGroupId];
|
||
|
|
vtxVertex[] vertTable = stripGroup.verts;
|
||
|
|
|
||
|
|
for(int i=0; i<stripGroup.numIndices;i++)
|
||
|
|
{
|
||
|
|
int vertTableIndex=stripGroup.indexArray[i];
|
||
|
|
int index = vertTable[vertTableIndex].origMeshVertID + mdlModel.verticesoffs + mdlMesh.vertexoffs;
|
||
|
|
//Debug.Log ("Index "+index);
|
||
|
|
if(index<40500)
|
||
|
|
indices[indexOffset]=index;
|
||
|
|
else
|
||
|
|
indices[indexOffset]=0;
|
||
|
|
indexOffset++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
Debug.LogWarning("Lod level is -1");
|
||
|
|
}
|
||
|
|
|
||
|
|
return indices;
|
||
|
|
}*/
|
||
|
|
|
||
|
|
int IterateStripGroups(int lodID, vtxBodypartHeader bodyPart)
|
||
|
|
{
|
||
|
|
int indices=0;
|
||
|
|
|
||
|
|
foreach(vtxModelHeader model in bodyPart.models)
|
||
|
|
{
|
||
|
|
if(lodID!=-1&&model.lods.Length>0)
|
||
|
|
{
|
||
|
|
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;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|