public bool Create(SKNFile file, Logger logger) { // This function converts the handedness of the DirectX style input data // into the handedness OpenGL expects. // So, vector inputs have their Z value negated and quaternion inputs have their // Z and W values negated. List <float> vertexPositions = new List <float>(); List <float> vertexNormals = new List <float>(); List <float> vertexTextureCoordinates = new List <float>(); for (int i = 0; i < file.numVertices; ++i) { vertexPositions.Add(file.vertices[i].position[0]); vertexPositions.Add(file.vertices[i].position[1]); vertexPositions.Add(-file.vertices[i].position[2]); vertexNormals.Add(file.vertices[i].normal[0]); vertexNormals.Add(file.vertices[i].normal[1]); vertexNormals.Add(-file.vertices[i].normal[2]); vertexTextureCoordinates.Add(file.vertices[i].texCoords[0]); vertexTextureCoordinates.Add(file.vertices[i].texCoords[1]); } List <uint> iData = new List <uint>(); for (int i = 0; i < numIndices; ++i) { iData.Add((uint)file.indices[i]); } return(Create(vertexPositions, vertexNormals, vertexTextureCoordinates, iData, logger)); }
/// <summary> /// Converts <paramref name="skn"/> to a list of <see cref="MeshGeometry3D"/> /// </summary> /// <param name="skn">The <see cref="SKNFile"/> which should get converted to a <c>Tuple{string, MeshGeometry3D}(submeshName, submeshData)</c></param> /// <returns>A collection of converted <see cref="SKNSubmesh"/></returns> /// <remarks>Normals do not get converted</remarks> public static IEnumerable <Tuple <string, MeshGeometry3D> > ConvertSKN(SKNFile skn) { foreach (SKNSubmesh submesh in skn.Submeshes) { MeshGeometry3D mesh = new MeshGeometry3D(); Int32Collection indices = new Int32Collection(submesh.Indices.Select(x => (int)x)); Point3DCollection vertices = new Point3DCollection(); Vector3DCollection normals = new Vector3DCollection(); PointCollection uvs = new PointCollection(); for (int i = 0; i < submesh.Vertices.Count; i++) { SKNVertex vertex = submesh.Vertices[i]; vertices.Add(new Point3D(vertex.Position.X, vertex.Position.Y, vertex.Position.Z)); normals.Add(new Vector3D(vertex.Normal.X, vertex.Normal.Y, vertex.Normal.Z)); uvs.Add(new Point(vertex.UV.X, vertex.UV.Y)); } mesh.TextureCoordinates = uvs; mesh.Positions = vertices; mesh.Normals = normals; mesh.TriangleIndices = indices; yield return(new Tuple <string, MeshGeometry3D>(submesh.Name, mesh)); } }
public static void Process(string fileLocation, SKNFile skn) { string exportDirectory = string.Format(@"{0}\Uvee_{1}", Path.GetDirectoryName(fileLocation), Path.GetFileNameWithoutExtension(fileLocation)); Directory.CreateDirectory(exportDirectory); foreach (SKNSubmesh submesh in skn.Submeshes) { Image image = CreateImage(); List <ushort> indices = submesh.GetNormalizedIndices(); //Loop through all submesh faces and draw the lines for them using vertex UV for (int i = 0; i < indices.Count;) { SKNVertex vertex1 = submesh.Vertices[indices[i++]]; SKNVertex vertex2 = submesh.Vertices[indices[i++]]; SKNVertex vertex3 = submesh.Vertices[indices[i++]]; PointF[] points = new PointF[] { new PointF(1024 * vertex1.UV.X, 1024 * vertex1.UV.Y), new PointF(1024 * vertex2.UV.X, 1024 * vertex2.UV.Y), new PointF(1024 * vertex3.UV.X, 1024 * vertex3.UV.Y), new PointF(1024 * vertex1.UV.X, 1024 * vertex1.UV.Y) //4th point to close the edge loop }; DrawLines(image, points); } string submeshLocation = string.Format(@"{0}\{1}.png", exportDirectory, submesh.Name); image.SaveAsPng(File.Create(submeshLocation)); } }
/// <summary> /// Converts <paramref name="skn"/> to a <c>Tuple{SCOFile, WGTFile}</c> /// </summary> /// <param name="skn">The <see cref="SKNFile"/> to convert to a <c>Tuple{SCOFile, WGTFile}</c></param> /// <returns>A <c>Tuple{SCOFile, WGTFile}</c> converted from <paramref name="skn"/></returns> public static Tuple <SCOFile, WGTFile> ConvertToLegacy(SKNFile skn) { List <Vector3> vertices = new List <Vector3>(); Dictionary <string, List <SCOFace> > materials = new Dictionary <string, List <SCOFace> >(); List <Vector4Byte> boneIndices = new List <Vector4Byte>(); List <Vector4> weights = new List <Vector4>(); foreach (SKNSubmesh submesh in skn.Submeshes) { List <SCOFace> faces = new List <SCOFace>(); for (int i = 0; i < submesh.Indices.Count; i += 3) { faces.Add(new SCOFace(new uint[] { submesh.Indices[i], submesh.Indices[i + 1], submesh.Indices[i + 2], }, submesh.Name, new Vector2[] { submesh.Vertices[submesh.Indices[i]].UV, submesh.Vertices[submesh.Indices[i + 1]].UV, submesh.Vertices[submesh.Indices[i + 2]].UV, })); } materials.Add(submesh.Name, faces); foreach (SKNVertex vertex in submesh.Vertices) { vertices.Add(vertex.Position); weights.Add(vertex.Weights); boneIndices.Add(vertex.BoneIndices); } } return(new Tuple <SCOFile, WGTFile>(new SCOFile(vertices, materials), new WGTFile(weights, boneIndices))); }
//public static OBJFile VisualiseNVRNodes(NVRFile Nvr) //{ // List<UInt16> Indices = new List<UInt16>(); // List<UInt16> BaseIndices = new List<UInt16>() // { // 0, 1, 2, // 0, 3, 2, // 4, 5, 6, // 4, 7, 6, // 6, 5, 1, // 6, 2, 1, // 0, 4, 7, // 0, 3, 7, // 2, 6, 7, // 2, 3, 7, // 0, 1, 5, // 0, 4, 5 // }; // List<Vector3> Vertices = new List<Vector3>(); // List<NVRNode> Nodes = Nvr.GetNodes(); // foreach (NVRNode Node in Nodes) // { // /* 0 Vector3 minLeftUp = Node.BoundingBox.Min; // 1 Vector3 minRightUp = new Vector3(Node.BoundingBox.Min.X, Node.BoundingBox.Min.Y, Node.BoundingBox.Max.Z); // 2 Vector3 minLeftDown = new Vector3(Node.BoundingBox.Max.X, Node.BoundingBox.Min.Y, Node.BoundingBox.Min.Z); // 3 Vector3 minRightDown = new Vector3(Node.BoundingBox.Max.X, Node.BoundingBox.Min.Y, Node.BoundingBox.Max.Z); // 6 Vector3 maxRightDown = Node.BoundingBox.Max; // 7 Vector3 maxLeftDown = new Vector3(Node.BoundingBox.Max.X, Node.BoundingBox.Max.Y, Node.BoundingBox.Min.Z); // 4 Vector3 maaxLeftUp = new Vector3(Node.BoundingBox.Min.X, Node.BoundingBox.Max.Y, Node.BoundingBox.Min.Z); // 5 Vector3 maxRightUp = new Vector3(Node.BoundingBox.Max.X, Node.BoundingBox.Min.Y, Node.BoundingBox.Max.Z);*/ // Vertices.AddRange(new Vector3[] // { // Node.BoundingBox.Min, // new Vector3(Node.BoundingBox.Min.X, Node.BoundingBox.Min.Y, Node.BoundingBox.Max.Z), // new Vector3(Node.BoundingBox.Max.X, Node.BoundingBox.Min.Y, Node.BoundingBox.Min.Z), // new Vector3(Node.BoundingBox.Max.X, Node.BoundingBox.Min.Y, Node.BoundingBox.Max.Z), // new Vector3(Node.BoundingBox.Min.X, Node.BoundingBox.Max.Y, Node.BoundingBox.Min.Z), // new Vector3(Node.BoundingBox.Max.X, Node.BoundingBox.Min.Y, Node.BoundingBox.Max.Z), // Node.BoundingBox.Max, // new Vector3(Node.BoundingBox.Max.X, Node.BoundingBox.Max.Y, Node.BoundingBox.Min.Z), // }); // } // for (int i = 0; i * 8 < Vertices.Count; i++) // { // Indices.AddRange(BaseIndices); // for (int j = 0; j < BaseIndices.Count; j++) // { // BaseIndices[j] += 8; // } // } // return new OBJFile(Vertices, Indices); //} public static OBJFile ConvertSKN(SKNFile Model) { List <Vector3> Vertices = new List <Vector3>(); List <Vector2> UV = new List <Vector2>(); List <Vector3> Normals = new List <Vector3>(); foreach (SKNVertex Vertex in Model.Vertices) { Vertices.Add(Vertex.Position); UV.Add(Vertex.UV); Normals.Add(Vertex.Normal); } return(new OBJFile(Vertices, UV, Normals, Model.Indices)); }
private bool CreateStaticModel(LOLModel model, Logger logger) { bool result = true; logger.Event("Creating static model."); SKNFile file = new SKNFile(); if (result == true) { // Model is stored in a RAF. result = SKNReader.Read(model.skn, ref file, logger); } staticModel = new GLStaticModel(); if (result == true) { result = staticModel.Create(file, logger); } // // Create Model Texture. // if (result == true) { // Texture stored in RAF file. result = CreateTexture(model.texture, TextureTarget.Texture2D, GLTexture.SupportedImageEncodings.DDS, logger); // Store it in our new model file. if (result == true) { String name = model.texture.FileName; int pos = name.LastIndexOf("/"); name = name.Substring(pos + 1); staticModel.TextureName = name; } } if (result == false) { logger.Error("Failed to create static model."); } return(result); }
public static Tuple <SCOFile, WGTFile> ConvertToLegacy(SKNFile SKN) { List <Vector3> Vertices = new List <Vector3>(); List <Vector2> UV = new List <Vector2>(); List <Vector4Byte> BoneIndices = new List <Vector4Byte>(); List <Vector4> Weights = new List <Vector4>(); foreach (SKNVertex Vertex in SKN.Vertices) { Vertices.Add(Vertex.Position); UV.Add(Vertex.UV); Weights.Add(Vertex.Weights); BoneIndices.Add(Vertex.BoneIndices); } return(new Tuple <SCOFile, WGTFile>(new SCOFile(SKN.Indices, Vertices, UV), new WGTFile(Weights, BoneIndices))); }
public override void writer(MFileObject file, string optionsString, FileAccessMode mode) { if (mode == FileAccessMode.kExportActiveAccessMode) { string sknPath = file.expandedFullName; string sklPath = Path.ChangeExtension(sknPath, ".skl"); SKLFile skl = new SKLFile(true); SKNFile skn = new SKNFile(skl); skl.Write(sklPath); skn.Write(sknPath); } else { MGlobal.displayError("SKNExporter - Wrong File Access Mode: " + mode); } }
/// <summary> /// Converts the Submeshes of the specified <see cref="SKNFile"/> into a List of <see cref="OBJFile"/> /// </summary> /// <param name="model"><see cref="SKNFile"/> to convert</param> public static IEnumerable <Tuple <string, OBJFile> > ConvertSKNModels(SKNFile model) { foreach (SKNSubmesh submesh in model.Submeshes) { List <uint> indices = new List <uint>(); List <Vector3> vertices = new List <Vector3>(); List <Vector2> uv = new List <Vector2>(); List <Vector3> normals = new List <Vector3>(); indices.AddRange(submesh.Indices.Select(i => (uint)i)); foreach (SKNVertex vertex in submesh.Vertices) { vertices.Add(vertex.Position); uv.Add(vertex.UV); normals.Add(vertex.Normal); } yield return(new Tuple <string, OBJFile>(submesh.Name, new OBJFile(vertices, indices, uv, normals))); } }
//public static OBJFile VisualiseNVRNodes(NVRFile Nvr) //{ // List<UInt16> Indices = new List<UInt16>(); // List<UInt16> BaseIndices = new List<UInt16>() // { // 0, 1, 2, // 0, 3, 2, // 4, 5, 6, // 4, 7, 6, // 6, 5, 1, // 6, 2, 1, // 0, 4, 7, // 0, 3, 7, // 2, 6, 7, // 2, 3, 7, // 0, 1, 5, // 0, 4, 5 // }; // List<Vector3> Vertices = new List<Vector3>(); // List<NVRNode> Nodes = Nvr.GetNodes(); // foreach (NVRNode Node in Nodes) // { // /* 0 Vector3 minLeftUp = Node.BoundingBox.Min; // 1 Vector3 minRightUp = new Vector3(Node.BoundingBox.Min.X, Node.BoundingBox.Min.Y, Node.BoundingBox.Max.Z); // 2 Vector3 minLeftDown = new Vector3(Node.BoundingBox.Max.X, Node.BoundingBox.Min.Y, Node.BoundingBox.Min.Z); // 3 Vector3 minRightDown = new Vector3(Node.BoundingBox.Max.X, Node.BoundingBox.Min.Y, Node.BoundingBox.Max.Z); // 6 Vector3 maxRightDown = Node.BoundingBox.Max; // 7 Vector3 maxLeftDown = new Vector3(Node.BoundingBox.Max.X, Node.BoundingBox.Max.Y, Node.BoundingBox.Min.Z); // 4 Vector3 maaxLeftUp = new Vector3(Node.BoundingBox.Min.X, Node.BoundingBox.Max.Y, Node.BoundingBox.Min.Z); // 5 Vector3 maxRightUp = new Vector3(Node.BoundingBox.Max.X, Node.BoundingBox.Min.Y, Node.BoundingBox.Max.Z);*/ // Vertices.AddRange(new Vector3[] // { // Node.BoundingBox.Min, // new Vector3(Node.BoundingBox.Min.X, Node.BoundingBox.Min.Y, Node.BoundingBox.Max.Z), // new Vector3(Node.BoundingBox.Max.X, Node.BoundingBox.Min.Y, Node.BoundingBox.Min.Z), // new Vector3(Node.BoundingBox.Max.X, Node.BoundingBox.Min.Y, Node.BoundingBox.Max.Z), // new Vector3(Node.BoundingBox.Min.X, Node.BoundingBox.Max.Y, Node.BoundingBox.Min.Z), // new Vector3(Node.BoundingBox.Max.X, Node.BoundingBox.Min.Y, Node.BoundingBox.Max.Z), // Node.BoundingBox.Max, // new Vector3(Node.BoundingBox.Max.X, Node.BoundingBox.Max.Y, Node.BoundingBox.Min.Z), // }); // } // for (int i = 0; i * 8 < Vertices.Count; i++) // { // Indices.AddRange(BaseIndices); // for (int j = 0; j < BaseIndices.Count; j++) // { // BaseIndices[j] += 8; // } // } // return new OBJFile(Vertices, Indices); //} /// <summary> /// Converts <paramref name="model"/> to an <see cref="OBJFile"/> /// </summary> /// <param name="model">The <see cref="SKNFile"/> to convert to a <see cref="OBJFile"/></param> /// <returns>An <see cref="OBJFile"/> converted from <paramref name="model"/></returns> public static OBJFile ConvertSKN(SKNFile model) { List <uint> indices = new List <uint>(); List <Vector3> vertices = new List <Vector3>(); List <Vector2> uv = new List <Vector2>(); List <Vector3> normals = new List <Vector3>(); foreach (SKNSubmesh submesh in model.Submeshes) { indices.AddRange(submesh.Indices.Cast <uint>()); foreach (SKNVertex vertex in submesh.Vertices) { vertices.Add(vertex.Position); uv.Add(vertex.UV); normals.Add(vertex.Normal); } } return(new OBJFile(vertices, indices, uv, normals)); }
public override void reader(MFileObject file, string optionsString, FileAccessMode mode) { if (mode == FileAccessMode.kImportAccessMode) { string pathWithoutExtension = file.expandedFullName.Substring(0, file.expandedFullName.LastIndexOf('.')); string name = Path.GetFileNameWithoutExtension(file.expandedFullName).Replace('.', '_'); SKNFile skn = new SKNFile(file.expandedFullName); SKLFile skl = new SKLFile(pathWithoutExtension + ".skl"); MGlobal.displayInfo("SKNImporter:reader - SKN Vertex Count: " + skn.Vertices.Count); MGlobal.displayInfo("SKNImporter:reader - SKN Index Count: " + skn.Indices.Count); MGlobal.displayInfo("SKNImporter:reader - SKN Submesh Count: " + skn.Submeshes.Count); skl.Load(); skn.Load(name, skl); } else { throw new ArgumentException("SKNImporter:reader - Invalid File Access Mode: " + mode, "mode"); } }
/// <summary> /// Loads data from SKN and SKL files into OpenGL. /// </summary> /// <param name="skn">The .skn data.</param> /// <param name="skl">The .skl data.</param> /// <returns></returns> public bool Create(SKNFile skn, SKLFile skl, Dictionary <String, ANMFile> anms, Logger logger) { bool result = true; // This function converts the handedness of the DirectX style input data // into the handedness OpenGL expects. // So, vector inputs have their Z value negated and quaternion inputs have their // Z and W values negated. // Vertex Data List <float> vertexPositions = new List <float>(); List <float> vertexNormals = new List <float>(); List <float> vertexTextureCoordinates = new List <float>(); List <float> vertexBoneIndices = new List <float>(); List <float> vertexBoneWeights = new List <float>(); List <uint> indices = new List <uint>(); // Animation data. List <OpenTK.Quaternion> boneOrientations = new List <OpenTK.Quaternion>(); List <OpenTK.Vector3> bonePositions = new List <OpenTK.Vector3>(); List <float> boneScales = new List <float>(); List <int> boneParents = new List <int>(); List <String> boneNames = new List <String>(); // Bones are not always in order between the ANM and SKL files. Dictionary <String, int> boneNameToID = new Dictionary <String, int>(); Dictionary <int, String> boneIDToName = new Dictionary <int, String>(); for (int i = 0; i < skn.numVertices; ++i) { // Position Information vertexPositions.Add(skn.vertices[i].position[0]); vertexPositions.Add(skn.vertices[i].position[1]); vertexPositions.Add(-skn.vertices[i].position[2]); // Normal Information vertexNormals.Add(skn.vertices[i].normal[0]); vertexNormals.Add(skn.vertices[i].normal[1]); vertexNormals.Add(-skn.vertices[i].normal[2]); // Tex Coords Information vertexTextureCoordinates.Add(skn.vertices[i].texCoords[0]); vertexTextureCoordinates.Add(skn.vertices[i].texCoords[1]); // Bone Index Information for (int j = 0; j < SKNVertex.BONE_INDEX_SIZE; ++j) { vertexBoneIndices.Add(skn.vertices[i].boneIndex[j]); } // Bone Weight Information vertexBoneWeights.Add(skn.vertices[i].weights[0]); vertexBoneWeights.Add(skn.vertices[i].weights[1]); vertexBoneWeights.Add(skn.vertices[i].weights[2]); vertexBoneWeights.Add(skn.vertices[i].weights[3]); } // Animation data for (int i = 0; i < skl.numBones; ++i) { Quaternion orientation = Quaternion.Identity; if (skl.version == 0) { // Version 0 SKLs contain a quaternion. orientation.X = skl.bones[i].orientation[0]; orientation.Y = skl.bones[i].orientation[1]; orientation.Z = -skl.bones[i].orientation[2]; orientation.W = -skl.bones[i].orientation[3]; } else { // Other SKLs contain a rotation matrix. // Create a matrix from the orientation values. Matrix4 transform = Matrix4.Identity; transform.M11 = skl.bones[i].orientation[0]; transform.M21 = skl.bones[i].orientation[1]; transform.M31 = skl.bones[i].orientation[2]; transform.M12 = skl.bones[i].orientation[4]; transform.M22 = skl.bones[i].orientation[5]; transform.M32 = skl.bones[i].orientation[6]; transform.M13 = skl.bones[i].orientation[8]; transform.M23 = skl.bones[i].orientation[9]; transform.M33 = skl.bones[i].orientation[10]; // Convert the matrix to a quaternion. orientation = OpenTKExtras.Matrix4.CreateQuatFromMatrix(transform); orientation.Z = -orientation.Z; orientation.W = -orientation.W; } boneOrientations.Add(orientation); // Create a vector from the position values. Vector3 position = Vector3.Zero; position.X = skl.bones[i].position[0]; position.Y = skl.bones[i].position[1]; position.Z = -skl.bones[i].position[2]; bonePositions.Add(position); boneNames.Add(skl.bones[i].name); boneNameToID[skl.bones[i].name] = i; boneIDToName[i] = skl.bones[i].name; boneScales.Add(skl.bones[i].scale); boneParents.Add(skl.bones[i].parentID); } // // Version 0 SKL files are similar to the animation files. // The bone positions and orientations are relative to their parent. // So, we need to compute their absolute location by hand. // if (skl.version == 0) { // // This algorithm is a little confusing since it's indexing identical data from // the SKL file and the local variable List<>s. The indexing scheme works because // the List<>s are created in the same order as the data in the SKL files. // for (int i = 0; i < skl.numBones; ++i) { // Only update non root bones. if (skl.bones[i].parentID != -1) { // Determine the parent bone. int parentBoneID = skl.bones[i].parentID; // Update orientation. // Append quaternions for rotation transform B * A. boneOrientations[i] = boneOrientations[parentBoneID] * boneOrientations[i]; Vector3 localPosition = Vector3.Zero; localPosition.X = skl.bones[i].position[0]; localPosition.Y = skl.bones[i].position[1]; localPosition.Z = skl.bones[i].position[2]; // Update position. bonePositions[i] = bonePositions[parentBoneID] + Vector3.Transform(localPosition, boneOrientations[parentBoneID]); } } } // Depending on the version of the model, the look ups change. if (skl.version == 2 || skl.version == 0) { for (int i = 0; i < vertexBoneIndices.Count; ++i) { // I don't know why things need remapped, but they do. // Sanity if (vertexBoneIndices[i] < skl.boneIDs.Count) { vertexBoneIndices[i] = skl.boneIDs[(int)vertexBoneIndices[i]]; } } } // Add the animations. foreach (var animation in anms) { if (animations.ContainsKey(animation.Key) == false) { // Create the OpenGL animation wrapper. GLAnimation glAnimation = new GLAnimation(); glAnimation.playbackFPS = animation.Value.playbackFPS; glAnimation.numberOfBones = animation.Value.numberOfBones; glAnimation.numberOfFrames = animation.Value.numberOfFrames; // Convert ANMBone to GLBone. foreach (ANMBone bone in animation.Value.bones) { GLBone glBone = new GLBone(); if (animation.Value.version == 4 && skl.boneIDMap.Count > 0) { // Version 4 ANM files contain a hash value to represent the bone ID/name. // We need to use the map from the SKL file to match the ANM bone with the correct // SKL bone. if (skl.boneIDMap.ContainsKey(bone.id)) { int sklID = (int)skl.boneIDMap[bone.id]; glBone.name = boneIDToName[sklID]; } } else { glBone.name = bone.name; } // Convert ANMFrame to Matrix4. foreach (ANMFrame frame in bone.frames) { Matrix4 transform = Matrix4.Identity; Quaternion quat = new Quaternion(frame.orientation[0], frame.orientation[1], -frame.orientation[2], -frame.orientation[3]); transform = Matrix4.Rotate(quat); transform.M41 = frame.position[0]; transform.M42 = frame.position[1]; transform.M43 = -frame.position[2]; glBone.frames.Add(transform); } glAnimation.bones.Add(glBone); } glAnimation.timePerFrame = 1.0f / (float)animation.Value.playbackFPS; // Store the animation. animations.Add(animation.Key, glAnimation); } } // Index Information for (int i = 0; i < skn.numIndices; ++i) { indices.Add((uint)skn.indices[i]); } this.numIndices = indices.Count; // // Compute the final animation transforms. // foreach (var animation in animations) { // This is sort of a mess. // We need to make sure "parent" bones are always updated before their "children". The SKL file contains // bones ordered in this manner. However, ANM files do not always do this. So, we sort the bones in the ANM to match the ordering in // the SKL file. animation.Value.bones.Sort((a, b) => { if (boneNameToID.ContainsKey(a.name) && boneNameToID.ContainsKey(b.name)) { return(boneNameToID[a.name].CompareTo(boneNameToID[b.name])); } else if (boneNameToID.ContainsKey(a.name) == false) { return(1); } else { return(-1); } }); } // Create the binding transform. (The SKL initial transform.) GLAnimation bindingBones = new GLAnimation(); for (int i = 0; i < boneOrientations.Count; ++i) { GLBone bone = new GLBone(); bone.name = boneNames[i]; bone.parent = boneParents[i]; bone.transform = Matrix4.Rotate(boneOrientations[i]); bone.transform.M41 = bonePositions[i].X; bone.transform.M42 = bonePositions[i].Y; bone.transform.M43 = bonePositions[i].Z; bone.transform = Matrix4.Invert(bone.transform); bindingBones.bones.Add(bone); } // Convert animations into absolute space. foreach (var animation in animations) { foreach (var bone in animation.Value.bones) { // Sanity. if (boneNameToID.ContainsKey(bone.name)) { int id = boneNameToID[bone.name]; bone.parent = bindingBones.bones[id].parent; // For each frame... for (int i = 0; i < bone.frames.Count; ++i) { Matrix4 parentTransform = Matrix4.Identity; if (bone.parent >= 0) { if (bone.parent < animation.Value.bones.Count) { GLBone parent = animation.Value.bones[bone.parent]; parentTransform = parent.frames[i]; } } bone.frames[i] = bone.frames[i] * parentTransform; } } } } // Multiply the animation transforms by the binding transform. foreach (var animation in animations) { foreach (var bone in animation.Value.bones) { // Sanity. if (boneNameToID.ContainsKey(bone.name)) { int id = boneNameToID[bone.name]; GLBone bindingBone = bindingBones.bones[id]; for (int i = 0; i < bone.frames.Count; ++i) { bone.frames[i] = bindingBone.transform * bone.frames[i]; } } } } // Create the OpenGL objects. result = Create(vertexPositions, vertexNormals, vertexTextureCoordinates, vertexBoneIndices, vertexBoneWeights, indices, logger); return(result); }
static void SKNTest() { SKNFile skn = new SKNFile("Pyke_Base.Pyke.skn"); }
private void handle(WADEntry entry, string namePath) { if (namePath.ToLower().EndsWith(".dds")) { if (mode == 0) { mode = 1; _viewPort.Visibility = Visibility.Collapsed; _previewImage.Visibility = Visibility.Visible; _previewTextureComboBox.IsEnabled = false; _previewMeshesComboBox.IsEnabled = false; } _previewTypeLabel.Content = "Type: DirectDraw Surface"; _previewNameLabel.Content = "Name: " + namePath.Split('/').Last(); var stream = new MemoryStream(); var image = DDS.LoadImage(entry.GetContent(true)); image.Save(stream, ImageFormat.Png); var imageSource = new BitmapImage(); imageSource.CacheOption = BitmapCacheOption.OnLoad; imageSource.BeginInit(); imageSource.StreamSource = stream; imageSource.EndInit(); imageSource.Freeze(); _previewImage.Dispatcher.BeginInvoke(new Action(() => { _previewImage.Source = imageSource; _previewImage.Width = image.Width; _previewImage.Height = image.Height; })); return; } if (mode == 1) { mode = 0; _previewImage.Visibility = Visibility.Collapsed; _viewPort.Visibility = Visibility.Visible; } clearUp(); _previewTextureComboBox.IsEnabled = true; _previewMeshesComboBox.IsEnabled = true; if (!_previewExpander.IsExpanded) { _previewExpander.IsExpanded = true; } if (namePath.ToLower().EndsWith(".scb")) { _previewMeshesComboBox.IsEnabled = false; var model = applyMesh(new SCBFile(new MemoryStream(entry.GetContent(true)))); _previewTypeLabel.Content = "Type: Static Object Binary"; _previewNameLabel.Content = "Name: " + namePath.Split('/').Last(); if (PreSelect != null) { foreach (var wadEntry in window.Wad.Entries) { if (wadEntry.XXHash == PreSelect.Item2) { applyMaterial(wadEntry, PreSelect.Item1, model); break; } } PreSelect = null; } else { applyMaterial(model); } return; } if (namePath.ToLower().EndsWith(".sco")) { _previewMeshesComboBox.IsEnabled = false; var model = applyMesh(new SCOFile(new MemoryStream(entry.GetContent(true)))); _previewTypeLabel.Content = "Type: Static Object Mesh"; _previewNameLabel.Content = "Name: " + namePath.Split('/').Last(); if (PreSelect != null) { foreach (var wadEntry in window.Wad.Entries) { if (wadEntry.XXHash == PreSelect.Item2) { applyMaterial(wadEntry, PreSelect.Item1, model); break; } } PreSelect = null; } else { applyMaterial(model); } return; } var result = generateInfoHolder(namePath); if (result == null) { return; } var skn = new SKNFile(new MemoryStream(result.sknPath.GetContent(true))); foreach (var subMesh in skn.Submeshes) { var model = applyMesh(subMesh); _previewNameLabel.Content = "Name: " + namePath.Split('/').Last(); _previewTypeLabel.Content = "Type: Simple Skin Mesh"; if (PreSelect != null) { foreach (var wadEntry in window.Wad.Entries) { if (wadEntry.XXHash == PreSelect.Item2) { applyMaterial(wadEntry, PreSelect.Item1, model); break; } } } else { if (result.textures.Count > 0) { applyMaterial(result.textures.First().Value, result.textures.First().Key, model); } else { applyMaterial(model); } } } PreSelect = null; }
private bool CreateRiggedModel(LOLModel model, Logger logger) { bool result = true; logger.Event("Creating rigged model."); // Open the skn file. SKNFile sknFile = new SKNFile(); if (result == true) { result = SKNReader.Read(model.skn, ref sknFile, logger); } // Open the skl file. SKLFile sklFile = new SKLFile(); if (result == true) { result = SKLReader.Read(model.skl, ref sklFile, logger); } // Open the anm files. Dictionary <String, ANMFile> anmFiles = new Dictionary <String, ANMFile>(); if (result == true) { foreach (var a in model.animations) { ANMFile anmFile = new ANMFile(); bool anmResult = ANMReader.Read(a.Value, ref anmFile, logger); if (anmResult == true) { anmFiles.Add(a.Key, anmFile); } } } // Create the model. riggedModel = new GLRiggedModel(); if (result == true) { result = riggedModel.Create(sknFile, sklFile, anmFiles, logger); } // Set up an initial animation. if (result == true) { if (anmFiles.Count > 0) { riggedModel.SetCurrentAnimation(anmFiles.First().Key); riggedModel.SetCurrentFrame(0, 0); } } // // Create Model Texture. // if (result == true) { // Texture stored in RAF file. result = CreateTexture(model.texture, TextureTarget.Texture2D, GLTexture.SupportedImageEncodings.DDS, logger); // Store it in our new model file. if (result == true) { String name = model.texture.FileName; int pos = name.LastIndexOf("/"); name = name.Substring(pos + 1); riggedModel.TextureName = name; } } if (result == false) { logger.Error("Failed to create rigged model."); } return(result); }
/// <summary> /// 导出skn为obj /// </summary> /// <param name="selectedPath"></param> /// <param name="entries"></param> private void ExtractWADEntriesObj(string selectedPath, List <WADEntry> entries) { this.progressBarWadExtraction.Maximum = entries.Count; this.IsEnabled = false; BackgroundWorker wadExtractor = new BackgroundWorker { WorkerReportsProgress = true }; wadExtractor.ProgressChanged += (sender, args) => { this.progressBarWadExtraction.Value = args.ProgressPercentage; }; wadExtractor.DoWork += (sender, e) => { Dictionary <string, byte[]> fileEntries = new Dictionary <string, byte[]>(); double progress = 0; bool createPackedMappingFile = false; string packedMappingFileContent = ""; foreach (WADEntry entry in entries) { byte[] entryData = entry.GetContent(true); string entryName; if (StringDictionary.ContainsKey(entry.XXHash)) { entryName = StringDictionary[entry.XXHash]; if (Regex.IsMatch(entryName, @"^DATA/.*_Skins_Skin.*\.bin$")) { createPackedMappingFile = true; entryName = entry.XXHash.ToString("X16") + ".bin"; packedMappingFileContent += string.Format("{0} = {1}\n", entryName, StringDictionary[entry.XXHash]); } else { Directory.CreateDirectory(Path.Combine(selectedPath, Path.GetDirectoryName(entryName) ?? "")); } } else { entryName = entry.XXHash.ToString("X16") + "." + Utilities.GetEntryExtension(Utilities.GetLeagueFileExtensionType(entryData)); } fileEntries.Add(entryName, entryData); progress += 0.5; wadExtractor.ReportProgress((int)progress); } if ((bool)this.Config["ParallelExtraction"]) { Parallel.ForEach(fileEntries, entry => { //File.WriteAllBytes(Path.Combine(selectedPath, entry.Key), entry.Value); SKNFile sknFile = new SKNFile(new MemoryStream(entry.Value)); sknFile.Write(Path.Combine(selectedPath, entry.Key)); progress += 0.5; wadExtractor.ReportProgress((int)progress); }); } else { foreach (KeyValuePair <string, byte[]> entry in fileEntries) { File.WriteAllBytes(Path.Combine(selectedPath, entry.Key), entry.Value); progress += 0.5; wadExtractor.ReportProgress((int)progress); } } if (createPackedMappingFile) { File.WriteAllText(Path.Combine(selectedPath, "OBSIDIAN_PACKED_MAPPING.txt"), packedMappingFileContent); } }; wadExtractor.RunWorkerCompleted += (sender, args) => { if (args.Error != null) { MessageBox.Show(string.Format("An error occured:\n{0}", args.Error), "", MessageBoxButton.OK, MessageBoxImage.Error); Logger.Error(string.Format("WAD extraction failed:\n{0}", args.Error)); } else { MessageBox.Show("Extraction Successful!", "", MessageBoxButton.OK, MessageBoxImage.Information); Logger.Info("WAD Extraction Successful!"); } this.progressBarWadExtraction.Maximum = 100; this.progressBarWadExtraction.Value = 100; this.IsEnabled = true; }; wadExtractor.RunWorkerAsync(); }