/// <summary> /// Adds tressfx hair to this instance. used for merging! /// </summary> /// <param name="h"></param> public void AddTressFXHair(TressFXHair h) { List<TressFXStrand> strands = new List<TressFXStrand>(this.strands); strands.AddRange(h.strands); // Recalculate vertex count and lowestVertexPerStrandCount and highestVertexPerStrandCount int vertices = 0; int lowestVertexCount = 0; int highestVertexCount = 0; foreach (TressFXStrand s in strands) { vertices += s.vertices.Length; if (lowestVertexCount == 0 || lowestVertexCount > s.vertices.Length) { lowestVertexCount = s.vertices.Length; } if (highestVertexCount == 0 || highestVertexCount < s.vertices.Length) { highestVertexCount = s.vertices.Length; } } // Set values this.strands = strands; this.vertexCount = vertices; this.lowestVertexPerStrandCount = lowestVertexCount; this.highestVertexPerStrandCount = highestVertexCount; }
/// <summary> /// Load hair menu strip item. /// Gets used for... loading hair... /// Seems like captain obvious hit again :D /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void menu_loadHair_Click(object sender, EventArgs e) { OpenFileDialog ofd = new OpenFileDialog(); ofd.Title = "Open TressFX Hairfile"; if (ofd.ShowDialog() == DialogResult.OK) { string filename = System.IO.Path.GetFileName(ofd.FileName); TressFXHair hair = new TressFXHair(); hair.LoadTressFXFile(ofd.FileName); hairMeshes.Add(Path.GetFileNameWithoutExtension(ofd.FileName), hair); this.UpdateHairGuiInfos(); } }
/// <summary> /// Converts a given ase file to a dictionary of tressfx hairs. /// Key of the dictionary contains the mesh name, value is the tressfxhair data. /// </summary> /// <param name="asefile"></param> /// <param name="hairFilePrefix"></param> /// <param name="directory"></param> /// <returns></returns> public static Dictionary<string, TressFXHair> ConvertAse(string asefile) { // Start parsing the file ConsoleUtil.LogToConsole("Loading ASE File...", ConsoleColor.Blue); string[] aseContent = File.ReadAllLines(asefile); Dictionary<string, TressFXHair> hairMeshes = new Dictionary<string, TressFXHair>(); List<TressFXStrand> currentStrands = new List<TressFXStrand>(); string aseFilenameWithoutExt = Path.GetFileNameWithoutExtension(asefile); int currentStrand = 0; int currentHairId = -1; float texcoordMultiplier = 0; ConsoleUtil.LogToConsole("Starting ASE parsing... This may take a LONG while..", ConsoleColor.Blue); // Now the hard part begins... for (int i = 0; i < aseContent.Length; i++) { string[] tokens = aseContent[i].Split('\t'); if (aseContent[i].Contains("*SHAPE_LINECOUNT")) { tokens = tokens[1].Split(' '); } else if (aseContent[i].Contains("SHAPE_LINE")) { tokens = tokens[1].Split(' '); } if (tokens.Length >= 2) { if (tokens[0] == "*SHAPE_LINECOUNT") { if (currentStrand > 0) { currentHairId++; currentStrand = 0; // Add to mesh list TressFXHair hairMesh = new TressFXHair(); foreach (TressFXStrand strand in currentStrands) { hairMesh.AddStrand(strand); } hairMeshes.Add(aseFilenameWithoutExt + "_" + currentHairId, hairMesh); // Clear current strands currentStrands.Clear(); texcoordMultiplier = 1.0f / (float)int.Parse(tokens[1]); ConsoleUtil.LogToConsole("Starting parse hair: " + currentHairId + ", lines count: " + int.Parse(tokens[1]), ConsoleColor.Yellow); } } else if (tokens[0] == "*SHAPE_LINE") { // Parse the current line Vector3[] positions = null; string[] vertexCountTokens = aseContent[i + 1].Split(' '); positions = new Vector3[int.Parse(vertexCountTokens[1])]; // Parse vertices for (int j = 0; j < positions.Length; j++) { string[] vertexTokens = aseContent[i + 2 + j].Replace('.', ',').Split('\t'); positions[j] = new Vector3(float.Parse(vertexTokens[4]), float.Parse(vertexTokens[5]), float.Parse(vertexTokens[6])); } TressFXStrand strand = new TressFXStrand(); strand.vertices = positions; strand.texcoordX = texcoordMultiplier * currentStrand; currentStrands.Add(strand); i = i + 1 + positions.Length; currentStrand++; } } } ConsoleUtil.LogToConsole("Asefile Parsed! Hairs parsed: " + currentHairId + "!", ConsoleColor.Green); return hairMeshes; }