public void OnEnable() { FoxModel foxModel = target as FoxModel; meshGroupsLength = foxModel.meshGroups.Length; meshDefinitionsLength = foxModel.meshDefinitions.Length; currentControlID = GUIUtility.keyboardControl; } //OnEnable
} //OnImportAsset public void ReadWithoutAssetImportContext(string filePath) { Fmdl fmdl = new Fmdl(Path.GetFileNameWithoutExtension(filePath)); fmdl.Read(filePath); int boneCount = fmdl.fmdlBones != null ? fmdl.fmdlBones.Length : 0; int materialCount = fmdl.fmdlMaterialInstances.Length; int textureCount = fmdl.fmdlTextures != null ? fmdl.fmdlTextures.Length : 0; int meshCount = fmdl.fmdlMeshInfos.Length; int meshGroupCount = fmdl.fmdlMeshGroups.Length; GameObject mainObject = new GameObject(fmdl.name); FoxModel foxModel = mainObject.AddComponent<FoxModel>(); foxModel.meshGroups = new FoxMeshGroup[meshGroupCount]; foxModel.meshDefinitions = new FoxMeshDefinition[meshCount]; Transform[] bones = new Transform[boneCount]; Texture[] textures = new Texture[textureCount]; Material[] materials = new Material[materialCount]; Mesh[] meshes = new Mesh[meshCount]; Transform rootBone = new GameObject().transform; rootBone.name = "[Root]"; rootBone.parent = mainObject.transform; Read(fmdl, mainObject, foxModel, bones, textures, materials, meshes, rootBone); } //ReadWithoutAssetImportContext
} //LoadTextureDXT private void ReadWithAssetImportContext(AssetImportContext ctx, string filePath) { Fmdl fmdl = new Fmdl(Path.GetFileNameWithoutExtension(filePath)); fmdl.Read(filePath); int boneCount = fmdl.fmdlBones != null ? fmdl.fmdlBones.Length : 0; int materialCount = fmdl.fmdlMaterialInstances.Length; int textureCount = fmdl.fmdlTextures != null ? fmdl.fmdlTextures.Length : 0; int meshCount = fmdl.fmdlMeshInfos.Length; int meshGroupCount = fmdl.fmdlMeshGroups.Length; GameObject mainObject = new GameObject(fmdl.name); FoxModel foxModel = mainObject.AddComponent<FoxModel>(); foxModel.meshGroups = new FoxMeshGroup[meshGroupCount]; foxModel.meshDefinitions = new FoxMeshDefinition[meshCount]; Transform[] bones = new Transform[boneCount]; Texture[] textures = new Texture[textureCount]; Material[] materials = new Material[materialCount]; Mesh[] meshes = new Mesh[meshCount]; Transform rootBone = new GameObject().transform; rootBone.name = "[Root]"; rootBone.parent = mainObject.transform; Read(fmdl, mainObject, foxModel, bones, textures, materials, meshes, rootBone); ctx.AddObjectToAsset("mainObject", mainObject); ctx.SetMainObject(mainObject); for (int i = 0; i < textureCount; i++) ctx.AddObjectToAsset($"Texture {i}", textures[i]); for (int i = 0; i < materialCount; i++) ctx.AddObjectToAsset($"Material {i}", materials[i]); for (int i = 0; i < meshCount; i++) ctx.AddObjectToAsset($"Mesh {i}", meshes[i]); } //ReadWithAssetImportContext
} //ReadWithAssetImportContext private void Read(Fmdl fmdl, GameObject mainObject, FoxModel foxModel, Transform[] bones, Texture[] textures, Material[] materials, Mesh[] meshes, Transform rootBone) { bool isGZFormat = fmdl.version == 2.03f; int boneCount = fmdl.fmdlBones != null ? fmdl.fmdlBones.Length : 0; int materialCount = fmdl.fmdlMaterialInstances.Length; int textureCount = fmdl.fmdlTextures != null ? fmdl.fmdlTextures.Length : 0; int meshCount = fmdl.fmdlMeshInfos.Length; int meshGroupCount = fmdl.fmdlMeshGroups.Length; { Fmdl.FmdlBoundingBox fmdlBoundingBox = fmdl.fmdlBoundingBoxes[0]; Bounds bounds = new Bounds(); bounds.SetMinMax(new Vector3(-fmdlBoundingBox.min.x, fmdlBoundingBox.min.y, fmdlBoundingBox.min.z), new Vector3(-fmdlBoundingBox.max.x, fmdlBoundingBox.max.y, fmdlBoundingBox.max.z)); BoxCollider boxCollider = rootBone.gameObject.AddComponent<BoxCollider>(); boxCollider.center = rootBone.InverseTransformPoint(bounds.center); boxCollider.size = bounds.size; } //code block for (int i = 0; i < boneCount; i++) { bones[i] = new GameObject().transform; Fmdl.FmdlBone fmdlBone = fmdl.fmdlBones[i]; Fmdl.FmdlBoundingBox fmdlBoundingBox = fmdl.fmdlBoundingBoxes[fmdlBone.boundingBoxIndex]; //Get the name. if (isGZFormat) bones[i].gameObject.name = fmdl.fmdlStrings[fmdlBone.nameIndex]; else bones[i].gameObject.name = Hashing.TryGetStringName(fmdl.fmdlStrCode64s[fmdlBone.nameIndex]); try { UInt64.Parse(bones[i].gameObject.name, System.Globalization.NumberStyles.HexNumber); bones[i].name = $"SKL_{(Int32.Parse(bones[i - 1].name.Substring(4, 3)) + 1).ToString("000")}_UNKNOWN ({bones[i].name})"; } //try catch { } //Assign the parent. if (fmdlBone.parentIndex != -1) bones[i].parent = bones[fmdlBone.parentIndex]; else bones[i].parent = rootBone.transform; bones[i].position = new Vector3(-fmdlBone.worldPosition.x, fmdlBone.worldPosition.y, fmdlBone.worldPosition.z); //Set up the bounding box. Bounds bounds = new Bounds(); //The x min and max are swapped here on purpose! The max value will end up as the smallest value and the min value will end up as the largest value if they aren't swapped here! bounds.SetMinMax(new Vector3(-fmdlBoundingBox.max.x, fmdlBoundingBox.min.y, fmdlBoundingBox.min.z), new Vector3(-fmdlBoundingBox.min.x, fmdlBoundingBox.max.y, fmdlBoundingBox.max.z)); BoxCollider boxCollider = bones[i].gameObject.AddComponent<BoxCollider>(); boxCollider.center = bones[i].InverseTransformPoint(bounds.center); boxCollider.size = bounds.size; } //for for (int i = 0; i < textureCount; i++) { string name; Fmdl.FmdlTexture fmdlTexture = fmdl.fmdlTextures[i]; //Get the name. if (isGZFormat) { name = fmdl.fmdlStrings[fmdlTexture.pathIndex] + fmdl.fmdlStrings[fmdlTexture.nameIndex]; name = name.Substring(0, name.IndexOf(".")) + ".dds"; } //if else name = Hashing.TryGetPathName(fmdl.fmdlPathCode64s[fmdlTexture.pathIndex]) + ".dds"; //Read the file. if (File.Exists($"{Globals.GetTexturePath()}\\{name}")) textures[i] = LoadTextureDXT($"{Globals.GetTexturePath()}\\{name}"); else { Debug.LogWarning($"Could not find {Globals.GetTexturePath()}\\{name}"); Texture2D texture = new Texture2D(512, 512); for (int j = 0; j < 512; j++) for (int h = 0; h < 512; h++) { Color c = new Color(0.25f, 0.25f, 0.25f); if (((j / 32) % 2 == 0 && (h / 32) % 2 != 0) || ((j / 32) % 2 != 0 && (h / 32) % 2 == 0)) c = new Color(0.5f, 0.5f, 0.5f); texture.SetPixel(j, h, c); } //for texture.Apply(); textures[i] = texture; } //else textures[i].name = name; } //for for (int i = 0; i < materialCount; i++) { string shaderName; string materialName; Fmdl.FmdlMaterialInstance fmdlMaterialInstance = fmdl.fmdlMaterialInstances[i]; //Get the shader and material name. if (isGZFormat) { shaderName = fmdl.fmdlStrings[fmdl.fmdlMaterials[fmdlMaterialInstance.materialIndex].typeIndex]; materialName = fmdl.fmdlStrings[fmdlMaterialInstance.nameIndex]; } //if else { shaderName = Hashing.TryGetStringName(fmdl.fmdlStrCode64s[fmdl.fmdlMaterials[fmdlMaterialInstance.materialIndex].typeIndex]); materialName = Hashing.TryGetStringName(fmdl.fmdlStrCode64s[fmdlMaterialInstance.nameIndex]); } //else //Some ombs models have broken, unused, materials in them. Try catch here is necessary to handle them. try { materials[i] = new Material(Shader.Find($"FoxShaders/{shaderName}")); } //try catch { materials[i] = new Material(Shader.Find($"FoxShaders/fox3DDF_Blin_LNM")); Debug.LogWarning($"Material {materialName} trying to use missing shader: {shaderName}! Defaulting to fox3DDF_Blin_LNM!"); } //catch materials[i].name = materialName; //Link textures. for (int j = fmdlMaterialInstance.firstTextureIndex; j < fmdlMaterialInstance.firstTextureIndex + fmdlMaterialInstance.textureCount; j++) { string textureType; Fmdl.FmdlMaterialParameter fmdlMaterialParameter = fmdl.fmdlMaterialParameters[j]; if (isGZFormat) textureType = fmdl.fmdlStrings[fmdlMaterialParameter.nameIndex]; else textureType = Hashing.TryGetStringName(fmdl.fmdlStrCode64s[fmdlMaterialParameter.nameIndex]); materials[i].SetTexture($"_{textureType}", textures[fmdlMaterialParameter.referenceIndex]); materials[i].SetTextureScale($"_{textureType}", new Vector2(1, -1)); //Have to flip textures here because Texture2D.LoadRawData is bugged an imports DDS files upside down. } //for //Set parameters. for (int j = fmdlMaterialInstance.firstParameterIndex; j < fmdlMaterialInstance.firstParameterIndex + fmdlMaterialInstance.parameterCount; j++) { string parameterName; Fmdl.FmdlMaterialParameter fmdlMaterialParameter = fmdl.fmdlMaterialParameters[j]; if (isGZFormat) parameterName = fmdl.fmdlStrings[fmdlMaterialParameter.nameIndex]; else parameterName = Hashing.TryGetStringName(fmdl.fmdlStrCode64s[fmdlMaterialParameter.nameIndex]); materials[i].SetVector($"_{parameterName}", fmdl.fmdlMaterialParameterVectors[fmdlMaterialParameter.referenceIndex]); } //for } //for for (int i = 0; i < meshGroupCount; i++) { foxModel.meshGroups[i] = new FoxMeshGroup(); string name; Fmdl.FmdlMeshGroup fmdlMeshGroup = fmdl.fmdlMeshGroups[i]; if (isGZFormat) name = fmdl.fmdlStrings[fmdlMeshGroup.nameIndex]; else name = Hashing.TryGetStringName(fmdl.fmdlStrCode64s[fmdlMeshGroup.nameIndex]); foxModel.meshGroups[i].name = name; foxModel.meshGroups[i].parent = fmdlMeshGroup.parentIndex; if (fmdlMeshGroup.invisibilityFlag == 0) foxModel.meshGroups[i].visible = true; else foxModel.meshGroups[i].visible = false; } //for for (int i = 0; i < meshCount; i++) { meshes[i] = new Mesh(); GameObject gameObject = new GameObject(); gameObject.transform.parent = mainObject.transform; SkinnedMeshRenderer skinnedMeshRenderer = gameObject.AddComponent<SkinnedMeshRenderer>(); foxModel.meshDefinitions[i] = new FoxMeshDefinition(); Fmdl.FmdlMesh fmdlMesh = fmdl.fmdlMeshes[i]; Fmdl.FmdlMeshInfo fmdlMeshInfo = fmdl.fmdlMeshInfos[i]; Fmdl.FmdlBoneGroup fmdlBoneGroup = fmdl.fmdlBoneGroups != null ? fmdl.fmdlBoneGroups[fmdlMeshInfo.boneGroupIndex] : new Fmdl.FmdlBoneGroup(); int vertexLength = fmdlMesh.vertices.Length; int faceLength = fmdlMesh.triangles.Length; string name; Vector3[] vertices = new Vector3[vertexLength]; Vector3[] normals = new Vector3[vertexLength]; Vector4[] tangents = fmdlMesh.tangents != null ? new Vector4[vertexLength] : new Vector4[0]; Color[] colors = fmdlMesh.colors != null ? new Color[vertexLength] : new Color[0]; BoneWeight[] boneWeights = fmdlMesh.boneWeights != null ? new BoneWeight[vertexLength] : new BoneWeight[0]; Vector2[] uv = fmdlMesh.uv != null ? new Vector2[vertexLength] : new Vector2[0]; Vector2[] uv2 = fmdlMesh.uv2 != null ? new Vector2[vertexLength] : new Vector2[0]; Vector2[] uv3 = fmdlMesh.uv3 != null ? new Vector2[vertexLength] : new Vector2[0]; Vector2[] uv4 = fmdlMesh.uv4 != null ? new Vector2[vertexLength] : new Vector2[0]; int[] triangles = new int[faceLength]; Matrix4x4[] bindPoses; List<Transform> usedBones = new List<Transform>(0); Transform[] usedBonesArray; for (int j = 0; j < vertexLength; j++) { vertices[j] = new Vector3(-fmdlMesh.vertices[j].x, fmdlMesh.vertices[j].y, fmdlMesh.vertices[j].z); normals[j] = new Vector3(-fmdlMesh.normals[j].x, fmdlMesh.normals[j].y, fmdlMesh.normals[j].z); if (tangents.Length > 0) tangents[j] = new Vector4(-fmdlMesh.tangents[j].x, fmdlMesh.tangents[j].y, fmdlMesh.tangents[j].z, fmdlMesh.tangents[j].w); if (colors.Length > 0) colors[j] = new Color(fmdlMesh.colors[j].x / 255f, fmdlMesh.colors[j].y / 255f, fmdlMesh.colors[j].z / 255f, fmdlMesh.colors[j].w / 255f); if (boneWeights.Length > 0) { boneWeights[j].weight0 = fmdlMesh.boneWeights[j].x / 255f; boneWeights[j].weight1 = fmdlMesh.boneWeights[j].y / 255f; boneWeights[j].weight2 = fmdlMesh.boneWeights[j].z / 255f; boneWeights[j].weight3 = fmdlMesh.boneWeights[j].w / 255f; boneWeights[j].boneIndex0 = fmdlBoneGroup.boneIndices[(int)fmdlMesh.boneIndices[j].x]; boneWeights[j].boneIndex1 = fmdlBoneGroup.boneIndices[(int)fmdlMesh.boneIndices[j].y]; boneWeights[j].boneIndex2 = fmdlBoneGroup.boneIndices[(int)fmdlMesh.boneIndices[j].z]; boneWeights[j].boneIndex3 = fmdlBoneGroup.boneIndices[(int)fmdlMesh.boneIndices[j].w]; } //if if (uv.Length > 0) uv[j] = new Vector2(fmdlMesh.uv[j].x, 1 - fmdlMesh.uv[j].y); if (uv2.Length > 0) uv2[j] = new Vector2(fmdlMesh.uv2[j].x, 1 - fmdlMesh.uv2[j].y); if (uv3.Length > 0) uv3[j] = new Vector2(fmdlMesh.uv3[j].x, 1 - fmdlMesh.uv3[j].y); if (uv4.Length > 0) uv4[j] = new Vector2(fmdlMesh.uv4[j].x, 1 - fmdlMesh.uv4[j].y); } //for for (int j = 0; j < faceLength; j++) triangles[j] = fmdlMesh.triangles[j]; for (int j = 0; j < boneWeights.Length; j++) { if (boneWeights[j].weight0 > 0f) { if (usedBones.Contains(bones[boneWeights[j].boneIndex0])) boneWeights[j].boneIndex0 = usedBones.IndexOf(bones[boneWeights[j].boneIndex0]); else { usedBones.Add(bones[boneWeights[j].boneIndex0]); boneWeights[j].boneIndex0 = usedBones.IndexOf(bones[boneWeights[j].boneIndex0]); } //else } //if else boneWeights[j].boneIndex0 = 0; if (boneWeights[j].weight1 > 0f) { if (usedBones.Contains(bones[boneWeights[j].boneIndex1])) boneWeights[j].boneIndex1 = usedBones.IndexOf(bones[boneWeights[j].boneIndex1]); else { usedBones.Add(bones[boneWeights[j].boneIndex1]); boneWeights[j].boneIndex1 = usedBones.IndexOf(bones[boneWeights[j].boneIndex1]); } //else } //if else boneWeights[j].boneIndex1 = 0; if (boneWeights[j].weight2 > 0f) { if (usedBones.Contains(bones[boneWeights[j].boneIndex2])) boneWeights[j].boneIndex2 = usedBones.IndexOf(bones[boneWeights[j].boneIndex2]); else { usedBones.Add(bones[boneWeights[j].boneIndex2]); boneWeights[j].boneIndex2 = usedBones.IndexOf(bones[boneWeights[j].boneIndex2]); } //else } //if else boneWeights[j].boneIndex2 = 0; if (boneWeights[j].weight3 > 0f) { if (usedBones.Contains(bones[boneWeights[j].boneIndex3])) boneWeights[j].boneIndex3 = usedBones.IndexOf(bones[boneWeights[j].boneIndex3]); else { usedBones.Add(bones[boneWeights[j].boneIndex3]); boneWeights[j].boneIndex3 = usedBones.IndexOf(bones[boneWeights[j].boneIndex3]); } //else } //if else boneWeights[j].boneIndex3 = 0; } //for usedBonesArray = usedBones.ToArray(); bindPoses = new Matrix4x4[usedBonesArray.Length]; for (int j = 0; j < usedBonesArray.Length; j++) bindPoses[j] = usedBones[j].worldToLocalMatrix * gameObject.transform.localToWorldMatrix; meshes[i].vertices = vertices; meshes[i].normals = normals; meshes[i].tangents = tangents; meshes[i].colors = colors; meshes[i].boneWeights = boneWeights; meshes[i].uv = uv; meshes[i].uv2 = uv2; meshes[i].uv3 = uv3; meshes[i].uv4 = uv4; meshes[i].triangles = triangles; meshes[i].bindposes = bindPoses; skinnedMeshRenderer.bones = usedBonesArray; skinnedMeshRenderer.sharedMaterial = materials[fmdlMeshInfo.materialInstanceIndex]; skinnedMeshRenderer.sharedMesh = meshes[i]; skinnedMeshRenderer.rootBone = mainObject.transform; foxModel.meshDefinitions[i].mesh = meshes[i]; foxModel.meshDefinitions[i].meshGroup = Array.Find(fmdl.fmdlMeshGroupEntries, x => x.firstMeshIndex <= i && x.firstMeshIndex + x.meshCount > i).meshGroupIndex; foxModel.meshDefinitions[i].alpha = (FoxMeshDefinition.Alpha)fmdlMeshInfo.alphaEnum; foxModel.meshDefinitions[i].shadow = (FoxMeshDefinition.Shadow)fmdlMeshInfo.shadowEnum; if (isGZFormat) name = fmdl.fmdlStrings[fmdl.fmdlMeshGroups[foxModel.meshDefinitions[i].meshGroup].nameIndex]; else name = Hashing.TryGetStringName(fmdl.fmdlStrCode64s[fmdl.fmdlMeshGroups[foxModel.meshDefinitions[i].meshGroup].nameIndex]); gameObject.name = $"{i} - {name}"; } //for } //Read
public GameObject GetDataFromFmdl(OldFmdl fmdl) { meshes = new UnityMesh[fmdl.section0Block3Entries.Count]; GameObject fmdlGameObject = new GameObject(); fmdlGameObject.name = fmdl.name; GameObject[] subFmdlGameObjects = new GameObject[fmdl.objects.Count]; Transform[] bones; //Matrix4x4[] bindPoses; Bounds[] bounds = new Bounds[fmdl.section0BlockDEntries.Count]; FoxModel foxModel = fmdlGameObject.AddComponent<FoxModel>(); foxModel.meshGroups = new FoxMeshGroup[fmdl.section0Block1Entries.Count]; foxModel.meshDefinitions = new FoxMeshDefinition[fmdl.objects.Count]; Material[] materials = new Material[fmdl.section0Block4Entries.Count]; if (fmdl.bonesIndex != -1) { bones = new Transform[fmdl.section0Block0Entries.Count]; //bindPoses = new Matrix4x4[fmdl.section0Block0Entries.Count]; } //if else { bones = new Transform[0]; //bindPoses = new Matrix4x4[0]; } //else //Mesh Groups for (int i = 0; i < fmdl.section0Block1Entries.Count; i++) { FoxMeshGroup foxMeshGroup = new FoxMeshGroup(); if (fmdl.stringsIndex != -1) foxMeshGroup.name = fmdl.strings[fmdl.section0Block1Entries[i].stringId]; else foxMeshGroup.name = Hashing.TryGetStringName(fmdl.section0Block16Entries[fmdl.section0Block1Entries[i].stringId]); foxMeshGroup.parent = (short)fmdl.section0Block1Entries[i].parentId; if (fmdl.section0Block1Entries[i].invisibilityFlag == 0) foxMeshGroup.visible = true; else foxMeshGroup.visible = false; foxModel.meshGroups[i] = foxMeshGroup; } //for //Materials for (int i = 0; i < fmdl.section0Block4Entries.Count; i++) { if (fmdl.stringsIndex != -1) materials[i] = new Material(Shader.Find($"FoxShaders/{fmdl.strings[fmdl.section0Block8Entries[fmdl.section0Block4Entries[i].materialId].typeId]}")); else materials[i] = new Material(Shader.Find($"FoxShaders/{Hashing.TryGetStringName(fmdl.section0Block16Entries[fmdl.section0Block8Entries[fmdl.section0Block4Entries[i].materialId].typeId])}")); //materials[i].material = new Material(Shader.Find("Legacy Shaders/Transparent/Cutout/Bumped Diffuse")); //materials[i].material = new Material(Shader.Find("Standard")); if (fmdl.stringsIndex != -1) { materials[i].name = fmdl.strings[fmdl.section0Block4Entries[i].stringId]; for (int j = fmdl.section0Block4Entries[i].firstTextureId; j < fmdl.section0Block4Entries[i].firstTextureId + fmdl.section0Block4Entries[i].numTextures; j++) { string textureName = ""; string textureType = fmdl.strings[fmdl.section0Block7Entries[j].stringId]; int extensionLocation; textureName = fmdl.strings[fmdl.section0Block6Entries[fmdl.section0Block7Entries[j].referenceId].pathId] + fmdl.strings[fmdl.section0Block6Entries[fmdl.section0Block7Entries[j].referenceId].stringId]; //materials[i].textureType = fmdl.strings[fmdl.section0Block7Entries[fmdl.section0Block4Entries[i].firstTextureId].stringId]; extensionLocation = textureName.IndexOf('.'); textureName = textureName.Substring(0, extensionLocation); if (File.Exists(Globals.texturePath + "\\" + textureName + ".dds")) { Texture2D texture = LoadTextureDXT(Globals.texturePath + "\\" + textureName + ".dds"); texture.name = textureName + ".dds"; materials[i].SetTexture(textureType, texture); } //if else { Debug.Log("Could not find: " + Globals.texturePath + "\\" + textureName + ".dds"); } //else } //for for (int j = fmdl.section0Block4Entries[i].firstParameterId; j < fmdl.section0Block4Entries[i].firstParameterId + fmdl.section0Block4Entries[i].numParameters; j++) materials[i].SetVector(fmdl.strings[fmdl.section0Block7Entries[j].stringId], new Vector4(fmdl.materialParameters[fmdl.section0Block7Entries[j].referenceId].values.x, fmdl.materialParameters[fmdl.section0Block7Entries[j].referenceId].values.y, fmdl.materialParameters[fmdl.section0Block7Entries[j].referenceId].values.z, fmdl.materialParameters[fmdl.section0Block7Entries[j].referenceId].values.w)); } //if else { materials[i].name = Hashing.TryGetStringName(fmdl.section0Block16Entries[fmdl.section0Block4Entries[i].stringId]); if (fmdl.texturePathsIndex != -1) { for (int j = fmdl.section0Block4Entries[i].firstTextureId; j < fmdl.section0Block4Entries[i].firstTextureId + fmdl.section0Block4Entries[i].numTextures; j++) { string textureName = Hashing.TryGetPathName(fmdl.section0Block15Entries[fmdl.section0Block7Entries[j].referenceId]); string textureType = Hashing.TryGetStringName(fmdl.section0Block16Entries[fmdl.section0Block7Entries[j].stringId]); if (File.Exists(Globals.texturePath + "\\" + textureName + ".dds")) { Texture2D texture = LoadTextureDXT(Globals.texturePath + "\\" + textureName + ".dds"); texture.name = textureName + ".dds"; materials[i].SetTexture(textureType, texture); } //if else { Debug.Log("Could not find: " + Globals.texturePath + "\\" + textureName + ".dds"); } //else } //for } //if for (int j = fmdl.section0Block4Entries[i].firstParameterId; j < fmdl.section0Block4Entries[i].firstParameterId + fmdl.section0Block4Entries[i].numParameters; j++) materials[i].SetVector(Hashing.TryGetStringName(fmdl.section0Block16Entries[fmdl.section0Block7Entries[j].stringId]), new Vector4(fmdl.materialParameters[fmdl.section0Block7Entries[j].referenceId].values[0], fmdl.materialParameters[fmdl.section0Block7Entries[j].referenceId].values[1], fmdl.materialParameters[fmdl.section0Block7Entries[j].referenceId].values[2], fmdl.materialParameters[fmdl.section0Block7Entries[j].referenceId].values[3])); } //else //Have to flip textures here because Texture2D.LoadRawData is bugged an imports DDS files upside down. for (int j = 0; j < ShaderUtil.GetPropertyCount(materials[i].shader); j++) if (ShaderUtil.GetPropertyType(materials[i].shader, j) == ShaderUtil.ShaderPropertyType.TexEnv) materials[i].SetTextureScale(ShaderUtil.GetPropertyName(materials[i].shader, j), new Vector2(1, -1)); } //for for (int i = 0; i < bounds.Length; i++) { bounds[i].SetMinMax(new Vector3(-fmdl.section0BlockDEntries[i].minX, fmdl.section0BlockDEntries[i].minY, fmdl.section0BlockDEntries[i].minZ), new Vector3(-fmdl.section0BlockDEntries[i].maxX, fmdl.section0BlockDEntries[i].maxY, fmdl.section0BlockDEntries[i].maxZ)); } //for Transform rootBone = new GameObject("[Root]").transform; //From what I can tell, the real name is "". But it looks kinda dumb having "" as its name; so using "[Root]" as a placeholder seems better. rootBone.parent = fmdlGameObject.transform; { BoxCollider collider = rootBone.gameObject.AddComponent<BoxCollider>(); collider.center = rootBone.InverseTransformPoint(bounds[0].center); //Have to convert these to local positions. They're stored as world positions. collider.size = bounds[0].size; } //code block for (int i = 0; i < bones.Length; i++) { bones[i] = new GameObject().transform; bones[i].position = new Vector3(-fmdl.section0Block0Entries[i].worldPositionX, fmdl.section0Block0Entries[i].worldPositionY, fmdl.section0Block0Entries[i].worldPositionZ); BoxCollider collider = bones[i].gameObject.AddComponent<BoxCollider>(); collider.center = bones[i].InverseTransformPoint(bounds[fmdl.section0Block0Entries[i].boundingBoxId].center); //Have to convert these to local positions. They're stored as world positions. collider.size = bounds[fmdl.section0Block0Entries[i].boundingBoxId].size; if (fmdl.stringsIndex != -1) bones[i].name = fmdl.strings[fmdl.section0Block0Entries[i].stringId]; else bones[i].name = Hashing.TryGetStringName(fmdl.section0Block16Entries[fmdl.section0Block0Entries[i].stringId]); if (fmdl.section0Block0Entries[i].parentId != 0xFFFF) bones[i].parent = bones[fmdl.section0Block0Entries[i].parentId]; else bones[i].parent = rootBone; } //for for (int i = 0; i < fmdl.objects.Count; i++) { int lod = 0; //Temporary solution. 0 loads the normal faces. 1 loads the first set of LOD faces. 2 loads the next set. Etc.... meshes[i].vertices = new Vector3[fmdl.objects[i].vertices.Length]; meshes[i].normals = new Vector3[fmdl.objects[i].additionalVertexData.Length]; meshes[i].tangents = new Vector4[fmdl.objects[i].additionalVertexData.Length]; meshes[i].colour = new Color[fmdl.objects[i].additionalVertexData.Length]; meshes[i].uv = new Vector2[fmdl.objects[i].additionalVertexData.Length]; meshes[i].uv2 = new Vector2[fmdl.objects[i].additionalVertexData.Length]; meshes[i].uv3 = new Vector2[fmdl.objects[i].additionalVertexData.Length]; meshes[i].uv4 = new Vector2[fmdl.objects[i].additionalVertexData.Length]; //meshes[i].faces = new int[fmdl.objects[i].faces.Length * 3]; meshes[i].faces = new int[fmdl.objects[i].lodFaces[lod].Length * 3]; meshes[i].boneWeights = new BoneWeight[fmdl.objects[i].additionalVertexData.Length]; //Position for (int j = 0; j < fmdl.objects[i].vertices.Length; j++) meshes[i].vertices[j] = new Vector3(-fmdl.objects[i].vertices[j].x, fmdl.objects[i].vertices[j].y, fmdl.objects[i].vertices[j].z); //Normals, Bone Weights, Bone Group Ids and UVs for (int j = 0; j < fmdl.objects[i].additionalVertexData.Length; j++) { meshes[i].normals[j] = new Vector3(-fmdl.objects[i].additionalVertexData[j].normalX, fmdl.objects[i].additionalVertexData[j].normalY, fmdl.objects[i].additionalVertexData[j].normalZ); meshes[i].tangents[j] = new Vector4(-fmdl.objects[i].additionalVertexData[j].tangentX, fmdl.objects[i].additionalVertexData[j].tangentY, fmdl.objects[i].additionalVertexData[j].tangentZ, fmdl.objects[i].additionalVertexData[j].tangentW); meshes[i].colour[j] = new Color(fmdl.objects[i].additionalVertexData[j].colourR, fmdl.objects[i].additionalVertexData[j].colourG, fmdl.objects[i].additionalVertexData[j].colourB, fmdl.objects[i].additionalVertexData[j].colourA); if (fmdl.bonesIndex != -1) { meshes[i].boneWeights[j].weight0 = fmdl.objects[i].additionalVertexData[j].boneWeightX; meshes[i].boneWeights[j].weight1 = fmdl.objects[i].additionalVertexData[j].boneWeightY; meshes[i].boneWeights[j].weight2 = fmdl.objects[i].additionalVertexData[j].boneWeightZ; meshes[i].boneWeights[j].weight3 = fmdl.objects[i].additionalVertexData[j].boneWeightW; meshes[i].boneWeights[j].boneIndex0 = fmdl.section0Block5Entries[fmdl.section0Block3Entries[i].boneGroupId].entries[fmdl.objects[i].additionalVertexData[j].boneGroup0Id]; meshes[i].boneWeights[j].boneIndex1 = fmdl.section0Block5Entries[fmdl.section0Block3Entries[i].boneGroupId].entries[fmdl.objects[i].additionalVertexData[j].boneGroup1Id]; meshes[i].boneWeights[j].boneIndex2 = fmdl.section0Block5Entries[fmdl.section0Block3Entries[i].boneGroupId].entries[fmdl.objects[i].additionalVertexData[j].boneGroup2Id]; meshes[i].boneWeights[j].boneIndex3 = fmdl.section0Block5Entries[fmdl.section0Block3Entries[i].boneGroupId].entries[fmdl.objects[i].additionalVertexData[j].boneGroup3Id]; } //if meshes[i].uv[j] = new Vector2(fmdl.objects[i].additionalVertexData[j].textureU, -fmdl.objects[i].additionalVertexData[j].textureV); meshes[i].uv2[j] = new Vector2(fmdl.objects[i].additionalVertexData[j].unknownU0, -fmdl.objects[i].additionalVertexData[j].unknownV0); meshes[i].uv3[j] = new Vector2(fmdl.objects[i].additionalVertexData[j].unknownU1, -fmdl.objects[i].additionalVertexData[j].unknownV1); meshes[i].uv4[j] = new Vector2(fmdl.objects[i].additionalVertexData[j].unknownU2, -fmdl.objects[i].additionalVertexData[j].unknownV2); } //for //Faces /*for (int j = 0, h = 0; j < fmdl.objects[i].faces.Length; j++, h += 3) { meshes[i].faces[h] = fmdl.objects[i].faces[j].vertex1Id; meshes[i].faces[h + 1] = fmdl.objects[i].faces[j].vertex2Id; meshes[i].faces[h + 2] = fmdl.objects[i].faces[j].vertex3Id; } //for*/ for (int j = 0, h = 0; j < fmdl.objects[i].lodFaces[lod].Length; j++, h += 3) { meshes[i].faces[h] = fmdl.objects[i].lodFaces[lod][j].vertex1Id; meshes[i].faces[h + 1] = fmdl.objects[i].lodFaces[lod][j].vertex2Id; meshes[i].faces[h + 2] = fmdl.objects[i].lodFaces[lod][j].vertex3Id; } //for //Render the mesh in Unity. subFmdlGameObjects[i] = new GameObject(); FoxMeshDefinition foxMeshDefinition = new FoxMeshDefinition(); foxMeshDefinition.alpha = (FoxMeshDefinition.Alpha)fmdl.section0Block3Entries[i].alphaEnum; foxMeshDefinition.shadow = (FoxMeshDefinition.Shadow)fmdl.section0Block3Entries[i].shadowEnum; //Get the mesh name. for (int j = 0; j < fmdl.section0Block2Entries.Count; j++) { if (i >= fmdl.section0Block2Entries[j].firstObjectId && i < fmdl.section0Block2Entries[j].firstObjectId + fmdl.section0Block2Entries[j].numObjects) { if (fmdl.stringsIndex != -1) subFmdlGameObjects[i].name = i + " - " + fmdl.strings[fmdl.section0Block1Entries[fmdl.section0Block2Entries[j].meshGroupId].stringId]; else subFmdlGameObjects[i].name = i + " - " + Hashing.TryGetStringName(fmdl.section0Block16Entries[fmdl.section0Block1Entries[fmdl.section0Block2Entries[j].meshGroupId].stringId]); foxMeshDefinition.meshGroup = fmdl.section0Block2Entries[j].meshGroupId; break; } //if } //for subFmdlGameObjects[i].transform.parent = fmdlGameObject.transform; SkinnedMeshRenderer meshRenderer = subFmdlGameObjects[i].AddComponent<SkinnedMeshRenderer>(); meshRenderer.sharedMaterial = materials[fmdl.section0Block3Entries[i].materialInstanceId]; Mesh mesh = new Mesh(); mesh.vertices = meshes[i].vertices; mesh.uv = meshes[i].uv; mesh.uv2 = meshes[i].uv2; mesh.uv3 = meshes[i].uv3; mesh.uv4 = meshes[i].uv4; mesh.normals = meshes[i].normals; mesh.tangents = meshes[i].tangents; mesh.triangles = meshes[i].faces; mesh.boneWeights = meshes[i].boneWeights; //Sets up the model to only use weighted bones. Transform[] boneArray = bones; List<Transform> usedBones = new List<Transform>(0); BoneWeight[] weightArray = meshes[i].boneWeights; int boneCount = boneArray.Length; int weightCount = weightArray.Length; for (int j = 0; j < boneCount; j++) { bool found = false; for (int h = 0; h < weightCount; h++) { if (weightArray[h].boneIndex0 == j) { found = true; if (!usedBones.Contains(boneArray[j])) weightArray[h].boneIndex0 = usedBones.Count; else weightArray[h].boneIndex0 = usedBones.IndexOf(boneArray[j]); } //if if (weightArray[h].boneIndex1 == j) { found = true; if (!usedBones.Contains(boneArray[j])) weightArray[h].boneIndex1 = usedBones.Count; else weightArray[h].boneIndex1 = usedBones.IndexOf(boneArray[j]); } //if if (weightArray[h].boneIndex2 == j) { found = true; if (!usedBones.Contains(boneArray[j])) weightArray[h].boneIndex2 = usedBones.Count; else weightArray[h].boneIndex2 = usedBones.IndexOf(boneArray[j]); } //if if (weightArray[h].boneIndex3 == j) { found = true; if (!usedBones.Contains(boneArray[j])) weightArray[h].boneIndex3 = usedBones.Count; else weightArray[h].boneIndex3 = usedBones.IndexOf(boneArray[j]); } //if } //for if (found) if (!usedBones.Contains(boneArray[j])) usedBones.Add(boneArray[j]); } //for mesh.boneWeights = weightArray; meshRenderer.bones = usedBones.ToArray(); boneCount = usedBones.Count; List<Matrix4x4> bindPoses = new List<Matrix4x4>(0); for (int j = 0; j < boneCount; j++) { bindPoses.Add(usedBones[j].worldToLocalMatrix * subFmdlGameObjects[i].transform.localToWorldMatrix); } //for mesh.bindposes = bindPoses.ToArray(); meshRenderer.sharedMesh = mesh; foxMeshDefinition.mesh = meshRenderer.sharedMesh; foxModel.meshDefinitions[i] = foxMeshDefinition; subFmdlGameObjects[i].AddComponent<MeshCollider>(); } //for return fmdlGameObject; } //GetDataFromFmdl
/// <summary> /// Returns true if the given model is ignored. /// </summary> /// <param name="model">The model to check.</param> /// <returns>True if the given model is ignored.</returns> public bool IsModelIgnored(FoxModel model) { return(this.ignoredModels.Contains(model)); }
/// <summary> /// Ignores a model. An ignored model will never have a SceneProxy created for it. /// </summary> /// <param name="model">The model to ignore.</param> public void IgnoreModel(FoxModel model) { this.ignoredModels.Add(model); }
} //OnEnable public override void OnInspectorGUI() { FoxModel foxModel = target as FoxModel; serializedObject.Update(); serializedObject.FindProperty("meshGroups").isExpanded = EditorGUILayout.Foldout(serializedObject.FindProperty("meshGroups").isExpanded, "Mesh Groups", true); if (serializedObject.FindProperty("meshGroups").isExpanded) { meshGroupsLength = EditorGUILayout.IntField("Size", meshGroupsLength); if (currentControlID != GUIUtility.keyboardControl) { foxModel.meshGroups = SetArraySize(foxModel.meshGroups, meshGroupsLength); currentControlID = GUIUtility.keyboardControl; serializedObject.Update(); } //if for (int i = 0; i < foxModel.meshGroups.Length; i++) { serializedObject.FindProperty("meshGroups").GetArrayElementAtIndex(i).isExpanded = EditorGUILayout.Foldout(serializedObject.FindProperty("meshGroups").GetArrayElementAtIndex(i).isExpanded, $"Element {i}", true); if (serializedObject.FindProperty("meshGroups").GetArrayElementAtIndex(i).isExpanded) { string[] meshGroupStrings = new string[i + 1]; meshGroupStrings[0] = "No Parent"; for (int j = 0; j < i; j++) meshGroupStrings[j + 1] = foxModel.meshGroups[j].name; foxModel.meshGroups[i].name = EditorGUILayout.TextField("Name", foxModel.meshGroups[i].name); foxModel.meshGroups[i].parent = (short)(EditorGUILayout.Popup("Parent", foxModel.meshGroups[i].parent + 1, meshGroupStrings) - 1); foxModel.meshGroups[i].visible = EditorGUILayout.Toggle("Is Visible", foxModel.meshGroups[i].visible); } //if } //for } //if serializedObject.FindProperty("meshDefinitions").isExpanded = EditorGUILayout.Foldout(serializedObject.FindProperty("meshDefinitions").isExpanded, "Mesh Definitions", true); if (serializedObject.FindProperty("meshDefinitions").isExpanded) { meshDefinitionsLength = EditorGUILayout.IntField("Size", meshDefinitionsLength); if (currentControlID != GUIUtility.keyboardControl) { foxModel.meshDefinitions = SetArraySize(foxModel.meshDefinitions, meshDefinitionsLength); currentControlID = GUIUtility.keyboardControl; serializedObject.Update(); } //if for (int i = 0; i < foxModel.meshDefinitions.Length; i++) { serializedObject.FindProperty("meshDefinitions").GetArrayElementAtIndex(i).isExpanded = EditorGUILayout.Foldout(serializedObject.FindProperty("meshDefinitions").GetArrayElementAtIndex(i).isExpanded, $"Element {i}", true); if (serializedObject.FindProperty("meshDefinitions").GetArrayElementAtIndex(i).isExpanded) { string[] meshGroupStrings = new string[foxModel.meshGroups.Length]; for (int j = 0; j < foxModel.meshGroups.Length; j++) meshGroupStrings[j] = foxModel.meshGroups[j].name; foxModel.meshDefinitions[i].mesh = (Mesh)EditorGUILayout.ObjectField("Mesh", foxModel.meshDefinitions[i].mesh, typeof(Mesh), true); foxModel.meshDefinitions[i].meshGroup = EditorGUILayout.Popup("Mesh Group", foxModel.meshDefinitions[i].meshGroup, meshGroupStrings); foxModel.meshDefinitions[i].alpha = (FoxMeshDefinition.Alpha)EditorGUILayout.EnumPopup("Alpha", foxModel.meshDefinitions[i].alpha); foxModel.meshDefinitions[i].shadow = (FoxMeshDefinition.Shadow)EditorGUILayout.EnumPopup("Shadow", foxModel.meshDefinitions[i].shadow); } //if } //for } //if } //OnInspectorGUI