diff --git a/Unity Studio/7zip/7z.dll b/Unity Studio/7zip/7z.dll new file mode 100644 index 0000000..cea996e Binary files /dev/null and b/Unity Studio/7zip/7z.dll differ diff --git a/Unity Studio/AssetsFile.cs b/Unity Studio/AssetsFile.cs index 725e0d2..2c221e9 100644 --- a/Unity Studio/AssetsFile.cs +++ b/Unity Studio/AssetsFile.cs @@ -53,20 +53,20 @@ namespace Unity_Studio switch (fileGen) { - case 6: + case 6://2.5.0 - 2.6.1 { a_Stream.Position = (dataEnd - tableSize); a_Stream.Position += 1; break; } - case 7://Unity 3 beta + case 7://3.0.0 beta { a_Stream.Position = (dataEnd - tableSize); a_Stream.Position += 1; m_Version = a_Stream.ReadStringToNull(); break; } - case 8: + case 8://3.0.0 - 3.4.2 { a_Stream.Position = (dataEnd - tableSize); a_Stream.Position += 1; @@ -74,15 +74,15 @@ namespace Unity_Studio platform = a_Stream.ReadInt32(); break; } - case 9: + case 9://3.5.0 - 4.6.x { a_Stream.Position += 4;//azero m_Version = a_Stream.ReadStringToNull(); platform = a_Stream.ReadInt32(); break; } - case 14: - case 15://not fully tested! + case 14://5.0.0 beta and final + case 15://5.0.1 and up { a_Stream.Position += 4;//azero m_Version = a_Stream.ReadStringToNull(); diff --git a/Unity Studio/FBXExport.Designer.cs b/Unity Studio/ExportOptions.Designer.cs similarity index 87% rename from Unity Studio/FBXExport.Designer.cs rename to Unity Studio/ExportOptions.Designer.cs index d27f706..8a3c63f 100644 --- a/Unity Studio/FBXExport.Designer.cs +++ b/Unity Studio/ExportOptions.Designer.cs @@ -29,10 +29,11 @@ private void InitializeComponent() { this.includeBox = new System.Windows.Forms.GroupBox(); + this.convertDummies = new System.Windows.Forms.CheckBox(); this.embedBox = new System.Windows.Forms.CheckBox(); this.lightsBox = new System.Windows.Forms.CheckBox(); this.camerasBox = new System.Windows.Forms.CheckBox(); - this.animationBox = new System.Windows.Forms.CheckBox(); + this.exportDeformers = new System.Windows.Forms.CheckBox(); this.geometryBox = new System.Windows.Forms.GroupBox(); this.exportColors = new System.Windows.Forms.CheckBox(); this.exportUVs = new System.Windows.Forms.CheckBox(); @@ -56,23 +57,35 @@ // includeBox // this.includeBox.AutoSize = true; + this.includeBox.Controls.Add(this.convertDummies); this.includeBox.Controls.Add(this.embedBox); this.includeBox.Controls.Add(this.lightsBox); this.includeBox.Controls.Add(this.camerasBox); - this.includeBox.Controls.Add(this.animationBox); + this.includeBox.Controls.Add(this.exportDeformers); this.includeBox.Controls.Add(this.geometryBox); - this.includeBox.Location = new System.Drawing.Point(13, 13); + this.includeBox.Location = new System.Drawing.Point(12, 12); this.includeBox.Name = "includeBox"; - this.includeBox.Size = new System.Drawing.Size(359, 262); + this.includeBox.Size = new System.Drawing.Size(360, 285); this.includeBox.TabIndex = 0; this.includeBox.TabStop = false; this.includeBox.Text = "Include"; // + // convertDummies + // + this.convertDummies.AutoSize = true; + this.convertDummies.Location = new System.Drawing.Point(14, 178); + this.convertDummies.Name = "convertDummies"; + this.convertDummies.Size = new System.Drawing.Size(205, 17); + this.convertDummies.TabIndex = 5; + this.convertDummies.Text = "Convert Deforming Dummies to Bones"; + this.convertDummies.UseVisualStyleBackColor = true; + this.convertDummies.CheckedChanged += new System.EventHandler(this.exportOpnions_CheckedChanged); + // // embedBox // this.embedBox.AutoSize = true; this.embedBox.Enabled = false; - this.embedBox.Location = new System.Drawing.Point(14, 226); + this.embedBox.Location = new System.Drawing.Point(14, 249); this.embedBox.Name = "embedBox"; this.embedBox.Size = new System.Drawing.Size(91, 17); this.embedBox.TabIndex = 4; @@ -83,7 +96,7 @@ // this.lightsBox.AutoSize = true; this.lightsBox.Enabled = false; - this.lightsBox.Location = new System.Drawing.Point(14, 202); + this.lightsBox.Location = new System.Drawing.Point(14, 225); this.lightsBox.Name = "lightsBox"; this.lightsBox.Size = new System.Drawing.Size(54, 17); this.lightsBox.TabIndex = 3; @@ -94,23 +107,23 @@ // this.camerasBox.AutoSize = true; this.camerasBox.Enabled = false; - this.camerasBox.Location = new System.Drawing.Point(14, 178); + this.camerasBox.Location = new System.Drawing.Point(14, 201); this.camerasBox.Name = "camerasBox"; this.camerasBox.Size = new System.Drawing.Size(67, 17); this.camerasBox.TabIndex = 2; this.camerasBox.Text = "Cameras"; this.camerasBox.UseVisualStyleBackColor = true; // - // animationBox + // exportDeformers // - this.animationBox.AutoSize = true; - this.animationBox.Enabled = false; - this.animationBox.Location = new System.Drawing.Point(14, 154); - this.animationBox.Name = "animationBox"; - this.animationBox.Size = new System.Drawing.Size(72, 17); - this.animationBox.TabIndex = 1; - this.animationBox.Text = "Animation"; - this.animationBox.UseVisualStyleBackColor = true; + this.exportDeformers.AutoSize = true; + this.exportDeformers.Location = new System.Drawing.Point(14, 154); + this.exportDeformers.Name = "exportDeformers"; + this.exportDeformers.Size = new System.Drawing.Size(98, 17); + this.exportDeformers.TabIndex = 1; + this.exportDeformers.Text = "Skin Deformers"; + this.exportDeformers.UseVisualStyleBackColor = true; + this.exportDeformers.CheckedChanged += new System.EventHandler(this.exportDeformers_CheckedChanged); // // geometryBox // @@ -155,7 +168,6 @@ // exportTangents // this.exportTangents.AutoSize = true; - this.exportTangents.Enabled = false; this.exportTangents.Location = new System.Drawing.Point(7, 44); this.exportTangents.Name = "exportTangents"; this.exportTangents.Size = new System.Drawing.Size(71, 17); @@ -184,7 +196,7 @@ this.advancedBox.Controls.Add(this.upAxis); this.advancedBox.Controls.Add(this.scaleFactor); this.advancedBox.Controls.Add(this.scaleLabel); - this.advancedBox.Location = new System.Drawing.Point(12, 281); + this.advancedBox.Location = new System.Drawing.Point(12, 303); this.advancedBox.Name = "advancedBox"; this.advancedBox.Size = new System.Drawing.Size(360, 80); this.advancedBox.TabIndex = 5; @@ -240,7 +252,7 @@ // // fbxOKbutton // - this.fbxOKbutton.Location = new System.Drawing.Point(216, 367); + this.fbxOKbutton.Location = new System.Drawing.Point(216, 389); this.fbxOKbutton.Name = "fbxOKbutton"; this.fbxOKbutton.Size = new System.Drawing.Size(75, 23); this.fbxOKbutton.TabIndex = 6; @@ -251,7 +263,7 @@ // fbxCancel // this.fbxCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; - this.fbxCancel.Location = new System.Drawing.Point(297, 367); + this.fbxCancel.Location = new System.Drawing.Point(297, 389); this.fbxCancel.Name = "fbxCancel"; this.fbxCancel.Size = new System.Drawing.Size(75, 23); this.fbxCancel.TabIndex = 7; @@ -267,11 +279,11 @@ // showExpOpt // this.showExpOpt.AutoSize = true; - this.showExpOpt.Location = new System.Drawing.Point(12, 371); + this.showExpOpt.Location = new System.Drawing.Point(12, 393); this.showExpOpt.Name = "showExpOpt"; - this.showExpOpt.Size = new System.Drawing.Size(127, 17); + this.showExpOpt.Size = new System.Drawing.Size(179, 17); this.showExpOpt.TabIndex = 8; - this.showExpOpt.Text = "Show for each export"; + this.showExpOpt.Text = "Show this dialog for every export"; this.showExpOpt.UseVisualStyleBackColor = true; // // ExportOptions @@ -280,7 +292,7 @@ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.CancelButton = this.fbxCancel; - this.ClientSize = new System.Drawing.Size(384, 401); + this.ClientSize = new System.Drawing.Size(384, 421); this.Controls.Add(this.showExpOpt); this.Controls.Add(this.fbxCancel); this.Controls.Add(this.fbxOKbutton); @@ -315,7 +327,7 @@ private System.Windows.Forms.CheckBox embedBox; private System.Windows.Forms.CheckBox lightsBox; private System.Windows.Forms.CheckBox camerasBox; - private System.Windows.Forms.CheckBox animationBox; + private System.Windows.Forms.CheckBox exportDeformers; private System.Windows.Forms.GroupBox geometryBox; private System.Windows.Forms.CheckBox exportColors; private System.Windows.Forms.CheckBox exportUVs; @@ -327,5 +339,6 @@ private System.Windows.Forms.Button fbxCancel; private System.Windows.Forms.SaveFileDialog saveFileDialog1; private System.Windows.Forms.CheckBox showExpOpt; + private System.Windows.Forms.CheckBox convertDummies; } } \ No newline at end of file diff --git a/Unity Studio/FBXExport.cs b/Unity Studio/ExportOptions.cs similarity index 80% rename from Unity Studio/FBXExport.cs rename to Unity Studio/ExportOptions.cs index 9fb9ec1..25a401a 100644 --- a/Unity Studio/FBXExport.cs +++ b/Unity Studio/ExportOptions.cs @@ -21,6 +21,8 @@ namespace Unity_Studio exportTangents.Checked = (bool)Properties.Settings.Default["exportTangents"]; exportUVs.Checked = (bool)Properties.Settings.Default["exportUVs"]; exportColors.Checked = (bool)Properties.Settings.Default["exportColors"]; + exportDeformers.Checked = (bool)Properties.Settings.Default["exportDeformers"]; + convertDummies.Checked = (bool)Properties.Settings.Default["convertDummies"]; scaleFactor.Value = (decimal)Properties.Settings.Default["scaleFactor"]; upAxis.SelectedIndex = (int)Properties.Settings.Default["upAxis"]; showExpOpt.Checked = (bool)Properties.Settings.Default["showExpOpt"]; @@ -38,6 +40,7 @@ namespace Unity_Studio Properties.Settings.Default["exportTangents"] = exportTangents.Checked; Properties.Settings.Default["exportUVs"] = exportUVs.Checked; Properties.Settings.Default["exportColors"] = exportColors.Checked; + Properties.Settings.Default["exportDeformers"] = exportDeformers.Checked; Properties.Settings.Default["scaleFactor"] = scaleFactor.Value; Properties.Settings.Default["upAxis"] = upAxis.SelectedIndex; this.DialogResult = DialogResult.OK; @@ -49,5 +52,11 @@ namespace Unity_Studio this.DialogResult = DialogResult.Cancel; this.Close(); } + + private void exportDeformers_CheckedChanged(object sender, EventArgs e) + { + exportOpnions_CheckedChanged(sender, e); + convertDummies.Enabled = exportDeformers.Checked; + } } } diff --git a/Unity Studio/FBXExport.resx b/Unity Studio/ExportOptions.resx similarity index 100% rename from Unity Studio/FBXExport.resx rename to Unity Studio/ExportOptions.resx diff --git a/Unity Studio/FMOD Studio API/fmod.dll b/Unity Studio/FMOD Studio API/fmod.dll new file mode 100644 index 0000000..64e485b Binary files /dev/null and b/Unity Studio/FMOD Studio API/fmod.dll differ diff --git a/Unity Studio/Properties/Settings.Designer.cs b/Unity Studio/Properties/Settings.Designer.cs index 2dd45cc..feff695 100644 --- a/Unity Studio/Properties/Settings.Designer.cs +++ b/Unity Studio/Properties/Settings.Designer.cs @@ -166,5 +166,29 @@ namespace Unity_Studio.Properties { this["showExpOpt"] = value; } } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("True")] + public bool exportDeformers { + get { + return ((bool)(this["exportDeformers"])); + } + set { + this["exportDeformers"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("True")] + public bool convertDummies { + get { + return ((bool)(this["convertDummies"])); + } + set { + this["convertDummies"] = value; + } + } } } diff --git a/Unity Studio/Properties/Settings.settings b/Unity Studio/Properties/Settings.settings index 0f60053..dd789da 100644 --- a/Unity Studio/Properties/Settings.settings +++ b/Unity Studio/Properties/Settings.settings @@ -38,5 +38,11 @@ False + + True + + + True + \ No newline at end of file diff --git a/Unity Studio/unity.ico b/Unity Studio/Resources/unity.ico similarity index 100% rename from Unity Studio/unity.ico rename to Unity Studio/Resources/unity.ico diff --git a/Unity Studio/AudioClip.cs b/Unity Studio/Unity Classes/AudioClip.cs similarity index 83% rename from Unity Studio/AudioClip.cs rename to Unity Studio/Unity Classes/AudioClip.cs index f2af2a9..d0c71d7 100644 --- a/Unity Studio/AudioClip.cs +++ b/Unity Studio/Unity Classes/AudioClip.cs @@ -9,8 +9,8 @@ namespace Unity_Studio class AudioClip { public string m_Name; - public int m_Format = 0; - public int m_Type; + public int m_Format; + public int m_Type = -1; public bool m_3D; public bool m_UseHardware; @@ -25,14 +25,14 @@ namespace Unity_Studio public bool m_PreloadAudioData; public bool m_LoadInBackground; public bool m_Legacy3D; - public int m_CompressionFormat; + public int m_CompressionFormat = -1; public string m_Source; public long m_Offset; public long m_Size; public byte[] m_AudioData; - public string extension; + public string extension = ""; public AudioClip(AssetPreloadData preloadData, bool readSwitch) { @@ -73,8 +73,7 @@ namespace Unity_Studio } else { - m_LoadType = a_Stream.ReadInt32(); - m_Type = m_LoadType; + m_LoadType = a_Stream.ReadInt32();//Decompress on load, Compressed in memory, Streaming m_Channels = a_Stream.ReadInt32(); m_Frequency = a_Stream.ReadInt32(); m_BitsPerSample = a_Stream.ReadInt32(); @@ -97,17 +96,13 @@ namespace Unity_Studio } #region Info Text & extension - preloadData.InfoText = "Format: " + m_Format + "\nType: "; + preloadData.InfoText = "Compression format: "; switch (m_Type) { - case 1: - extension = ".fsb"; - preloadData.InfoText += "FSB with substreams"; - break; case 2: - extension = ".fsb"; - preloadData.InfoText += "FSB"; + extension = ".aif"; + preloadData.InfoText += "AIFF"; break; case 13: extension = ".mp3"; @@ -125,11 +120,29 @@ namespace Unity_Studio extension = ".wav"; preloadData.InfoText += "Xbox360 WAV"; break; - default: - preloadData.InfoText += "Unknown type " + m_Type; + } + + switch (m_CompressionFormat) + { + case 0: + extension = ".fsb"; + preloadData.InfoText += "PCM"; + break; + case 1: + extension = ".fsb"; + preloadData.InfoText += "Vorbis"; + break; + case 2: + extension = ".fsb"; + preloadData.InfoText += "ADPCM"; + break; + case 3: + extension = ".fsb"; + preloadData.InfoText += "MP3";//not sure break; } + if (extension == "") { preloadData.InfoText += "Unknown"; } preloadData.InfoText += "\n3D: " + m_3D.ToString(); #endregion diff --git a/Unity Studio/BuildSettings.cs b/Unity Studio/Unity Classes/BuildSettings.cs similarity index 100% rename from Unity Studio/BuildSettings.cs rename to Unity Studio/Unity Classes/BuildSettings.cs diff --git a/Unity Studio/Font.cs b/Unity Studio/Unity Classes/Font.cs similarity index 100% rename from Unity Studio/Font.cs rename to Unity Studio/Unity Classes/Font.cs diff --git a/Unity Studio/GameObject.cs b/Unity Studio/Unity Classes/GameObject.cs similarity index 100% rename from Unity Studio/GameObject.cs rename to Unity Studio/Unity Classes/GameObject.cs diff --git a/Unity Studio/Material.cs b/Unity Studio/Unity Classes/Material.cs similarity index 100% rename from Unity Studio/Material.cs rename to Unity Studio/Unity Classes/Material.cs diff --git a/Unity Studio/Mesh.cs b/Unity Studio/Unity Classes/Mesh.cs similarity index 78% rename from Unity Studio/Mesh.cs rename to Unity Studio/Unity Classes/Mesh.cs index 8d43a65..5ac590b 100644 --- a/Unity Studio/Mesh.cs +++ b/Unity Studio/Unity Classes/Mesh.cs @@ -93,7 +93,7 @@ But since the -90 rotation from Unity is a regular type, it will show up in the Also, re-importing this FBX in Unity will now produce a (-90)+(-90)=-180 rotation. This is an unfortunate eyesore, but nothing more, the orientation will be fine. -In theory, one could add +90 degrees rotation to GameObjects that link to Mesh assets (but not other types) and use a different conversion for vertex components. +In theory, one could add +90 degrees rotation to GameObjects that link to Mesh assets (but not other types) to cancel out the Unity rotation. The problem is you can never know where the Unity mesh originated from. If it came from a left-handed format such as OBJ, there wouldn't have been any conversion and it wouldn't have that -90 degree adjustment. So it would "fix" meshes that were originally sourced form FBX, but would still have the "extra" rotation in mehses sourced from left-handed formats. */ @@ -107,10 +107,13 @@ namespace Unity_Studio public List m_SubMeshes = new List(); public List m_Indices = new List(); //use a list because I don't always know the facecount for triangle strips public List m_materialIDs = new List(); - public uint m_VertexCount; + private uint[] m_IndexBuffer; private ChannelInfo[] m_Channels; private StreamInfo[] m_Streams; - private uint[] m_IndexBuffer; + public List[] m_Skin; + //public Dictionary[] m_Skin; + public float[][,] m_BindPose; + public uint m_VertexCount; public float[] m_Vertices; public float[] m_Normals; public float[] m_Colors; @@ -130,6 +133,12 @@ namespace Unity_Studio public uint vertexCount; } + public class BoneInfluence + { + public float weight; + public int boneIndex; + } + public class ChannelInfo { public byte stream; @@ -362,6 +371,7 @@ namespace Unity_Studio } #endregion + #region subMeshes int m_SubMeshes_size = a_Stream.ReadInt32(); for (int s = 0; s < m_SubMeshes_size; s++) { @@ -380,54 +390,68 @@ namespace Unity_Studio a_Stream.Position += 24; //Axis-Aligned Bounding Box } } + #endregion - #region m_Shapes for 4.1.0 and later, excluding 4.1.0 alpha - if (version [0] >= 5 || (version[0] == 4 && (version[1] > 1 || (version[1] == 1 && MeshPD.sourceFile.buildType[0] != "a")))) + #region BlendShapeData + #region 4.1.0 to 4.2.x, excluding 4.1.0 alpha + if (version[0] == 4 && ((version[1] == 1 && MeshPD.sourceFile.buildType[0] != "a") || + (version[1] > 1 && version[1] <= 2))) { - if (version[0] == 4 && version[1] <= 2) //4.1.0f4 - 4.2.2f1 + int m_Shapes_size = a_Stream.ReadInt32(); + if (m_Shapes_size > 0) { - int m_Shapes_size = a_Stream.ReadInt32(); - if (m_Shapes_size > 0) - { - bool stop = true; - } - for (int s = 0; s < m_Shapes_size; s++) //untested - { - string shape_name = a_Stream.ReadAlignedString(a_Stream.ReadInt32()); - a_Stream.Position += 36; //uint firstVertex, vertexCount; Vector3f aabbMinDelta, aabbMaxDelta; bool hasNormals, hasTangents - } - - int m_ShapeVertices_size = a_Stream.ReadInt32(); - a_Stream.Position += m_ShapeVertices_size * 40; //vertex positions, normals, tangents & uint index + bool stop = true; } - else //4.3.0 and later + for (int s = 0; s < m_Shapes_size; s++) //untested { - int m_ShapeVertices_size = a_Stream.ReadInt32(); - a_Stream.Position += m_ShapeVertices_size * 40; //vertex positions, normals, tangents & uint index - - int shapes_size = a_Stream.ReadInt32(); - a_Stream.Position += shapes_size * 12; //uint firstVertex, vertexCount; bool hasNormals, hasTangents - - int channels_size = a_Stream.ReadInt32(); - for (int c = 0; c < channels_size; c++) - { - string channel_name = a_Stream.ReadAlignedString(a_Stream.ReadInt32()); - a_Stream.Position += 12; //uint nameHash; int frameIndex, frameCount - } - - int fullWeights_size = a_Stream.ReadInt32(); - a_Stream.Position += fullWeights_size * 4; //floats - - int m_BindPose_size = a_Stream.ReadInt32(); - a_Stream.Position += m_BindPose_size * 16 * 4; //matrix 4x4 - - int m_BoneNameHashes_size = a_Stream.ReadInt32(); - a_Stream.Position += m_BoneNameHashes_size * 4; //uints - - uint m_RootBoneNameHash = a_Stream.ReadUInt32(); + string shape_name = a_Stream.ReadAlignedString(a_Stream.ReadInt32()); + a_Stream.Position += 36; //uint firstVertex, vertexCount; Vector3f aabbMinDelta, aabbMaxDelta; bool hasNormals, hasTangents } + + int m_ShapeVertices_size = a_Stream.ReadInt32(); + a_Stream.Position += m_ShapeVertices_size * 40; //vertex positions, normals, tangents & uint index } #endregion + #region 4.3.0 and later + else if (version[0] >= 5 || (version[0] == 4 && version[1] >= 3)) + { + int m_ShapeVertices_size = a_Stream.ReadInt32(); + if (m_ShapeVertices_size > 0) + { + bool stop = true; + } + a_Stream.Position += m_ShapeVertices_size * 40; //vertex positions, normals, tangents & uint index + + int shapes_size = a_Stream.ReadInt32(); + a_Stream.Position += shapes_size * 12; //uint firstVertex, vertexCount; bool hasNormals, hasTangents + + int channels_size = a_Stream.ReadInt32(); + for (int c = 0; c < channels_size; c++) + { + string channel_name = a_Stream.ReadAlignedString(a_Stream.ReadInt32()); + a_Stream.Position += 12; //uint nameHash; int frameIndex, frameCount + } + + int fullWeights_size = a_Stream.ReadInt32(); + a_Stream.Position += fullWeights_size * 4; //floats + + m_BindPose = new float[a_Stream.ReadInt32()][,]; + for (int i = 0; i < m_BindPose.Length; i++) + { + m_BindPose[i] = new float[4,4] { + { a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle() }, + { a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle() }, + { a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle() }, + { a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle() } }; + } + + int m_BoneNameHashes_size = a_Stream.ReadInt32(); + a_Stream.Position += m_BoneNameHashes_size * 4; //uints + + uint m_RootBoneNameHash = a_Stream.ReadUInt32(); + } + #endregion + #endregion #region Index Buffer for 2.6.0 and later if (version[0] >= 3 || (version[0] == 2 && version[1] >= 6)) @@ -454,7 +478,7 @@ namespace Unity_Studio { m_IndexBuffer = new uint[m_IndexBuffer_size / 4]; for (int i = 0; i < m_IndexBuffer_size / 4; i++) { m_IndexBuffer[i] = a_Stream.ReadUInt32(); } - //align?? + a_Stream.AlignStream(4);//untested } } #endregion @@ -466,11 +490,32 @@ namespace Unity_Studio m_Vertices = new float[m_VertexCount * 3]; for (int v = 0; v < m_VertexCount * 3; v++) { m_Vertices[v] = a_Stream.ReadSingle(); } - int m_Skin_size = a_Stream.ReadInt32(); - a_Stream.Position += m_Skin_size * 32; //4x float weights & 4x int boneIndices + m_Skin = new List[a_Stream.ReadInt32()]; + //m_Skin = new Dictionary[a_Stream.ReadInt32()]; + for (int s = 0; s < m_Skin.Length; s++) + { + m_Skin[s] = new List(); + for (int i = 0; i < 4; i++) { m_Skin[s].Add(new BoneInfluence() { weight = a_Stream.ReadSingle() }); } + for (int i = 0; i < 4; i++) { m_Skin[s][i].boneIndex = a_Stream.ReadInt32(); } - int m_BindPose_size = a_Stream.ReadInt32(); - a_Stream.Position += m_BindPose_size * 16 * 4; //matrix 4x4 + /*m_Skin[s] = new Dictionary(); + float[] weights = new float[4] { a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle() }; + for (int i = 0; i < 4; i++) + { + int boneIndex = a_Stream.ReadInt32(); + m_Skin[s][boneIndex] = weights[i]; + }*/ + } + + m_BindPose = new float[a_Stream.ReadInt32()][,]; + for (int i = 0; i < m_BindPose.Length; i++) + { + m_BindPose[i] = new float[4, 4] { + { a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle() }, + { a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle() }, + { a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle() }, + { a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle() } }; + } int m_UV1_size = a_Stream.ReadInt32(); m_UV1 = new float[m_UV1_size * 2]; @@ -507,13 +552,35 @@ namespace Unity_Studio else { #region read vertex stream - int m_Skin_size = a_Stream.ReadInt32(); - a_Stream.Position += m_Skin_size * 32; //4x float weights & 4x int boneIndices - - if (version[0] <= 3 || (version[0] == 4 && version[1] <= 2)) + m_Skin = new List[a_Stream.ReadInt32()]; + //m_Skin = new Dictionary[a_Stream.ReadInt32()]; + for (int s = 0; s < m_Skin.Length; s++) { - int m_BindPose_size = a_Stream.ReadInt32(); - a_Stream.Position += m_BindPose_size * 16 * 4; //matrix 4x4 + m_Skin[s] = new List(); + for (int i = 0; i < 4; i++) { m_Skin[s].Add(new BoneInfluence() { weight = a_Stream.ReadSingle() }); } + for (int i = 0; i < 4; i++) { m_Skin[s][i].boneIndex = a_Stream.ReadInt32(); } + + /*m_Skin[s] = new Dictionary(); + float[] weights = new float[4] { a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle() }; + for (int i = 0; i < 4; i++) + { + int boneIndex = a_Stream.ReadInt32(); + m_Skin[s][boneIndex] = weights[i]; + }*/ + } + + + if (version[0] == 3 || (version[0] == 4 && version[1] <= 2)) + { + m_BindPose = new float[a_Stream.ReadInt32()][,]; + for (int i = 0; i < m_BindPose.Length; i++) + { + m_BindPose[i] = new float[4, 4] { + { a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle() }, + { a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle() }, + { a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle() }, + { a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle() } }; + } } int m_CurrentChannels = a_Stream.ReadInt32();//defined as uint in Unity @@ -588,15 +655,15 @@ namespace Unity_Studio #endregion #region compute FvF - int valueBufferSize = 0; - byte[] valueBuffer; - float[] dstArray; + int componentByteSize = 0; + byte[] componentBytes; + float[] componentsArray; + #region 4.0.0 and later if (m_Channels != null) { //it is better to loop channels instead of streams //because channels are likely to be sorted by vertex property - #region 4.0.0 and later foreach (var m_Channel in m_Channels) { if (m_Channel.dimension > 0) @@ -610,7 +677,7 @@ namespace Unity_Studio // in Unity 4.x the colors channel has 1 dimension, as in 1 color with 4 components if (b == 2 && m_Channel.format == 2) { m_Channel.dimension = 4; } - valueBufferSize = 4 / (int)Math.Pow(2, m_Channel.format); + componentByteSize = 4 / (int)Math.Pow(2, m_Channel.format); /*switch (m_Channel.format) { @@ -626,51 +693,38 @@ namespace Unity_Studio break; }*/ - valueBuffer = new byte[valueBufferSize]; - dstArray = new float[m_VertexCount * m_Channel.dimension]; + componentBytes = new byte[componentByteSize]; + componentsArray = new float[m_VertexCount * m_Channel.dimension]; for (int v = 0; v < m_VertexCount; v++) { + int vertexOffset = m_Stream.offset + m_Channel.offset + m_Stream.stride * v; for (int d = 0; d < m_Channel.dimension; d++) { - int m_DataSizeOffset = m_Stream.offset + m_Channel.offset + m_Stream.stride * v + valueBufferSize * d; - Buffer.BlockCopy(m_DataSize, m_DataSizeOffset, valueBuffer, 0, valueBufferSize); - dstArray[v * m_Channel.dimension + d] = bytesToFloat(valueBuffer); + int componentOffset = vertexOffset + componentByteSize * d; + Buffer.BlockCopy(m_DataSize, componentOffset, componentBytes, 0, componentByteSize); + componentsArray[v * m_Channel.dimension + d] = bytesToFloat(componentBytes); } } switch (b) { - case 0: - m_Vertices = dstArray; - break; - case 1: - m_Normals = dstArray; - break; - case 2: - m_Colors = dstArray; - break; - case 3: - m_UV1 = dstArray; - break; - case 4: - m_UV2 = dstArray; - break; + case 0: m_Vertices = componentsArray; break; + case 1: m_Normals = componentsArray; break; + case 2: m_Colors = componentsArray; break; + case 3: m_UV1 = componentsArray; break; + case 4: m_UV2 = componentsArray; break; case 5: - if (version[0] == 5) { m_UV3 = dstArray; } - else { m_Tangents = dstArray; } - break; - case 6: - m_UV4 = dstArray; - break; - case 7: - m_Tangents = dstArray; + if (version[0] == 5) { m_UV3 = componentsArray; } + else { m_Tangents = componentsArray; } break; + case 6: m_UV4 = componentsArray; break; + case 7: m_Tangents = componentsArray; break; } - m_Stream.channelMask.Set(b, false); //is this needed? - valueBuffer = null; - dstArray = null; + m_Stream.channelMask.Set(b, false); + componentBytes = null; + componentsArray = null; break; //go to next channel } } @@ -697,63 +751,52 @@ namespace Unity_Studio { case 0: case 1: - valueBufferSize = 4; + componentByteSize = 4; m_Channel.dimension = 3; break; case 2: - valueBufferSize = 1; + componentByteSize = 1; m_Channel.dimension = 4; break; case 3: case 4: - valueBufferSize = 4; + componentByteSize = 4; m_Channel.dimension = 2; break; case 5: - valueBufferSize = 4; + componentByteSize = 4; m_Channel.dimension = 4; break; } - valueBuffer = new byte[valueBufferSize]; - dstArray = new float[m_VertexCount * m_Channel.dimension]; + componentBytes = new byte[componentByteSize]; + componentsArray = new float[m_VertexCount * m_Channel.dimension]; for (int v = 0; v < m_VertexCount; v++) { + int vertexOffset = m_Stream.offset + m_Channel.offset + m_Stream.stride * v; for (int d = 0; d < m_Channel.dimension; d++) { - int m_DataSizeOffset = m_Stream.offset + m_Channel.offset + m_Stream.stride * v + valueBufferSize * d; - Buffer.BlockCopy(m_DataSize, m_DataSizeOffset, valueBuffer, 0, valueBufferSize); - dstArray[v * m_Channel.dimension + d] = bytesToFloat(valueBuffer); + int m_DataSizeOffset = vertexOffset + componentByteSize * d; + Buffer.BlockCopy(m_DataSize, m_DataSizeOffset, componentBytes, 0, componentByteSize); + componentsArray[v * m_Channel.dimension + d] = bytesToFloat(componentBytes); } } switch (b) { - case 0: - m_Vertices = dstArray; - break; - case 1: - m_Normals = dstArray; - break; - case 2: - m_Colors = dstArray; - break; - case 3: - m_UV1 = dstArray; - break; - case 4: - m_UV2 = dstArray; - break; - case 5: - m_Tangents = dstArray; - break; + case 0: m_Vertices = componentsArray; break; + case 1: m_Normals = componentsArray; break; + case 2: m_Colors = componentsArray; break; + case 3: m_UV1 = componentsArray; break; + case 4: m_UV2 = componentsArray; break; + case 5: m_Tangents = componentsArray; break; } - m_Channel.offset += (byte)(m_Channel.dimension * valueBufferSize); //strides larger than 255 are unlikely - m_Stream.channelMask.Set(b, false); //is this needed? - valueBuffer = null; - dstArray = null; + m_Channel.offset += (byte)(m_Channel.dimension * componentByteSize); //safe to cast as byte because strides larger than 255 are unlikely + m_Stream.channelMask.Set(b, false); + componentBytes = null; + componentsArray = null; } } } @@ -800,7 +843,7 @@ namespace Unity_Studio m_UV_Packed.m_BitSize = a_Stream.ReadByte(); a_Stream.Position += 3; //4 byte alignment - if (m_UV_Packed.m_NumItems > 0) + if (m_UV_Packed.m_NumItems > 0 && (bool)Properties.Settings.Default["exportUVs"]) { uint[] m_UV_Unpacked = UnpackBitVector(m_UV_Packed); int bitmax = 0; @@ -890,7 +933,7 @@ namespace Unity_Studio m_NormalSigns_packed.m_BitSize = a_Stream.ReadByte(); a_Stream.Position += 3; //4 byte alignment - if (m_Normals_Packed.m_NumItems > 0) + if (m_Normals_Packed.m_NumItems > 0 && (bool)Properties.Settings.Default["exportNormals"]) { uint[] m_Normals_Unpacked = UnpackBitVector(m_Normals_Packed); uint[] m_NormalSigns = UnpackBitVector(m_NormalSigns_packed); @@ -906,13 +949,29 @@ namespace Unity_Studio } } - PackedBitVector m_TangentSigns = new PackedBitVector(); - m_TangentSigns.m_NumItems = a_Stream.ReadUInt32(); - m_TangentSigns.m_Data = new byte[a_Stream.ReadInt32()]; - a_Stream.Read(m_TangentSigns.m_Data, 0, m_TangentSigns.m_Data.Length); + PackedBitVector m_TangentSigns_packed = new PackedBitVector(); + m_TangentSigns_packed.m_NumItems = a_Stream.ReadUInt32(); + m_TangentSigns_packed.m_Data = new byte[a_Stream.ReadInt32()]; + a_Stream.Read(m_TangentSigns_packed.m_Data, 0, m_TangentSigns_packed.m_Data.Length); a_Stream.AlignStream(4); - m_TangentSigns.m_BitSize = a_Stream.ReadByte(); + m_TangentSigns_packed.m_BitSize = a_Stream.ReadByte(); a_Stream.Position += 3; //4 byte alignment + + if (m_Tangents_Packed.m_NumItems > 0 && (bool)Properties.Settings.Default["exportTangents"]) + { + uint[] m_Tangents_Unpacked = UnpackBitVector(m_Tangents_Packed); + uint[] m_TangentSigns = UnpackBitVector(m_TangentSigns_packed); + int bitmax = 0; + for (int b = 0; b < m_Tangents_Packed.m_BitSize; b++) { bitmax |= (1 << b); } + m_Tangents = new float[m_Tangents_Packed.m_NumItems / 2 * 3]; + for (int v = 0; v < m_Tangents_Packed.m_NumItems / 2; v++) + { + m_Tangents[v * 3] = (float)((double)m_Tangents_Unpacked[v * 2] / bitmax) * m_Tangents_Packed.m_Range + m_Tangents_Packed.m_Start; + m_Tangents[v * 3 + 1] = (float)((double)m_Tangents_Unpacked[v * 2 + 1] / bitmax) * m_Tangents_Packed.m_Range + m_Tangents_Packed.m_Start; + m_Tangents[v * 3 + 2] = (float)Math.Sqrt(1 - m_Tangents[v * 3] * m_Tangents[v * 3] - m_Tangents[v * 3 + 1] * m_Tangents[v * 3 + 1]); + if (m_TangentSigns[v] == 0) { m_Tangents[v * 3 + 2] *= -1; } + } + } if (version[0] >= 5) { @@ -926,7 +985,7 @@ namespace Unity_Studio m_FloatColors.m_BitSize = a_Stream.ReadByte(); a_Stream.Position += 3; //4 byte alignment - if (m_FloatColors.m_NumItems > 0) + if (m_FloatColors.m_NumItems > 0 && (bool)Properties.Settings.Default["exportColors"]) { uint[] m_FloatColors_Unpacked = UnpackBitVector(m_FloatColors); int bitmax = 0; diff --git a/Unity Studio/MeshFilter.cs b/Unity Studio/Unity Classes/MeshFilter.cs similarity index 100% rename from Unity Studio/MeshFilter.cs rename to Unity Studio/Unity Classes/MeshFilter.cs diff --git a/Unity Studio/PlayerSettings.cs b/Unity Studio/Unity Classes/PlayerSettings.cs similarity index 100% rename from Unity Studio/PlayerSettings.cs rename to Unity Studio/Unity Classes/PlayerSettings.cs diff --git a/Unity Studio/RectTransform.cs b/Unity Studio/Unity Classes/RectTransform.cs similarity index 100% rename from Unity Studio/RectTransform.cs rename to Unity Studio/Unity Classes/RectTransform.cs diff --git a/Unity Studio/Renderer.cs b/Unity Studio/Unity Classes/Renderer.cs similarity index 100% rename from Unity Studio/Renderer.cs rename to Unity Studio/Unity Classes/Renderer.cs diff --git a/Unity Studio/SkinnedMeshRenderer.cs b/Unity Studio/Unity Classes/SkinnedMeshRenderer.cs similarity index 78% rename from Unity Studio/SkinnedMeshRenderer.cs rename to Unity Studio/Unity Classes/SkinnedMeshRenderer.cs index 2b2f3f5..2309f81 100644 --- a/Unity Studio/SkinnedMeshRenderer.cs +++ b/Unity Studio/Unity Classes/SkinnedMeshRenderer.cs @@ -15,6 +15,7 @@ namespace Unity_Studio public ushort m_LightmapIndexDynamic; public PPtr[] m_Materials; public PPtr m_Mesh; + public PPtr[] m_Bones; public SkinnedMeshRenderer(AssetPreloadData preloadData) { @@ -98,28 +99,38 @@ namespace Unity_Studio m_Mesh = sourceFile.ReadPPtr(); - /*int m_Bones_size = a_Stream.ReadInt32(); - for (int b = 0; b < m_Bones_size; b++) + m_Bones = new PPtr[a_Stream.ReadInt32()]; + for (int b = 0; b < m_Bones.Length; b++) { - PPtr aBone = sourceFile.ReadPPtr(); + m_Bones[b] = sourceFile.ReadPPtr(); } if (version[0] < 3) { - int m_BindPose_size = a_Stream.ReadInt32(); - a_Stream.Position += m_BindPose_size * 16 * 4;//Matrix4x4f + int m_BindPose = a_Stream.ReadInt32(); + a_Stream.Position += m_BindPose * 16 * 4;//Matrix4x4f } - else if (version[0] >= 3 && version[1] >= 4) + else { - if (version[1] >= 5) + if (version[0] >= 4 || (version[0] == 4 && version[1] >= 3)) + { + int m_BlendShapeWeights = a_Stream.ReadInt32(); + a_Stream.Position += m_BlendShapeWeights * 4; //floats + } + + if (version[0] >= 4 || (version[0] >= 3 && version[1] >= 5)) { PPtr m_RootBone = sourceFile.ReadPPtr(); } - //AABB - float[] m_Center = new float[] { a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle() }; - float[] m_Extent = new float[] { a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle() }; - bool m_DirtyAABB = a_Stream.ReadBoolean(); - }*/ + + if (version[0] >= 4 || (version[0] == 3 && version[1] >= 4)) + { + //AABB + float[] m_Center = new float[] { a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle() }; + float[] m_Extent = new float[] { a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle() }; + bool m_DirtyAABB = a_Stream.ReadBoolean(); + } + } } } } diff --git a/Unity Studio/TextAsset.cs b/Unity Studio/Unity Classes/TextAsset.cs similarity index 100% rename from Unity Studio/TextAsset.cs rename to Unity Studio/Unity Classes/TextAsset.cs diff --git a/Unity Studio/Texture2D.cs b/Unity Studio/Unity Classes/Texture2D.cs similarity index 100% rename from Unity Studio/Texture2D.cs rename to Unity Studio/Unity Classes/Texture2D.cs diff --git a/Unity Studio/Transform.cs b/Unity Studio/Unity Classes/Transform.cs similarity index 100% rename from Unity Studio/Transform.cs rename to Unity Studio/Unity Classes/Transform.cs diff --git a/Unity Studio/Unity Studio.csproj b/Unity Studio/Unity Studio.csproj index 028e0f0..9b58817 100644 --- a/Unity Studio/Unity Studio.csproj +++ b/Unity Studio/Unity Studio.csproj @@ -50,7 +50,7 @@ 4 - unity.ico + Resources\unity.ico @@ -128,37 +128,37 @@ AboutBox.cs - - + + - + Form - - FBXExport.cs + + ExportOptions.cs - + Component - - - + + + - - - - - - - - + + + + + + + + @@ -172,8 +172,8 @@ AboutBox.cs Designer - - FBXExport.cs + + ExportOptions.cs ResXFileCodeGenerator @@ -219,7 +219,13 @@ - + + PreserveNewest + + + PreserveNewest + + diff --git a/Unity Studio/UnityStudioForm.cs b/Unity Studio/UnityStudioForm.cs index 67d3cf1..9bc9dfe 100644 --- a/Unity Studio/UnityStudioForm.cs +++ b/Unity Studio/UnityStudioForm.cs @@ -66,8 +66,8 @@ namespace Unity_Studio [DllImport("gdi32.dll")] private static extern IntPtr AddFontMemResourceEx(IntPtr pbFont, uint cbFont, IntPtr pdv, [In] ref uint pcFonts); - [DllImport("PVRTexLib.dll")] - private static extern void test(); + //[DllImport("PVRTexLib.dll")] + //private static extern void test(); private void loadFile_Click(object sender, System.EventArgs e) @@ -730,7 +730,7 @@ namespace Unity_Studio { PlayerSettings plSet = new PlayerSettings(asset); productName = plSet.productName; - base.Text = "Unity Studio - " + productName + " - " + assetsFile.m_Version + " - " + assetsFile.platformStr; ; + base.Text = "Unity Studio - " + productName + " - " + assetsFile.m_Version + " - " + assetsFile.platformStr; break; } @@ -746,13 +746,16 @@ namespace Unity_Studio //if (assetGroup.Items.Count > 0) { listView1.Groups.Add(assetGroup); } } + if (base.Text == "Unity Studio" && assetsfileList.Count > 0) + { + base.Text = "Unity Studio - no productName - " + assetsfileList[0].m_Version + " - " + assetsfileList[0].platformStr; + } + visibleAssets = exportableAssets; assetListView.VirtualListSize = visibleAssets.Count; - //won't work because ListView is not visible - //assetListView.AutoResizeColumn(1, ColumnHeaderAutoResizeStyle.ColumnContent); - //assetListView.AutoResizeColumn(2, ColumnHeaderAutoResizeStyle.ColumnContent); - //resizeAssetListColumns(); + //will only work if ListView is visible + resizeAssetListColumns(); assetListView.EndUpdate(); progressBar1.Value = 0; @@ -771,6 +774,7 @@ namespace Unity_Studio StatusStripUpdate("Building tree structure from " + Path.GetFileName(assetsFile.filePath)); GameObject fileNode = new GameObject(null); fileNode.Text = Path.GetFileName(assetsFile.filePath); + fileNode.m_Name = "RootNode"; foreach (var m_GameObject in assetsFile.GameObjectList.Values) { @@ -946,7 +950,7 @@ namespace Unity_Studio { if (treeSrcResults.Count > 0) { - if (nextGObject > treeSrcResults.Count) { nextGObject = 0; } + if (nextGObject >= treeSrcResults.Count) { nextGObject = 0; } treeSrcResults[nextGObject].EnsureVisible(); sceneTreeView.SelectedNode = treeSrcResults[nextGObject]; nextGObject++; @@ -971,9 +975,9 @@ namespace Unity_Studio assetListView.AutoResizeColumn(2, ColumnHeaderAutoResizeStyle.HeaderSize); assetListView.AutoResizeColumn(2, ColumnHeaderAutoResizeStyle.ColumnContent); - var test = SystemInformation.VerticalScrollBarWidth; - var vscroll = ((float)visibleAssets.Count / (float)assetListView.Height) > 0.0567f; - columnHeaderName.Width = assetListView.Width - columnHeaderType.Width - columnHeaderSize.Width - (vscroll ? 25 : 5); + var vscrollwidth = SystemInformation.VerticalScrollBarWidth; + var hasvscroll = ((float)visibleAssets.Count / (float)assetListView.Height) > 0.0567f; + columnHeaderName.Width = assetListView.Width - columnHeaderType.Width - columnHeaderSize.Width - (hasvscroll ? (5 + vscrollwidth) : 5); } private void tabPage2_Resize(object sender, EventArgs e) @@ -1667,23 +1671,247 @@ namespace Unity_Studio StringBuilder fbx = new StringBuilder(); StringBuilder ob = new StringBuilder(); //Objects builder StringBuilder cb = new StringBuilder(); //Connections builder + StringBuilder mb = new StringBuilder(); //Materials builder to get texture count in advance + StringBuilder cb2 = new StringBuilder(); //and keep connections ordered cb.Append("\n}\n");//Objects end cb.Append("\nConnections: {"); - HashSet MeshList = new HashSet(); - HashSet MaterialList = new HashSet(); - HashSet TextureList = new HashSet(); + HashSet GameObjects = new HashSet(); + HashSet LimbNodes = new HashSet(); + HashSet Skins = new HashSet(); + HashSet Meshes = new HashSet();//MeshFilters are not unique!! + HashSet Materials = new HashSet(); + HashSet Textures = new HashSet(); - int ModelCount = 0; - int GeometryCount = 0; - int MaterialCount = 0; - int TextureCount = 0; + int DeformerCount = 0; - //using m_PathID as unique ID would fail because it could be a negative number (Hearthstone syndrome) - //consider using uint - //no, do something smarter + #region loop nodes and collect objects for export + foreach (var assetsFile in assetsfileList) + { + foreach (var m_GameObject in assetsFile.GameObjectList.Values) + { + if (m_GameObject.Checked || allNodes) + { + GameObjects.Add(m_GameObject); + + AssetPreloadData MeshFilterPD; + if (assetsfileList.TryGetPD(m_GameObject.m_MeshFilter, out MeshFilterPD)) + { + //MeshFilters are not unique! + //MeshFilters.Add(MeshFilterPD); + MeshFilter m_MeshFilter = new MeshFilter(MeshFilterPD); + AssetPreloadData MeshPD; + if (assetsfileList.TryGetPD(m_MeshFilter.m_Mesh, out MeshPD)) + { + Meshes.Add(MeshPD); + + cb2.AppendFormat("\n\n\t;Geometry::, Model::{0}", m_GameObject.m_Name); + cb2.AppendFormat("\n\tC: \"OO\",{0},{1}", MeshPD.uniqueID, m_GameObject.uniqueID); + } + } - #region write generic FBX data + #region get Renderer + AssetPreloadData RendererPD; + if (assetsfileList.TryGetPD(m_GameObject.m_Renderer, out RendererPD)) + { + Renderer m_Renderer = new Renderer(RendererPD); + + foreach (var MaterialPPtr in m_Renderer.m_Materials) + { + AssetPreloadData MaterialPD; + if (assetsfileList.TryGetPD(MaterialPPtr, out MaterialPD)) + { + Materials.Add(MaterialPD); + cb2.AppendFormat("\n\n\t;Material::, Model::{0}", m_GameObject.m_Name); + cb2.AppendFormat("\n\tC: \"OO\",{0},{1}", MaterialPD.uniqueID, m_GameObject.uniqueID); + } + } + } + #endregion + + #region get SkinnedMeshRenderer + AssetPreloadData SkinnedMeshPD; + if (assetsfileList.TryGetPD(m_GameObject.m_SkinnedMeshRenderer, out SkinnedMeshPD)) + { + Skins.Add(SkinnedMeshPD); + + SkinnedMeshRenderer m_SkinnedMeshRenderer = new SkinnedMeshRenderer(SkinnedMeshPD); + + foreach (var MaterialPPtr in m_SkinnedMeshRenderer.m_Materials) + { + AssetPreloadData MaterialPD; + if (assetsfileList.TryGetPD(MaterialPPtr, out MaterialPD)) + { + Materials.Add(MaterialPD); + cb2.AppendFormat("\n\n\t;Material::, Model::{0}", m_GameObject.m_Name); + cb2.AppendFormat("\n\tC: \"OO\",{0},{1}", MaterialPD.uniqueID, m_GameObject.uniqueID); + } + } + + if ((bool)Properties.Settings.Default["exportDeformers"]) + { + DeformerCount += m_SkinnedMeshRenderer.m_Bones.Length; + + //collect skeleton dummies to make sure they are exported + foreach (var bonePPtr in m_SkinnedMeshRenderer.m_Bones) + { + Transform b_Transform; + if (assetsfileList.TryGetTransform(bonePPtr, out b_Transform)) + { + GameObject m_Bone; + if (assetsfileList.TryGetGameObject(b_Transform.m_GameObject, out m_Bone)) + { + LimbNodes.Add(m_Bone); + //also collect the root bone + if (m_Bone.Parent.Level > 0) { LimbNodes.Add((GameObject)m_Bone.Parent); } + //should I collect siblings? + } + + #region collect children because m_SkinnedMeshRenderer.m_Bones doesn't contain terminations + foreach (var ChildPPtr in b_Transform.m_Children) + { + Transform ChildTR; + if (assetsfileList.TryGetTransform(ChildPPtr, out ChildTR)) + { + GameObject m_Child; + if (assetsfileList.TryGetGameObject(ChildTR.m_GameObject, out m_Child)) + { + //check that the Model doesn't contain a Mesh, although this won't ensure it's part of the skeleton + if (m_Child.m_MeshFilter == null && m_Child.m_SkinnedMeshRenderer == null) + { + LimbNodes.Add(m_Child); + } + } + } + } + #endregion + } + } + } + } + #endregion + } + } + } + + //if ((bool)Properties.Settings.Default["convertDummies"]) { GameObjects.Except(LimbNodes); } + //else { GameObjects.UnionWith(LimbNodes); LimbNodes.Clear(); } + //add either way and use LimbNodes to test if a node is Null or LimbNode + GameObjects.UnionWith(LimbNodes); + #endregion + + #region write Materials, collect Texture objects + StatusStripUpdate("Writing Materials"); + foreach (var MaterialPD in Materials) + { + Material m_Material = new Material(MaterialPD); + + mb.AppendFormat("\n\tMaterial: {0}, \"Material::{1}\", \"\" {{", MaterialPD.uniqueID, m_Material.m_Name); + mb.Append("\n\t\tVersion: 102"); + mb.Append("\n\t\tShadingModel: \"phong\""); + mb.Append("\n\t\tMultiLayer: 0"); + mb.Append("\n\t\tProperties70: {"); + mb.Append("\n\t\t\tP: \"ShadingModel\", \"KString\", \"\", \"\", \"phong\""); + + #region write material colors + foreach (var m_Color in m_Material.m_Colors) + { + switch (m_Color.first) + { + case "_Color": + case "gSurfaceColor": + mb.AppendFormat("\n\t\t\tP: \"DiffuseColor\", \"Color\", \"\", \"A\",{0},{1},{2}", m_Color.second[0], m_Color.second[1], m_Color.second[2]); + break; + case "_SpecularColor"://then what is _SpecColor?? + mb.AppendFormat("\n\t\t\tP: \"SpecularColor\", \"Color\", \"\", \"A\",{0},{1},{2}", m_Color.second[0], m_Color.second[1], m_Color.second[2]); + break; + case "_ReflectColor": + mb.AppendFormat("\n\t\t\tP: \"AmbientColor\", \"Color\", \"\", \"A\",{0},{1},{2}", m_Color.second[0], m_Color.second[1], m_Color.second[2]); + break; + default: + mb.AppendFormat("\n;\t\t\tP: \"{3}\", \"Color\", \"\", \"A\",{0},{1},{2}", m_Color.second[0], m_Color.second[1], m_Color.second[2], m_Color.first);//commented out + break; + } + } + #endregion + + #region write material parameters + foreach (var m_Float in m_Material.m_Floats) + { + switch (m_Float.first) + { + case "_Shininess": + mb.AppendFormat("\n\t\t\tP: \"ShininessExponent\", \"Number\", \"\", \"A\",{0}", m_Float.second); + mb.AppendFormat("\n\t\t\tP: \"Shininess\", \"Number\", \"\", \"A\",{0}", m_Float.second); + break; + default: + mb.AppendFormat("\n;\t\t\tP: \"{0}\", \"Number\", \"\", \"A\",{1}", m_Float.first, m_Float.second); + break; + } + } + #endregion + + //mb.Append("\n\t\t\tP: \"SpecularFactor\", \"Number\", \"\", \"A\",0"); + mb.Append("\n\t\t}"); + mb.Append("\n\t}"); + + #region write texture connections + foreach (var m_TexEnv in m_Material.m_TexEnvs) + { + AssetPreloadData TexturePD; + if (assetsfileList.TryGetPD(m_TexEnv.m_Texture, out TexturePD)) { } + else if (jsonMats != null) + { + Dictionary matProp; + if (jsonMats.TryGetValue(m_Material.m_Name, out matProp)) + { + string texName; + if (matProp.TryGetValue(m_TexEnv.name, out texName)) + { + foreach (var asset in exportableAssets) + { + if (asset.Type2 == 28 && asset.Text == texName) + { + TexturePD = asset; + break; + } + } + } + } + } + + if (TexturePD != null) + { + Textures.Add(TexturePD); + + cb2.AppendFormat("\n\n\t;Texture::, Material::{0}", m_Material.m_Name); + cb2.AppendFormat("\n\tC: \"OP\",{0},{1}, \"", TexturePD.uniqueID, MaterialPD.uniqueID); + switch (m_TexEnv.name) + { + case "_MainTex": + case "gDiffuseSampler": + cb2.Append("DiffuseColor\""); + break; + case "_SpecularMap": + case "gSpecularSampler": + cb2.Append("SpecularColor\""); + break; + case "_NormalMap": + case "_BumpMap": + case "gNormalSampler": + cb2.Append("NormalMap\""); + break; + default: + cb2.AppendFormat("{0}\"", m_TexEnv.name); + break; + } + } + } + #endregion + } + #endregion + + #region write generic FBX data after everything was collected fbx.Append("; FBX 7.1.0 project file"); fbx.Append("\nFBXHeaderExtension: {\n\tFBXHeaderVersion: 1003\n\tFBXVersion: 7100\n\tCreationTimeStamp: {\n\t\tVersion: 1000"); fbx.Append("\n\t\tYear: " + timestamp.Year); @@ -1708,16 +1936,16 @@ namespace Unity_Studio fbx.Append("\n\t\tP: \"OriginalUpAxisSign\", \"int\", \"Integer\", \"\",1"); fbx.AppendFormat("\n\t\tP: \"UnitScaleFactor\", \"double\", \"Number\", \"\",{0}", Properties.Settings.Default["scaleFactor"]); fbx.Append("\n\t\tP: \"OriginalUnitScaleFactor\", \"double\", \"Number\", \"\",1.0"); - //sb.Append("\n\t\tP: \"AmbientColor\", \"ColorRGB\", \"Color\", \"\",0,0,0"); - //sb.Append("\n\t\tP: \"DefaultCamera\", \"KString\", \"\", \"\", \"Producer Perspective\""); - //sb.Append("\n\t\tP: \"TimeMode\", \"enum\", \"\", \"\",6"); - //sb.Append("\n\t\tP: \"TimeProtocol\", \"enum\", \"\", \"\",2"); - //sb.Append("\n\t\tP: \"SnapOnFrameMode\", \"enum\", \"\", \"\",0"); - //sb.Append("\n\t\tP: \"TimeSpanStart\", \"KTime\", \"Time\", \"\",0"); - //sb.Append("\n\t\tP: \"TimeSpanStop\", \"KTime\", \"Time\", \"\",153953860000"); - //sb.Append("\n\t\tP: \"CustomFrameRate\", \"double\", \"Number\", \"\",-1"); - //sb.Append("\n\t\tP: \"TimeMarker\", \"Compound\", \"\", \"\""); - //sb.Append("\n\t\tP: \"CurrentTimeMarker\", \"int\", \"Integer\", \"\",-1"); + //fbx.Append("\n\t\tP: \"AmbientColor\", \"ColorRGB\", \"Color\", \"\",0,0,0"); + //fbx.Append("\n\t\tP: \"DefaultCamera\", \"KString\", \"\", \"\", \"Producer Perspective\""); + //fbx.Append("\n\t\tP: \"TimeMode\", \"enum\", \"\", \"\",6"); + //fbx.Append("\n\t\tP: \"TimeProtocol\", \"enum\", \"\", \"\",2"); + //fbx.Append("\n\t\tP: \"SnapOnFrameMode\", \"enum\", \"\", \"\",0"); + //fbx.Append("\n\t\tP: \"TimeSpanStart\", \"KTime\", \"Time\", \"\",0"); + //fbx.Append("\n\t\tP: \"TimeSpanStop\", \"KTime\", \"Time\", \"\",153953860000"); + //fbx.Append("\n\t\tP: \"CustomFrameRate\", \"double\", \"Number\", \"\",-1"); + //fbx.Append("\n\t\tP: \"TimeMarker\", \"Compound\", \"\", \"\""); + //fbx.Append("\n\t\tP: \"CurrentTimeMarker\", \"int\", \"Integer\", \"\",-1"); fbx.Append("\n\t}\n}\n"); fbx.Append("\nDocuments: {"); @@ -1733,783 +1961,335 @@ namespace Unity_Studio fbx.Append("\nDefinitions: {"); fbx.Append("\n\tVersion: 100"); - //fbx.AppendFormat("\n\tCount: {0}", 1 + srcModel.nodes.Count + FBXgeometryCount + srcModel.materials.Count + srcModel.usedTex.Count * 2); + fbx.AppendFormat("\n\tCount: {0}", 1 + 2 * GameObjects.Count + Materials.Count + 2 * Textures.Count + ((bool)Properties.Settings.Default["exportDeformers"] ? Skins.Count + DeformerCount + Skins.Count + 1 : 0)); fbx.Append("\n\tObjectType: \"GlobalSettings\" {"); fbx.Append("\n\t\tCount: 1"); fbx.Append("\n\t}"); fbx.Append("\n\tObjectType: \"Model\" {"); - //fbx.AppendFormat("\n\t\tCount: {0}", ModelCount); + fbx.AppendFormat("\n\t\tCount: {0}", GameObjects.Count); fbx.Append("\n\t}"); + fbx.Append("\n\tObjectType: \"NodeAttribute\" {"); + fbx.AppendFormat("\n\t\tCount: {0}", GameObjects.Count - Meshes.Count - Skins.Count); + fbx.Append("\n\t\tPropertyTemplate: \"FbxNull\" {"); + fbx.Append("\n\t\t\tProperties70: {"); + fbx.Append("\n\t\t\t\tP: \"Color\", \"ColorRGB\", \"Color\", \"\",0.8,0.8,0.8"); + fbx.Append("\n\t\t\t\tP: \"Size\", \"double\", \"Number\", \"\",100"); + fbx.Append("\n\t\t\t\tP: \"Look\", \"enum\", \"\", \"\",1"); + fbx.Append("\n\t\t\t}\n\t\t}\n\t}"); + fbx.Append("\n\tObjectType: \"Geometry\" {"); - //fbx.AppendFormat("\n\t\tCount: {0}", GeometryCount); + fbx.AppendFormat("\n\t\tCount: {0}", Meshes.Count + Skins.Count); fbx.Append("\n\t}"); fbx.Append("\n\tObjectType: \"Material\" {"); - //fbx.AppendFormat("\n\t\tCount: {0}", MaterialCount); + fbx.AppendFormat("\n\t\tCount: {0}", Materials.Count); fbx.Append("\n\t}"); fbx.Append("\n\tObjectType: \"Texture\" {"); - //fbx.AppendFormat("\n\t\tCount: {0}", TextureCount); + fbx.AppendFormat("\n\t\tCount: {0}", Textures.Count); fbx.Append("\n\t}"); fbx.Append("\n\tObjectType: \"Video\" {"); - //fbx.AppendFormat("\n\t\tCount: {0}", TextureCount); + fbx.AppendFormat("\n\t\tCount: {0}", Textures.Count); fbx.Append("\n\t}"); + + if ((bool)Properties.Settings.Default["exportDeformers"]) + { + fbx.Append("\n\tObjectType: \"CollectionExclusive\" {"); + fbx.AppendFormat("\n\t\tCount: {0}", Skins.Count); + fbx.Append("\n\t\tPropertyTemplate: \"FbxDisplayLayer\" {"); + fbx.Append("\n\t\t\tProperties70: {"); + fbx.Append("\n\t\t\t\tP: \"Color\", \"ColorRGB\", \"Color\", \"\",0.8,0.8,0.8"); + fbx.Append("\n\t\t\t\tP: \"Show\", \"bool\", \"\", \"\",1"); + fbx.Append("\n\t\t\t\tP: \"Freeze\", \"bool\", \"\", \"\",0"); + fbx.Append("\n\t\t\t\tP: \"LODBox\", \"bool\", \"\", \"\",0"); + fbx.Append("\n\t\t\t}"); + fbx.Append("\n\t\t}"); + fbx.Append("\n\t}"); + + fbx.Append("\n\tObjectType: \"Deformer\" {"); + fbx.AppendFormat("\n\t\tCount: {0}", DeformerCount + Skins.Count); + fbx.Append("\n\t}"); + + fbx.Append("\n\tObjectType: \"Pose\" {"); + fbx.Append("\n\t\tCount: 1"); + fbx.Append("\n\t}"); + } + fbx.Append("\n}\n"); fbx.Append("\nObjects: {"); FBXwriter.Write(fbx); - fbx.Length = 0; + fbx.Clear(); #endregion - #region write Models, collect Mesh & Material objects - foreach (var assetsFile in assetsfileList) + #region write Model nodes and connections + StatusStripUpdate("Writing Nodes and hierarchy"); + foreach (var m_GameObject in GameObjects) { - foreach (var m_GameObject in assetsFile.GameObjectList.Values) + if (m_GameObject.m_MeshFilter == null && m_GameObject.m_SkinnedMeshRenderer == null) { - if (m_GameObject.Checked || allNodes) + //NodeAttribute objects will have the same GameObject ID preceded by "2" + if ((bool)Properties.Settings.Default["exportDeformers"] && (bool)Properties.Settings.Default["convertDummies"] && LimbNodes.Contains(m_GameObject)) { - #region write Model and Transform - ob.AppendFormat("\n\tModel: {0}, \"Model::{1}\"", m_GameObject.uniqueID, m_GameObject.m_Name); + ob.AppendFormat("\n\tNodeAttribute: 2{0}, \"NodeAttribute::\", \"LimbNode\" {{", m_GameObject.uniqueID); + ob.Append("\n\t\tTypeFlags: \"Skeleton\""); + ob.Append("\n\t}"); - if (m_GameObject.m_MeshFilter != null || m_GameObject.m_SkinnedMeshRenderer != null) - { - ob.Append(", \"Mesh\" {"); - } - else { ob.Append(", \"Null\" {"); } - - ob.Append("\n\t\tVersion: 232"); - ob.Append("\n\t\tProperties70: {"); - ob.Append("\n\t\t\tP: \"InheritType\", \"enum\", \"\", \"\",1"); - ob.Append("\n\t\t\tP: \"ScalingMax\", \"Vector3D\", \"Vector\", \"\",0,0,0"); - ob.Append("\n\t\t\tP: \"DefaultAttributeIndex\", \"int\", \"Integer\", \"\",0"); - - //connect model to parent - GameObject parentObject = (GameObject)m_GameObject.Parent; - if (parentObject.Checked || allNodes) - { - cb.AppendFormat("\n\tC: \"OO\",{0},{1}", m_GameObject.uniqueID, parentObject.uniqueID); - //if parentObject is a file or folder node, it will have uniqueID 0 - } - else { cb.AppendFormat("\n\tC: \"OO\",{0},0", m_GameObject.uniqueID); }//connect to scene - - Transform m_Transform; - if (assetsfileList.TryGetTransform(m_GameObject.m_Transform, out m_Transform)) - { - float[] m_EulerRotation = QuatToEuler(new float[] { m_Transform.m_LocalRotation[0], -m_Transform.m_LocalRotation[1], -m_Transform.m_LocalRotation[2], m_Transform.m_LocalRotation[3] }); - - ob.AppendFormat("\n\t\t\tP: \"Lcl Translation\", \"Lcl Translation\", \"\", \"A\",{0},{1},{2}", -m_Transform.m_LocalPosition[0], m_Transform.m_LocalPosition[1], m_Transform.m_LocalPosition[2]); - ob.AppendFormat("\n\t\t\tP: \"Lcl Rotation\", \"Lcl Rotation\", \"\", \"A\",{0},{1},{2}", m_EulerRotation[0], m_EulerRotation[1], m_EulerRotation[2]);//handedness is switched in quat - ob.AppendFormat("\n\t\t\tP: \"Lcl Scaling\", \"Lcl Scaling\", \"\", \"A\",{0},{1},{2}", m_Transform.m_LocalScale[0], m_Transform.m_LocalScale[1], m_Transform.m_LocalScale[2]); - } - - //mb.Append("\n\t\t\tP: \"UDP3DSMAX\", \"KString\", \"\", \"U\", \"MapChannel:1 = UVChannel_1&cr;&lf;MapChannel:2 = UVChannel_2&cr;&lf;\""); - //mb.Append("\n\t\t\tP: \"MaxHandle\", \"int\", \"Integer\", \"UH\",24"); - ob.Append("\n\t\t}"); - ob.Append("\n\t\tShading: T"); - ob.Append("\n\t\tCulling: \"CullingOff\"\n\t}"); - #endregion - - #region get MeshFilter - AssetPreloadData MeshFilterPD; - if (assetsfileList.TryGetPD(m_GameObject.m_MeshFilter, out MeshFilterPD)) - { - MeshFilter m_MeshFilter = new MeshFilter(MeshFilterPD); - - AssetPreloadData MeshPD; - if (assetsfileList.TryGetPD(m_MeshFilter.m_Mesh, out MeshPD)) - { - MeshList.Add(MeshPD);//first collect meshes in unique list to use instances and avoid duplicate geometry - cb.AppendFormat("\n\tC: \"OO\",{0},{1}", MeshPD.uniqueID, m_GameObject.uniqueID); - } - } - - /*if (m_GameObject.m_MeshFilter != null && m_GameObject.m_MeshFilter.m_FileID >= 0) - { - var MeshFilterAF = assetsfileList[m_GameObject.m_MeshFilter.m_FileID]; - AssetPreloadData MeshFilterPD; - if (MeshFilterAF.preloadTable.TryGetValue(m_GameObject.m_MeshFilter.m_PathID, out MeshFilterPD)) - { - MeshFilter m_MeshFilter = new MeshFilter(MeshFilterPD); - - if (m_MeshFilter.m_Mesh.m_FileID >= 0) - { - var MeshAF = assetsfileList[m_MeshFilter.m_Mesh.m_FileID]; - AssetPreloadData MeshPD; - if (MeshAF.preloadTable.TryGetValue(m_MeshFilter.m_Mesh.m_PathID, out MeshPD)) - { - MeshList.Add(MeshPD);//first collect meshes in unique list to use instances and avoid duplicate geometry - cb.AppendFormat("\n\tC: \"OO\",{0},{1}", MeshPD.uniqueID, m_GameObject.uniqueID); - } - } - } - }*/ - #endregion - - #region get Renderer - AssetPreloadData RendererPD; - if (assetsfileList.TryGetPD(m_GameObject.m_Renderer, out RendererPD)) - { - Renderer m_Renderer = new Renderer(RendererPD); - - foreach (var MaterialPPtr in m_Renderer.m_Materials) - { - AssetPreloadData MaterialPD; - if (assetsfileList.TryGetPD(MaterialPPtr, out MaterialPD)) - { - MaterialList.Add(MaterialPD); - cb.AppendFormat("\n\tC: \"OO\",{0},{1}", MaterialPD.uniqueID, m_GameObject.uniqueID); - } - } - } - - /*if (m_GameObject.m_Renderer != null && m_GameObject.m_Renderer.m_FileID >= 0) - { - var RendererAF = assetsfileList[m_GameObject.m_Renderer.m_FileID]; - AssetPreloadData RendererPD; - if (RendererAF.preloadTable.TryGetValue(m_GameObject.m_Renderer.m_PathID, out RendererPD)) - { - Renderer m_Renderer = new Renderer(RendererPD); - foreach (var MaterialPPtr in m_Renderer.m_Materials) - { - if (MaterialPPtr.m_FileID >= 0) - { - var MaterialAF = assetsfileList[MaterialPPtr.m_FileID]; - AssetPreloadData MaterialPD; - if (MaterialAF.preloadTable.TryGetValue(MaterialPPtr.m_PathID, out MaterialPD)) - { - MaterialList.Add(MaterialPD); - cb.AppendFormat("\n\tC: \"OO\",{0},{1}", MaterialPD.uniqueID, m_GameObject.uniqueID); - } - } - } - } - }*/ - #endregion - - #region get SkinnedMeshRenderer - AssetPreloadData SkinnedMeshPD; - if (assetsfileList.TryGetPD(m_GameObject.m_SkinnedMeshRenderer, out SkinnedMeshPD)) - { - SkinnedMeshRenderer m_SkinnedMeshRenderer = new SkinnedMeshRenderer(SkinnedMeshPD); - - foreach (var MaterialPPtr in m_SkinnedMeshRenderer.m_Materials) - { - AssetPreloadData MaterialPD; - if (assetsfileList.TryGetPD(MaterialPPtr, out MaterialPD)) - { - MaterialList.Add(MaterialPD); - cb.AppendFormat("\n\tC: \"OO\",{0},{1}", MaterialPD.uniqueID, m_GameObject.uniqueID); - } - } - - AssetPreloadData MeshPD; - if (assetsfileList.TryGetPD(m_SkinnedMeshRenderer.m_Mesh, out MeshPD)) - { - MeshList.Add(MeshPD);//first collect meshes in unique list to use instances and avoid duplicate geometry - cb.AppendFormat("\n\tC: \"OO\",{0},{1}", MeshPD.uniqueID, m_GameObject.uniqueID); - } - } - - /*if (m_GameObject.m_SkinnedMeshRenderer != null && m_GameObject.m_SkinnedMeshRenderer.m_FileID >= 0) - { - var SkinnedMeshAF = assetsfileList[m_GameObject.m_SkinnedMeshRenderer.m_FileID]; - AssetPreloadData SkinnedMeshPD; - if (SkinnedMeshAF.preloadTable.TryGetValue(m_GameObject.m_SkinnedMeshRenderer.m_PathID, out SkinnedMeshPD)) - { - SkinnedMeshRenderer m_SkinnedMeshRenderer = new SkinnedMeshRenderer(SkinnedMeshPD); - - foreach (var MaterialPPtr in m_SkinnedMeshRenderer.m_Materials) - { - if (MaterialPPtr.m_FileID >= 0) - { - var MaterialAF = assetsfileList[MaterialPPtr.m_FileID]; - AssetPreloadData MaterialPD; - if (MaterialAF.preloadTable.TryGetValue(MaterialPPtr.m_PathID, out MaterialPD)) - { - MaterialList.Add(MaterialPD); - cb.AppendFormat("\n\tC: \"OO\",{0},{1}", MaterialPD.uniqueID, m_GameObject.uniqueID); - } - } - } - - if (m_SkinnedMeshRenderer.m_Mesh.m_FileID >= 0) - { - var MeshAF = assetsfileList[m_SkinnedMeshRenderer.m_Mesh.m_FileID]; - AssetPreloadData MeshPD; - if (MeshAF.preloadTable.TryGetValue(m_SkinnedMeshRenderer.m_Mesh.m_PathID, out MeshPD)) - { - MeshList.Add(MeshPD); - cb.AppendFormat("\n\tC: \"OO\",{0},{1}", MeshPD.uniqueID, m_GameObject.uniqueID); - } - } - } - }*/ - #endregion - - //write data 8MB at a time - if (ob.Length > (8 * 0x100000)) - { - FBXwriter.Write(ob); - ob.Length = 0; - } + ob.AppendFormat("\n\tModel: {0}, \"Model::{1}\", \"LimbNode\" {{", m_GameObject.uniqueID, m_GameObject.m_Name); } - } - } - #endregion - - #region write Geometry - foreach (var MeshPD in MeshList) - { - Mesh m_Mesh = new Mesh(MeshPD); - - if (m_Mesh.m_VertexCount > 0)//general failsafe - { - StatusStripUpdate("Writing Geometry: " + m_Mesh.m_Name); - - ob.AppendFormat("\n\tGeometry: {0}, \"Geometry::\", \"Mesh\" {{", MeshPD.uniqueID); - ob.Append("\n\t\tProperties70: {"); - var randomColor = RandomColorGenerator(MeshPD.uniqueID); - ob.AppendFormat("\n\t\t\tP: \"Color\", \"ColorRGB\", \"Color\", \"\",{0},{1},{2}", ((float)randomColor[0] / 255), ((float)randomColor[1] / 255), ((float)randomColor[2] / 255)); - ob.Append("\n\t\t}"); - - #region Vertices - ob.AppendFormat("\n\t\tVertices: *{0} {{\n\t\t\ta: ", m_Mesh.m_VertexCount * 3); - - int c = 3;//vertex components - //skip last value in half4 components - if (m_Mesh.m_Vertices.Length == m_Mesh.m_VertexCount * 4) { c++; } //haha - - //split arrays in groups of 2040 chars - uint f3Lines = m_Mesh.m_VertexCount / 40;//40 verts * 3 components * 17 max chars per float including comma - uint remf3Verts = m_Mesh.m_VertexCount % 40; - - uint f2Lines = m_Mesh.m_VertexCount / 60;//60 UVs * 2 components * 17 max chars per float including comma - uint remf2Verts = m_Mesh.m_VertexCount % 60; - - //this is fast but line length is not optimal - for (int l = 0; l < f3Lines; l++) - { - for (int v = 0; v < 40; v++) - { - ob.AppendFormat("{0},{1},{2},", -m_Mesh.m_Vertices[(l * 40 + v) * c], m_Mesh.m_Vertices[(l * 40 + v) * c + 1], m_Mesh.m_Vertices[(l * 40 + v) * c + 2]); - } - ob.Append("\n"); - } - - if (remf3Verts != 0) - { - for (int v = 0; v < remf3Verts; v++) - { - ob.AppendFormat("{0},{1},{2},", -m_Mesh.m_Vertices[(f3Lines * 40 + v) * c], m_Mesh.m_Vertices[(f3Lines * 40 + v) * c + 1], m_Mesh.m_Vertices[(f3Lines * 40 + v) * c + 2]); - } - } - else { ob.Length--; }//remove last newline - ob.Length--;//remove last comma - - ob.Append("\n\t\t}"); - #endregion - - #region Indices - //in order to test topology for triangles/quads we need to store submeshes and write each one as geometry, then link to Mesh Node - ob.AppendFormat("\n\t\tPolygonVertexIndex: *{0} {{\n\t\t\ta: ", m_Mesh.m_Indices.Count); - - int iLines = m_Mesh.m_Indices.Count / 180; - int remTris = (m_Mesh.m_Indices.Count % 180) / 3; - - for (int l = 0; l < iLines; l++) - { - for (int f = 0; f < 60; f++) - { - ob.AppendFormat("{0},{1},{2},", m_Mesh.m_Indices[l * 180 + f * 3], m_Mesh.m_Indices[l * 180 + f * 3 + 2], (-m_Mesh.m_Indices[l * 180 + f * 3 + 1] - 1)); - } - ob.Append("\n"); - } - - if (remTris != 0) - { - for (int f = 0; f < remTris; f++) - { - ob.AppendFormat("{0},{1},{2},", m_Mesh.m_Indices[iLines * 180 + f * 3], m_Mesh.m_Indices[iLines * 180 + f * 3 + 2], (-m_Mesh.m_Indices[iLines * 180 + f * 3 + 1] - 1)); - } - } - else { ob.Length--; }//remove last newline - ob.Length--;//remove last comma - - ob.Append("\n\t\t}"); - ob.Append("\n\t\tGeometryVersion: 124"); - #endregion - - #region Normals - if ((bool)Properties.Settings.Default["exportNormals"] && m_Mesh.m_Normals != null && m_Mesh.m_Normals.Length > 0) - { - ob.Append("\n\t\tLayerElementNormal: 0 {"); - ob.Append("\n\t\t\tVersion: 101"); - ob.Append("\n\t\t\tName: \"\""); - ob.Append("\n\t\t\tMappingInformationType: \"ByVertice\""); - ob.Append("\n\t\t\tReferenceInformationType: \"Direct\""); - ob.AppendFormat("\n\t\t\tNormals: *{0} {{\n\t\t\ta: ", (m_Mesh.m_VertexCount * 3)); - - if (m_Mesh.m_Normals.Length == m_Mesh.m_VertexCount * 3) { c = 3; } - else if (m_Mesh.m_Normals.Length == m_Mesh.m_VertexCount * 4) { c = 4; } - - for (int l = 0; l < f3Lines; l++) - { - for (int v = 0; v < 40; v++) - { - ob.AppendFormat("{0},{1},{2},", -m_Mesh.m_Normals[(l * 40 + v) * c], m_Mesh.m_Normals[(l * 40 + v) * c + 1], m_Mesh.m_Normals[(l * 40 + v) * c + 2]); - } - ob.Append("\n"); - } - - if (remf3Verts != 0) - { - for (int v = 0; v < remf3Verts; v++) - { - ob.AppendFormat("{0},{1},{2},", -m_Mesh.m_Normals[(f3Lines * 40 + v) * c], m_Mesh.m_Normals[(f3Lines * 40 + v) * c + 1], m_Mesh.m_Normals[(f3Lines * 40 + v) * c + 2]); - } - } - else { ob.Length--; }//remove last newline - ob.Length--;//remove last comma - - ob.Append("\n\t\t\t}\n\t\t}"); - } - #endregion - - #region Colors - - if ((bool)Properties.Settings.Default["exportColors"] && m_Mesh.m_Colors != null && m_Mesh.m_Colors.Length > 0) - { - ob.Append("\n\t\tLayerElementColor: 0 {"); - ob.Append("\n\t\t\tVersion: 101"); - ob.Append("\n\t\t\tName: \"\""); - //ob.Append("\n\t\t\tMappingInformationType: \"ByVertice\""); - //ob.Append("\n\t\t\tReferenceInformationType: \"Direct\""); - ob.Append("\n\t\t\tMappingInformationType: \"ByPolygonVertex\""); - ob.Append("\n\t\t\tReferenceInformationType: \"IndexToDirect\""); - ob.AppendFormat("\n\t\t\tColors: *{0} {{\n\t\t\ta: ", m_Mesh.m_Colors.Length); - //ob.Append(string.Join(",", m_Mesh.m_Colors)); - - int cLines = m_Mesh.m_Colors.Length / 120; - int remCols = m_Mesh.m_Colors.Length % 120; - - for (int l = 0; l < cLines; l++) - { - for (int i = 0; i < 120; i++) - { - ob.AppendFormat("{0},", m_Mesh.m_Colors[l * 120 + i]); - } - ob.Append("\n"); - } - - if (remCols > 0) - { - for (int i = 0; i < remCols; i++) - { - ob.AppendFormat("{0},", m_Mesh.m_Colors[cLines * 120 + i]); - } - } - else { ob.Length--; }//remove last newline - ob.Length--;//remove last comma - - ob.Append("\n\t\t\t}"); - ob.AppendFormat("\n\t\t\tColorIndex: *{0} {{\n\t\t\ta: ", m_Mesh.m_Indices.Count); - - for (int l = 0; l < iLines; l++) - { - for (int f = 0; f < 60; f++) - { - ob.AppendFormat("{0},{1},{2},", m_Mesh.m_Indices[l * 180 + f * 3], m_Mesh.m_Indices[l * 180 + f * 3 + 2], m_Mesh.m_Indices[l * 180 + f * 3 + 1]); - } - ob.Append("\n"); - } - - if (remTris != 0) - { - for (int f = 0; f < remTris; f++) - { - ob.AppendFormat("{0},{1},{2},", m_Mesh.m_Indices[iLines * 180 + f * 3], m_Mesh.m_Indices[iLines * 180 + f * 3 + 2], m_Mesh.m_Indices[iLines * 180 + f * 3 + 1]); - } - } - else { ob.Length--; }//remove last newline - ob.Length--;//remove last comma - - ob.Append("\n\t\t\t}\n\t\t}"); - } - #endregion - - #region UV1 - //does FBX support UVW coordinates? - if ((bool)Properties.Settings.Default["exportUVs"] && m_Mesh.m_UV1 != null && m_Mesh.m_UV1.Length > 0) - { - ob.Append("\n\t\tLayerElementUV: 0 {"); - ob.Append("\n\t\t\tVersion: 101"); - ob.Append("\n\t\t\tName: \"UVChannel_1\""); - ob.Append("\n\t\t\tMappingInformationType: \"ByVertice\""); - ob.Append("\n\t\t\tReferenceInformationType: \"Direct\""); - ob.AppendFormat("\n\t\t\tUV: *{0} {{\n\t\t\ta: ", m_Mesh.m_UV1.Length); - - for (int l = 0; l < f2Lines; l++) - { - for (int v = 0; v < 60; v++) - { - ob.AppendFormat("{0},{1},", m_Mesh.m_UV1[l * 120 + v * 2], 1 - m_Mesh.m_UV1[l * 120 + v * 2 + 1]); - } - ob.Append("\n"); - } - - if (remf2Verts != 0) - { - for (int v = 0; v < remf2Verts; v++) - { - ob.AppendFormat("{0},{1},", m_Mesh.m_UV1[f2Lines * 120 + v * 2], 1 - m_Mesh.m_UV1[f2Lines * 120 + v * 2 + 1]); - } - } - else { ob.Length--; }//remove last newline - ob.Length--;//remove last comma - - ob.Append("\n\t\t\t}\n\t\t}"); - } - #endregion - #region UV2 - if ((bool)Properties.Settings.Default["exportUVs"] && m_Mesh.m_UV2 != null && m_Mesh.m_UV2.Length > 0) - { - ob.Append("\n\t\tLayerElementUV: 1 {"); - ob.Append("\n\t\t\tVersion: 101"); - ob.Append("\n\t\t\tName: \"UVChannel_2\""); - ob.Append("\n\t\t\tMappingInformationType: \"ByVertice\""); - ob.Append("\n\t\t\tReferenceInformationType: \"Direct\""); - ob.AppendFormat("\n\t\t\tUV: *{0} {{\n\t\t\ta: ", m_Mesh.m_UV2.Length); - - for (int l = 0; l < f2Lines; l++) - { - for (int v = 0; v < 60; v++) - { - ob.AppendFormat("{0},{1},", m_Mesh.m_UV2[l * 120 + v * 2], 1 - m_Mesh.m_UV2[l * 120 + v * 2 + 1]); - } - ob.Append("\n"); - } - - if (remf2Verts != 0) - { - for (int v = 0; v < remf2Verts; v++) - { - ob.AppendFormat("{0},{1},", m_Mesh.m_UV2[f2Lines * 120 + v * 2], 1 - m_Mesh.m_UV2[f2Lines * 120 + v * 2 + 1]); - } - } - else { ob.Length--; }//remove last newline - ob.Length--;//remove last comma - - ob.Append("\n\t\t\t}\n\t\t}"); - } - #endregion - #region UV3 - if ((bool)Properties.Settings.Default["exportUVs"] && m_Mesh.m_UV3 != null && m_Mesh.m_UV3.Length > 0) - { - ob.Append("\n\t\tLayerElementUV: 2 {"); - ob.Append("\n\t\t\tVersion: 101"); - ob.Append("\n\t\t\tName: \"UVChannel_3\""); - ob.Append("\n\t\t\tMappingInformationType: \"ByVertice\""); - ob.Append("\n\t\t\tReferenceInformationType: \"Direct\""); - ob.AppendFormat("\n\t\t\tUV: *{0} {{\n\t\t\ta: ", m_Mesh.m_UV3.Length); - - for (int l = 0; l < f2Lines; l++) - { - for (int v = 0; v < 60; v++) - { - ob.AppendFormat("{0},{1},", m_Mesh.m_UV3[l * 120 + v * 2], 1 - m_Mesh.m_UV3[l * 120 + v * 2 + 1]); - } - ob.Append("\n"); - } - - if (remf2Verts != 0) - { - for (int v = 0; v < remf2Verts; v++) - { - ob.AppendFormat("{0},{1},", m_Mesh.m_UV3[f2Lines * 120 + v * 2], 1 - m_Mesh.m_UV3[f2Lines * 120 + v * 2 + 1]); - } - } - else { ob.Length--; }//remove last newline - ob.Length--;//remove last comma - - ob.Append("\n\t\t\t}\n\t\t}"); - } - #endregion - #region UV4 - if ((bool)Properties.Settings.Default["exportUVs"] && m_Mesh.m_UV4 != null && m_Mesh.m_UV4.Length > 0) - { - ob.Append("\n\t\tLayerElementUV: 3 {"); - ob.Append("\n\t\t\tVersion: 101"); - ob.Append("\n\t\t\tName: \"UVChannel_4\""); - ob.Append("\n\t\t\tMappingInformationType: \"ByVertice\""); - ob.Append("\n\t\t\tReferenceInformationType: \"Direct\""); - ob.AppendFormat("\n\t\t\tUV: *{0} {{\n\t\t\ta: ", m_Mesh.m_UV4.Length); - - for (int l = 0; l < f2Lines; l++) - { - for (int v = 0; v < 60; v++) - { - ob.AppendFormat("{0},{1},", m_Mesh.m_UV4[l * 120 + v * 2], 1 - m_Mesh.m_UV4[l * 120 + v * 2 + 1]); - } - ob.Append("\n"); - } - - if (remf2Verts != 0) - { - for (int v = 0; v < remf2Verts; v++) - { - ob.AppendFormat("{0},{1},", m_Mesh.m_UV4[f2Lines * 120 + v * 2], 1 - m_Mesh.m_UV4[f2Lines * 120 + v * 2 + 1]); - } - } - else { ob.Length--; }//remove last newline - ob.Length--;//remove last comma - - ob.Append("\n\t\t\t}\n\t\t}"); - } - #endregion - - #region Material - ob.Append("\n\t\tLayerElementMaterial: 0 {"); - ob.Append("\n\t\t\tVersion: 101"); - ob.Append("\n\t\t\tName: \"\""); - ob.Append("\n\t\t\tMappingInformationType: \""); - if (m_Mesh.m_SubMeshes.Count == 1) { ob.Append("AllSame\""); } - else { ob.Append("ByPolygon\""); } - ob.Append("\n\t\t\tReferenceInformationType: \"IndexToDirect\""); - ob.AppendFormat("\n\t\t\tMaterials: *{0} {{", m_Mesh.m_materialIDs.Count); - ob.Append("\n\t\t\t\t"); - if (m_Mesh.m_SubMeshes.Count == 1) { ob.Append("0"); } else { - int idLines = m_Mesh.m_materialIDs.Count / 500; - int remIds = m_Mesh.m_materialIDs.Count % 500; + ob.AppendFormat("\n\tNodeAttribute: 2{0}, \"NodeAttribute::\", \"Null\" {{", m_GameObject.uniqueID); + ob.Append("\n\t\tTypeFlags: \"Null\""); + ob.Append("\n\t}"); - for (int l = 0; l < idLines; l++) - { - for (int i = 0; i < 500; i++) - { - ob.AppendFormat("{0},", m_Mesh.m_materialIDs[l * 500 + i]); - } - ob.Append("\n"); - } - - if (remIds != 0) - { - for (int i = 0; i < remIds; i++) - { - ob.AppendFormat("{0},", m_Mesh.m_materialIDs[idLines * 500 + i]); - } - } - else { ob.Length--; }//remove last newline - ob.Length--;//remove last comma - } - ob.Append("\n\t\t\t}\n\t\t}"); - #endregion - - #region Layers - ob.Append("\n\t\tLayer: 0 {"); - ob.Append("\n\t\t\tVersion: 100"); - if ((bool)Properties.Settings.Default["exportNormals"] && m_Mesh.m_Normals != null && m_Mesh.m_Normals.Length > 0) - { - ob.Append("\n\t\t\tLayerElement: {"); - ob.Append("\n\t\t\t\tType: \"LayerElementNormal\""); - ob.Append("\n\t\t\t\tTypedIndex: 0"); - ob.Append("\n\t\t\t}"); - } - ob.Append("\n\t\t\tLayerElement: {"); - ob.Append("\n\t\t\t\tType: \"LayerElementMaterial\""); - ob.Append("\n\t\t\t\tTypedIndex: 0"); - ob.Append("\n\t\t\t}"); - // - /*ob.Append("\n\t\t\tLayerElement: {"); - ob.Append("\n\t\t\t\tType: \"LayerElementTexture\""); - ob.Append("\n\t\t\t\tTypedIndex: 0"); - ob.Append("\n\t\t\t}"); - ob.Append("\n\t\t\tLayerElement: {"); - ob.Append("\n\t\t\t\tType: \"LayerElementBumpTextures\""); - ob.Append("\n\t\t\t\tTypedIndex: 0"); - ob.Append("\n\t\t\t}");*/ - if ((bool)Properties.Settings.Default["exportColors"] && m_Mesh.m_Colors != null && m_Mesh.m_Colors.Length > 0) - { - ob.Append("\n\t\t\tLayerElement: {"); - ob.Append("\n\t\t\t\tType: \"LayerElementColor\""); - ob.Append("\n\t\t\t\tTypedIndex: 0"); - ob.Append("\n\t\t\t}"); - } - if ((bool)Properties.Settings.Default["exportUVs"] && m_Mesh.m_UV1 != null && m_Mesh.m_UV1.Length > 0) - { - ob.Append("\n\t\t\tLayerElement: {"); - ob.Append("\n\t\t\t\tType: \"LayerElementUV\""); - ob.Append("\n\t\t\t\tTypedIndex: 0"); - ob.Append("\n\t\t\t}"); - } - ob.Append("\n\t\t}"); //Layer 0 end - - if ((bool)Properties.Settings.Default["exportUVs"] && m_Mesh.m_UV2 != null && m_Mesh.m_UV2.Length > 0) - { - ob.Append("\n\t\tLayer: 1 {"); - ob.Append("\n\t\t\tVersion: 100"); - ob.Append("\n\t\t\tLayerElement: {"); - ob.Append("\n\t\t\t\tType: \"LayerElementUV\""); - ob.Append("\n\t\t\t\tTypedIndex: 1"); - ob.Append("\n\t\t\t}"); - ob.Append("\n\t\t}"); //Layer 1 end + ob.AppendFormat("\n\tModel: {0}, \"Model::{1}\", \"Null\" {{", m_GameObject.uniqueID, m_GameObject.m_Name); } - if ((bool)Properties.Settings.Default["exportUVs"] && m_Mesh.m_UV3 != null && m_Mesh.m_UV3.Length > 0) - { - ob.Append("\n\t\tLayer: 2 {"); - ob.Append("\n\t\t\tVersion: 100"); - ob.Append("\n\t\t\tLayerElement: {"); - ob.Append("\n\t\t\t\tType: \"LayerElementUV\""); - ob.Append("\n\t\t\t\tTypedIndex: 2"); - ob.Append("\n\t\t\t}"); - ob.Append("\n\t\t}"); //Layer 2 end - } - - if ((bool)Properties.Settings.Default["exportUVs"] && m_Mesh.m_UV4 != null && m_Mesh.m_UV4.Length > 0) - { - ob.Append("\n\t\tLayer: 3 {"); - ob.Append("\n\t\t\tVersion: 100"); - ob.Append("\n\t\t\tLayerElement: {"); - ob.Append("\n\t\t\t\tType: \"LayerElementUV\""); - ob.Append("\n\t\t\t\tTypedIndex: 3"); - ob.Append("\n\t\t\t}"); - ob.Append("\n\t\t}"); //Layer 3 end - } - #endregion - - ob.Append("\n\t}"); //Geometry end - - //write data 8MB at a time - if (ob.Length > (8 * 0x100000)) - { - FBXwriter.Write(ob); - ob.Length = 0; - } + //connect NodeAttribute to Model + cb.AppendFormat("\n\n\t;NodeAttribute::, Model::{0}", m_GameObject.m_Name); + cb.AppendFormat("\n\tC: \"OO\",2{0},{0}", m_GameObject.uniqueID); } + else + { + ob.AppendFormat("\n\tModel: {0}, \"Model::{1}\", \"Mesh\" {{", m_GameObject.uniqueID, m_GameObject.m_Name); + } + + ob.Append("\n\t\tVersion: 232"); + ob.Append("\n\t\tProperties70: {"); + ob.Append("\n\t\t\tP: \"InheritType\", \"enum\", \"\", \"\",1"); + ob.Append("\n\t\t\tP: \"ScalingMax\", \"Vector3D\", \"Vector\", \"\",0,0,0"); + ob.Append("\n\t\t\tP: \"DefaultAttributeIndex\", \"int\", \"Integer\", \"\",0"); + + Transform m_Transform; + if (assetsfileList.TryGetTransform(m_GameObject.m_Transform, out m_Transform)) + { + float[] m_EulerRotation = QuatToEuler(new float[] { m_Transform.m_LocalRotation[0], -m_Transform.m_LocalRotation[1], -m_Transform.m_LocalRotation[2], m_Transform.m_LocalRotation[3] }); + + ob.AppendFormat("\n\t\t\tP: \"Lcl Translation\", \"Lcl Translation\", \"\", \"A\",{0},{1},{2}", -m_Transform.m_LocalPosition[0], m_Transform.m_LocalPosition[1], m_Transform.m_LocalPosition[2]); + ob.AppendFormat("\n\t\t\tP: \"Lcl Rotation\", \"Lcl Rotation\", \"\", \"A\",{0},{1},{2}", m_EulerRotation[0], m_EulerRotation[1], m_EulerRotation[2]);//handedness is switched in quat + ob.AppendFormat("\n\t\t\tP: \"Lcl Scaling\", \"Lcl Scaling\", \"\", \"A\",{0},{1},{2}", m_Transform.m_LocalScale[0], m_Transform.m_LocalScale[1], m_Transform.m_LocalScale[2]); + } + + //mb.Append("\n\t\t\tP: \"UDP3DSMAX\", \"KString\", \"\", \"U\", \"MapChannel:1 = UVChannel_1&cr;&lf;MapChannel:2 = UVChannel_2&cr;&lf;\""); + //mb.Append("\n\t\t\tP: \"MaxHandle\", \"int\", \"Integer\", \"UH\",24"); + ob.Append("\n\t\t}"); + ob.Append("\n\t\tShading: T"); + ob.Append("\n\t\tCulling: \"CullingOff\"\n\t}"); + + //connect Model to parent + GameObject parentObject = (GameObject)m_GameObject.Parent; + if (GameObjects.Contains(parentObject)) + { + cb.AppendFormat("\n\n\t;Model::{0}, Model::{1}", m_GameObject.m_Name, parentObject.m_Name); + cb.AppendFormat("\n\tC: \"OO\",{0},{1}", m_GameObject.uniqueID, parentObject.uniqueID); + } + else + { + cb.AppendFormat("\n\n\t;Model::{0}, Model::RootNode", m_GameObject.m_Name); + cb.AppendFormat("\n\tC: \"OO\",{0},0", m_GameObject.uniqueID); + } + + } #endregion - #region write Materials, collect Texture objects - StatusStripUpdate("Writing Materials"); - foreach (var MaterialPD in MaterialList) + #region write non-skinnned Geometry + StatusStripUpdate("Writing Geometry"); + foreach (var MeshPD in Meshes) { - Material m_Material = new Material(MaterialPD); + Mesh m_Mesh = new Mesh(MeshPD); + MeshFBX(m_Mesh, MeshPD.uniqueID, ob); - ob.AppendFormat("\n\tMaterial: {0}, \"Material::{1}\", \"\" {{", MaterialPD.uniqueID, m_Material.m_Name); - ob.Append("\n\t\tVersion: 102"); - ob.Append("\n\t\tShadingModel: \"phong\""); - ob.Append("\n\t\tMultiLayer: 0"); - ob.Append("\n\t\tProperties70: {"); - ob.Append("\n\t\t\tP: \"ShadingModel\", \"KString\", \"\", \"\", \"phong\""); + //write data 8MB at a time + if (ob.Length > (8 * 0x100000)) + { FBXwriter.Write(ob); ob.Clear(); } + } + #endregion - #region write material colors - foreach (var m_Color in m_Material.m_Colors) + #region write Deformer objects and skinned Geometry + StringBuilder pb = new StringBuilder(); + //generate unique ID for BindPose + pb.Append("\n\tPose: 5123456789, \"Pose::BIND_POSES\", \"BindPose\" {"); + pb.Append("\n\t\tType: \"BindPose\""); + pb.Append("\n\t\tVersion: 100"); + pb.AppendFormat("\n\t\tNbPoseNodes: {0}", Skins.Count + LimbNodes.Count); + + foreach (var SkinnedMeshPD in Skins) + { + SkinnedMeshRenderer m_SkinnedMeshRenderer = new SkinnedMeshRenderer(SkinnedMeshPD); + + GameObject m_GameObject; + AssetPreloadData MeshPD; + if (assetsfileList.TryGetGameObject(m_SkinnedMeshRenderer.m_GameObject, out m_GameObject) && assetsfileList.TryGetPD(m_SkinnedMeshRenderer.m_Mesh, out MeshPD)) { - switch (m_Color.first) - { - case "_Color": - case "gSurfaceColor": - ob.AppendFormat("\n\t\t\tP: \"DiffuseColor\", \"Color\", \"\", \"A\",{0},{1},{2}", m_Color.second[0], m_Color.second[1], m_Color.second[2]); - break; - case "_SpecColor": - ob.AppendFormat("\n\t\t\tP: \"SpecularColor\", \"Color\", \"\", \"A\",{0},{1},{2}", m_Color.second[0], m_Color.second[1], m_Color.second[2]); - break; - case "_ReflectColor": - ob.AppendFormat("\n\t\t\tP: \"AmbientColor\", \"Color\", \"\", \"A\",{0},{1},{2}", m_Color.second[0], m_Color.second[1], m_Color.second[2]); - break; - default: - ob.AppendFormat("\n;\t\t\tP: \"{3}\", \"Color\", \"\", \"A\",{0},{1},{2}", m_Color.second[0], m_Color.second[1], m_Color.second[2], m_Color.first);//commented out - break; - } - } - #endregion + Mesh m_Mesh = new Mesh(MeshPD); + MeshFBX(m_Mesh, MeshPD.uniqueID, ob); + + //write data 8MB at a time + if (ob.Length > (8 * 0x100000)) + { FBXwriter.Write(ob); ob.Clear(); } - #region write material parameters - foreach (var m_Float in m_Material.m_Floats) - { - switch (m_Float.first) + cb2.AppendFormat("\n\n\t;Geometry::, Model::{0}", m_GameObject.m_Name); + cb2.AppendFormat("\n\tC: \"OO\",{0},{1}", MeshPD.uniqueID, m_GameObject.uniqueID); + + if ((bool)Properties.Settings.Default["exportDeformers"]) { - case "_Shininess": - ob.AppendFormat("\n\t\t\tP: \"ShininessExponent\", \"Number\", \"\", \"A\",{0}", m_Float.second); - break; - default: - ob.AppendFormat("\n;\t\t\tP: \"{0}\", \"Number\", \"\", \"A\",{1}", m_Float.first, m_Float.second); - break; - } - } - #endregion + //add BindPose node + pb.Append("\n\t\tPoseNode: {"); + pb.AppendFormat("\n\t\t\tNode: {0}", m_GameObject.uniqueID); + //pb.Append("\n\t\t\tMatrix: *16 {"); + //pb.Append("\n\t\t\t\ta: "); + //pb.Append("\n\t\t\t} "); + pb.Append("\n\t\t}"); - //ob.Append("\n\t\t\tP: \"SpecularFactor\", \"Number\", \"\", \"A\",0"); - ob.Append("\n\t\t}"); - ob.Append("\n\t}"); + //write DisplayLayer with SkinnedMeshRenderer ID preceded by "3" + ob.AppendFormat("\n\tCollectionExclusive: 3{0}, \"DisplayLayer::{0}\", \"DisplayLayer\" {{", SkinnedMeshPD.uniqueID); + ob.Append("\n\t\tProperties70: {"); + ob.Append("\n\t\t}"); + ob.Append("\n\t}"); - #region write texture connections - foreach (var m_TexEnv in m_Material.m_TexEnvs) - { - AssetPreloadData TexturePD; - if (assetsfileList.TryGetPD(m_TexEnv.m_Texture, out TexturePD)) - { + //connect Model to DisplayLayer + cb2.AppendFormat("\n\n\t;Model::{0}, DisplayLayer::", m_GameObject.m_Name); + cb2.AppendFormat("\n\tC: \"OO\",{0},3{1}", m_GameObject.uniqueID, SkinnedMeshPD.uniqueID); - } - else if (jsonMats != null) - { - Dictionary matProp; - if (jsonMats.TryGetValue(m_Material.m_Name, out matProp)) + //write Deformers + if (m_Mesh.m_Skin.Length > 0) { - string texName; - if (matProp.TryGetValue(m_TexEnv.name, out texName)) + //write main Skin Deformer + ob.AppendFormat("\n\tDeformer: {0}, \"Deformer::\", \"Skin\" {{", SkinnedMeshPD.uniqueID); + ob.Append("\n\t\tVersion: 101"); + ob.Append("\n\t\tLink_DeformAcuracy: 50"); + ob.Append("\n\t}"); //Deformer end + + //connect Skin Deformer to Geometry + cb2.Append("\n\t;Deformer::, Geometry::"); + cb2.AppendFormat("\n\tC: \"OO\",{0},{1}", SkinnedMeshPD.uniqueID, MeshPD.uniqueID); + + for (int b = 0; b < m_SkinnedMeshRenderer.m_Bones.Length; b++) { - foreach (var asset in exportableAssets) + Transform m_Transform; + if (assetsfileList.TryGetTransform(m_SkinnedMeshRenderer.m_Bones[b], out m_Transform)) { - if (asset.Type2 == 28 && asset.Text == texName) + GameObject m_Bone; + if (assetsfileList.TryGetGameObject(m_Transform.m_GameObject, out m_Bone)) { - TexturePD = asset; - break; + int influences = 0, ibSplit = 0, wbSplit = 0; + StringBuilder ib = new StringBuilder();//indices (vertex) + StringBuilder wb = new StringBuilder();//weights + + for (int index = 0; index < m_Mesh.m_Skin.Length; index++) + { + if (m_Mesh.m_Skin[index][0].weight == 0 && (m_Mesh.m_Skin[index].All(x => x.weight == 0) || //if all weights (and indicces) are 0, bone0 has full control + m_Mesh.m_Skin[index][1].weight > 0)) //this implies a second bone exists, so bone0 has control too (otherwise it wouldn't be the first in the series) + { m_Mesh.m_Skin[index][0].weight = 1; } + + var influence = m_Mesh.m_Skin[index].Find(x => x.boneIndex == b && x.weight > 0); + if (influence != null) + { + influences++; + ib.AppendFormat("{0},", index); + wb.AppendFormat("{0},", influence.weight); + + if (ib.Length - ibSplit > 2000) { ib.Append("\n"); ibSplit = ib.Length; } + if (wb.Length - wbSplit > 2000) { wb.Append("\n"); wbSplit = wb.Length; } + } + + /*float weight; + if (m_Mesh.m_Skin[index].TryGetValue(b, out weight)) + { + if (weight > 0) + { + influences++; + ib.AppendFormat("{0},", index); + wb.AppendFormat("{0},", weight); + } + else if (m_Mesh.m_Skin[index].Keys.Count == 1)//m_Mesh.m_Skin[index].Values.All(x => x == 0) + { + influences++; + ib.AppendFormat("{0},", index); + wb.AppendFormat("{0},", 1); + } + + if (ib.Length - ibSplit > 2000) { ib.Append("\n"); ibSplit = ib.Length; } + if (wb.Length - wbSplit > 2000) { wb.Append("\n"); wbSplit = wb.Length; } + }*/ + } + if (influences > 0) + { + ib.Length--;//remove last comma + wb.Length--;//remove last comma + } + + //SubDeformer objects need unique IDs because 2 or more deformers can be attached to the same bone + ob.AppendFormat("\n\tDeformer: 1{0}{1}, \"SubDeformer::\", \"Cluster\" {{", b, SkinnedMeshPD.uniqueID); + ob.Append("\n\t\tVersion: 100"); + ob.Append("\n\t\tUserData: \"\", \"\""); + + ob.AppendFormat("\n\t\tIndexes: *{0} {{\n\t\t\ta: ", influences); + ob.Append(ib); + ob.Append("\n\t\t}"); + ib.Clear(); + + ob.AppendFormat("\n\t\tWeights: *{0} {{\n\t\t\ta: ", influences); + ob.Append(wb); + ob.Append("\n\t\t}"); + wb.Clear(); + + ob.Append("\n\t\tTransform: *16 {\n\t\t\ta: "); + //ob.Append(string.Join(",", m_Mesh.m_BindPose[b])); + var m = m_Mesh.m_BindPose[b]; + ob.AppendFormat("{0},{1},{2},{3},", m[0, 0], -m[1, 0], -m[2, 0], m[3, 0]); + ob.AppendFormat("{0},{1},{2},{3},", -m[0, 1], m[1, 1], m[2, 1], m[3, 1]); + ob.AppendFormat("{0},{1},{2},{3},", -m[0, 2], m[1, 2], m[2, 2], m[3, 2]); + ob.AppendFormat("{0},{1},{2},{3},", -m[0, 3], m[1, 3], m[2, 3], m[3, 3]); + ob.Append("\n\t\t}"); + + ob.Append("\n\t}"); //SubDeformer end + + //connect SubDeformer to Skin Deformer + cb2.Append("\n\n\t;SubDeformer::, Deformer::"); + cb2.AppendFormat("\n\tC: \"OO\",1{0}{1},{1}", b, SkinnedMeshPD.uniqueID); + + //connect dummy to SubDeformer + cb2.AppendFormat("\n\n\t;Model::{0}, SubDeformer::", m_Bone.m_Name); + cb2.AppendFormat("\n\tC: \"OO\",{0},1{1}{2}", m_Bone.uniqueID, b, SkinnedMeshPD.uniqueID); } } } } } - - if (TexturePD != null) - { - TextureList.Add(TexturePD); - - cb.AppendFormat("\n\tC: \"OP\",{0},{1}, \"", TexturePD.uniqueID, MaterialPD.uniqueID); - switch (m_TexEnv.name) - { - case "_MainTex": - case "gDiffuseSampler": - cb.Append("DiffuseColor\""); - break; - case "_SpecularMap": - case "gSpecularSampler": - cb.Append("SpecularColor\""); - break; - case "_NormalMap": - case "_BumpMap": - case "gNormalSampler": - cb.Append("NormalMap\""); - break; - default: - cb.AppendFormat("{0}\"", m_TexEnv.name); - break; - } - } } - #endregion + } + + if ((bool)Properties.Settings.Default["exportDeformers"]) + { + foreach (var m_Bone in LimbNodes) + { + //add BindPose node + pb.Append("\n\t\tPoseNode: {"); + pb.AppendFormat("\n\t\t\tNode: {0}", m_Bone.uniqueID); + //pb.Append("\n\t\t\tMatrix: *16 {"); + //pb.Append("\n\t\t\t\ta: "); + //pb.Append("\n\t\t\t} "); + pb.Append("\n\t\t}"); + } + pb.Append("\n\t}"); //BindPose end + ob.Append(pb); pb.Clear(); } #endregion + ob.Append(mb); mb.Clear(); + cb.Append(cb2); cb2.Clear(); + #region write & extract Textures Directory.CreateDirectory(Path.GetDirectoryName(FBXfile) + "\\Texture2D"); - foreach (var TexturePD in TextureList) + foreach (var TexturePD in Textures) { Texture2D m_Texture2D = new Texture2D(TexturePD, true); @@ -2586,6 +2366,7 @@ namespace Unity_Studio ob.Append("\n\t}"); //connect video to texture + cb.AppendFormat("\n\n\t;Video::{0}, Texture::{0}", TexturePD.Text); cb.AppendFormat("\n\tC: \"OO\",1{0},{1}", TexturePD.uniqueID, TexturePD.uniqueID); } #endregion @@ -2601,6 +2382,381 @@ namespace Unity_Studio } } + private void MeshFBX(Mesh m_Mesh, string MeshID, StringBuilder ob) + { + if (m_Mesh.m_VertexCount > 0)//general failsafe + { + StatusStripUpdate("Writing Geometry: " + m_Mesh.m_Name); + + ob.AppendFormat("\n\tGeometry: {0}, \"Geometry::\", \"Mesh\" {{", MeshID); + ob.Append("\n\t\tProperties70: {"); + var randomColor = RandomColorGenerator(m_Mesh.m_Name); + ob.AppendFormat("\n\t\t\tP: \"Color\", \"ColorRGB\", \"Color\", \"\",{0},{1},{2}", ((float)randomColor[0] / 255), ((float)randomColor[1] / 255), ((float)randomColor[2] / 255)); + ob.Append("\n\t\t}"); + + #region Vertices + ob.AppendFormat("\n\t\tVertices: *{0} {{\n\t\t\ta: ", m_Mesh.m_VertexCount * 3); + + int c = 3;//vertex components + //skip last component in vector4 + if (m_Mesh.m_Vertices.Length == m_Mesh.m_VertexCount * 4) { c++; } //haha + + int lineSplit = ob.Length; + for (int v = 0; v < m_Mesh.m_VertexCount; v++) + { + ob.AppendFormat("{0},{1},{2},", -m_Mesh.m_Vertices[v * c], m_Mesh.m_Vertices[v * c + 1], m_Mesh.m_Vertices[v * c + 2]); + + if (ob.Length - lineSplit > 2000) + { + ob.Append("\n"); + lineSplit = ob.Length; + } + } + ob.Length--;//remove last comma + ob.Append("\n\t\t}"); + #endregion + + #region Indices + //in order to test topology for triangles/quads we need to store submeshes and write each one as geometry, then link to Mesh Node + ob.AppendFormat("\n\t\tPolygonVertexIndex: *{0} {{\n\t\t\ta: ", m_Mesh.m_Indices.Count); + + lineSplit = ob.Length; + for (int f = 0; f < m_Mesh.m_Indices.Count / 3; f++) + { + ob.AppendFormat("{0},{1},{2},", m_Mesh.m_Indices[f * 3], m_Mesh.m_Indices[f * 3 + 2], (-m_Mesh.m_Indices[f * 3 + 1] - 1)); + + if (ob.Length - lineSplit > 2000) + { + ob.Append("\n"); + lineSplit = ob.Length; + } + } + ob.Length--;//remove last comma + + ob.Append("\n\t\t}"); + ob.Append("\n\t\tGeometryVersion: 124"); + #endregion + + #region Normals + if ((bool)Properties.Settings.Default["exportNormals"] && m_Mesh.m_Normals != null && m_Mesh.m_Normals.Length > 0) + { + ob.Append("\n\t\tLayerElementNormal: 0 {"); + ob.Append("\n\t\t\tVersion: 101"); + ob.Append("\n\t\t\tName: \"\""); + ob.Append("\n\t\t\tMappingInformationType: \"ByVertice\""); + ob.Append("\n\t\t\tReferenceInformationType: \"Direct\""); + ob.AppendFormat("\n\t\t\tNormals: *{0} {{\n\t\t\ta: ", (m_Mesh.m_VertexCount * 3)); + + if (m_Mesh.m_Normals.Length == m_Mesh.m_VertexCount * 3) { c = 3; } + else if (m_Mesh.m_Normals.Length == m_Mesh.m_VertexCount * 4) { c = 4; } + + lineSplit = ob.Length; + for (int v = 0; v < m_Mesh.m_VertexCount; v++) + { + ob.AppendFormat("{0},{1},{2},", -m_Mesh.m_Normals[v * c], m_Mesh.m_Normals[v * c + 1], m_Mesh.m_Normals[v * c + 2]); + + if (ob.Length - lineSplit > 2000) + { + ob.Append("\n"); + lineSplit = ob.Length; + } + } + ob.Length--;//remove last comma + ob.Append("\n\t\t\t}\n\t\t}"); + } + #endregion + + #region Tangents + if ((bool)Properties.Settings.Default["exportTangents"] && m_Mesh.m_Tangents != null && m_Mesh.m_Tangents.Length > 0) + { + ob.Append("\n\t\tLayerElementTangent: 0 {"); + ob.Append("\n\t\t\tVersion: 101"); + ob.Append("\n\t\t\tName: \"\""); + ob.Append("\n\t\t\tMappingInformationType: \"ByVertice\""); + ob.Append("\n\t\t\tReferenceInformationType: \"Direct\""); + ob.AppendFormat("\n\t\t\tTangents: *{0} {{\n\t\t\ta: ", (m_Mesh.m_VertexCount * 3)); + + if (m_Mesh.m_Tangents.Length == m_Mesh.m_VertexCount * 3) { c = 3; } + else if (m_Mesh.m_Tangents.Length == m_Mesh.m_VertexCount * 4) { c = 4; } + + lineSplit = ob.Length; + for (int v = 0; v < m_Mesh.m_VertexCount; v++) + { + ob.AppendFormat("{0},{1},{2},", -m_Mesh.m_Tangents[v * c], m_Mesh.m_Tangents[v * c + 1], m_Mesh.m_Tangents[v * c + 2]); + + if (ob.Length - lineSplit > 2000) + { + ob.Append("\n"); + lineSplit = ob.Length; + } + } + ob.Length--;//remove last comma + ob.Append("\n\t\t\t}\n\t\t}"); + } + #endregion + + #region Colors + if ((bool)Properties.Settings.Default["exportColors"] && m_Mesh.m_Colors != null && m_Mesh.m_Colors.Length > 0) + { + ob.Append("\n\t\tLayerElementColor: 0 {"); + ob.Append("\n\t\t\tVersion: 101"); + ob.Append("\n\t\t\tName: \"\""); + //ob.Append("\n\t\t\tMappingInformationType: \"ByVertice\""); + //ob.Append("\n\t\t\tReferenceInformationType: \"Direct\""); + ob.Append("\n\t\t\tMappingInformationType: \"ByPolygonVertex\""); + ob.Append("\n\t\t\tReferenceInformationType: \"IndexToDirect\""); + ob.AppendFormat("\n\t\t\tColors: *{0} {{\n\t\t\ta: ", m_Mesh.m_Colors.Length); + //ob.Append(string.Join(",", m_Mesh.m_Colors)); + + lineSplit = ob.Length; + for (int i = 0; i < m_Mesh.m_VertexCount; i++) + { + ob.AppendFormat("{0},{1},{2},{3},", m_Mesh.m_Colors[i * 2], m_Mesh.m_Colors[i * 2 + 1], m_Mesh.m_Colors[i * 2 + 2], m_Mesh.m_Colors[i * 2 + 3]); + + if (ob.Length - lineSplit > 2000) + { + ob.Append("\n"); + lineSplit = ob.Length; + } + + } + ob.Length--;//remove last comma + + ob.Append("\n\t\t\t}"); + ob.AppendFormat("\n\t\t\tColorIndex: *{0} {{\n\t\t\ta: ", m_Mesh.m_Indices.Count); + + lineSplit = ob.Length; + for (int f = 0; f < m_Mesh.m_Indices.Count / 3; f++) + { + ob.AppendFormat("{0},{1},{2},", m_Mesh.m_Indices[f * 3], m_Mesh.m_Indices[f * 3 + 2], m_Mesh.m_Indices[f * 3 + 1]); + + if (ob.Length - lineSplit > 2000) + { + ob.Append("\n"); + lineSplit = ob.Length; + } + } + ob.Length--;//remove last comma + + ob.Append("\n\t\t\t}\n\t\t}"); + } + #endregion + + #region UV1 + //does FBX support UVW coordinates? + if ((bool)Properties.Settings.Default["exportUVs"] && m_Mesh.m_UV1 != null && m_Mesh.m_UV1.Length > 0) + { + ob.Append("\n\t\tLayerElementUV: 0 {"); + ob.Append("\n\t\t\tVersion: 101"); + ob.Append("\n\t\t\tName: \"UVChannel_1\""); + ob.Append("\n\t\t\tMappingInformationType: \"ByVertice\""); + ob.Append("\n\t\t\tReferenceInformationType: \"Direct\""); + ob.AppendFormat("\n\t\t\tUV: *{0} {{\n\t\t\ta: ", m_Mesh.m_UV1.Length); + + lineSplit = ob.Length; + for (int v = 0; v < m_Mesh.m_VertexCount; v++) + { + ob.AppendFormat("{0},{1},", m_Mesh.m_UV1[v * 2], 1 - m_Mesh.m_UV1[v * 2 + 1]); + + if (ob.Length - lineSplit > 2000) + { + ob.Append("\n"); + lineSplit = ob.Length; + } + } + ob.Length--;//remove last comma + ob.Append("\n\t\t\t}\n\t\t}"); + } + #endregion + #region UV2 + if ((bool)Properties.Settings.Default["exportUVs"] && m_Mesh.m_UV2 != null && m_Mesh.m_UV2.Length > 0) + { + ob.Append("\n\t\tLayerElementUV: 1 {"); + ob.Append("\n\t\t\tVersion: 101"); + ob.Append("\n\t\t\tName: \"UVChannel_2\""); + ob.Append("\n\t\t\tMappingInformationType: \"ByVertice\""); + ob.Append("\n\t\t\tReferenceInformationType: \"Direct\""); + ob.AppendFormat("\n\t\t\tUV: *{0} {{\n\t\t\ta: ", m_Mesh.m_UV2.Length); + + lineSplit = ob.Length; + for (int v = 0; v < m_Mesh.m_VertexCount; v++) + { + ob.AppendFormat("{0},{1},", m_Mesh.m_UV2[v * 2], 1 - m_Mesh.m_UV2[v * 2 + 1]); + + if (ob.Length - lineSplit > 2000) + { + ob.Append("\n"); + lineSplit = ob.Length; + } + } + ob.Length--;//remove last comma + ob.Append("\n\t\t\t}\n\t\t}"); + } + #endregion + #region UV3 + if ((bool)Properties.Settings.Default["exportUVs"] && m_Mesh.m_UV3 != null && m_Mesh.m_UV3.Length > 0) + { + ob.Append("\n\t\tLayerElementUV: 2 {"); + ob.Append("\n\t\t\tVersion: 101"); + ob.Append("\n\t\t\tName: \"UVChannel_3\""); + ob.Append("\n\t\t\tMappingInformationType: \"ByVertice\""); + ob.Append("\n\t\t\tReferenceInformationType: \"Direct\""); + ob.AppendFormat("\n\t\t\tUV: *{0} {{\n\t\t\ta: ", m_Mesh.m_UV3.Length); + + lineSplit = ob.Length; + for (int v = 0; v < m_Mesh.m_VertexCount; v++) + { + ob.AppendFormat("{0},{1},", m_Mesh.m_UV3[v * 2], 1 - m_Mesh.m_UV3[v * 2 + 1]); + + if (ob.Length - lineSplit > 2000) + { + ob.Append("\n"); + lineSplit = ob.Length; + } + } + ob.Length--;//remove last comma + ob.Append("\n\t\t\t}\n\t\t}"); + } + #endregion + #region UV4 + if ((bool)Properties.Settings.Default["exportUVs"] && m_Mesh.m_UV4 != null && m_Mesh.m_UV4.Length > 0) + { + ob.Append("\n\t\tLayerElementUV: 3 {"); + ob.Append("\n\t\t\tVersion: 101"); + ob.Append("\n\t\t\tName: \"UVChannel_4\""); + ob.Append("\n\t\t\tMappingInformationType: \"ByVertice\""); + ob.Append("\n\t\t\tReferenceInformationType: \"Direct\""); + ob.AppendFormat("\n\t\t\tUV: *{0} {{\n\t\t\ta: ", m_Mesh.m_UV4.Length); + + lineSplit = ob.Length; + for (int v = 0; v < m_Mesh.m_VertexCount; v++) + { + ob.AppendFormat("{0},{1},", m_Mesh.m_UV4[v * 2], 1 - m_Mesh.m_UV4[v * 2 + 1]); + + if (ob.Length - lineSplit > 2000) + { + ob.Append("\n"); + lineSplit = ob.Length; + } + } + ob.Length--;//remove last comma + ob.Append("\n\t\t\t}\n\t\t}"); + } + #endregion + + #region Material + ob.Append("\n\t\tLayerElementMaterial: 0 {"); + ob.Append("\n\t\t\tVersion: 101"); + ob.Append("\n\t\t\tName: \"\""); + ob.Append("\n\t\t\tMappingInformationType: \""); + if (m_Mesh.m_SubMeshes.Count == 1) { ob.Append("AllSame\""); } + else { ob.Append("ByPolygon\""); } + ob.Append("\n\t\t\tReferenceInformationType: \"IndexToDirect\""); + ob.AppendFormat("\n\t\t\tMaterials: *{0} {{", m_Mesh.m_materialIDs.Count); + ob.Append("\n\t\t\t\t"); + if (m_Mesh.m_SubMeshes.Count == 1) { ob.Append("0"); } + else + { + lineSplit = ob.Length; + for (int i = 0; i < m_Mesh.m_materialIDs.Count; i++) + { + ob.AppendFormat("{0},", m_Mesh.m_materialIDs[i]); + + if (ob.Length - lineSplit > 2000) + { + ob.Append("\n"); + lineSplit = ob.Length; + } + } + ob.Length--;//remove last comma + } + ob.Append("\n\t\t\t}\n\t\t}"); + #endregion + + #region Layers + ob.Append("\n\t\tLayer: 0 {"); + ob.Append("\n\t\t\tVersion: 100"); + if ((bool)Properties.Settings.Default["exportNormals"] && m_Mesh.m_Normals != null && m_Mesh.m_Normals.Length > 0) + { + ob.Append("\n\t\t\tLayerElement: {"); + ob.Append("\n\t\t\t\tType: \"LayerElementNormal\""); + ob.Append("\n\t\t\t\tTypedIndex: 0"); + ob.Append("\n\t\t\t}"); + } + if ((bool)Properties.Settings.Default["exportTangents"] && m_Mesh.m_Tangents != null && m_Mesh.m_Tangents.Length > 0) + { + ob.Append("\n\t\t\tLayerElement: {"); + ob.Append("\n\t\t\t\tType: \"LayerElementTangent\""); + ob.Append("\n\t\t\t\tTypedIndex: 0"); + ob.Append("\n\t\t\t}"); + } + ob.Append("\n\t\t\tLayerElement: {"); + ob.Append("\n\t\t\t\tType: \"LayerElementMaterial\""); + ob.Append("\n\t\t\t\tTypedIndex: 0"); + ob.Append("\n\t\t\t}"); + // + /*ob.Append("\n\t\t\tLayerElement: {"); + ob.Append("\n\t\t\t\tType: \"LayerElementTexture\""); + ob.Append("\n\t\t\t\tTypedIndex: 0"); + ob.Append("\n\t\t\t}"); + ob.Append("\n\t\t\tLayerElement: {"); + ob.Append("\n\t\t\t\tType: \"LayerElementBumpTextures\""); + ob.Append("\n\t\t\t\tTypedIndex: 0"); + ob.Append("\n\t\t\t}");*/ + if ((bool)Properties.Settings.Default["exportColors"] && m_Mesh.m_Colors != null && m_Mesh.m_Colors.Length > 0) + { + ob.Append("\n\t\t\tLayerElement: {"); + ob.Append("\n\t\t\t\tType: \"LayerElementColor\""); + ob.Append("\n\t\t\t\tTypedIndex: 0"); + ob.Append("\n\t\t\t}"); + } + if ((bool)Properties.Settings.Default["exportUVs"] && m_Mesh.m_UV1 != null && m_Mesh.m_UV1.Length > 0) + { + ob.Append("\n\t\t\tLayerElement: {"); + ob.Append("\n\t\t\t\tType: \"LayerElementUV\""); + ob.Append("\n\t\t\t\tTypedIndex: 0"); + ob.Append("\n\t\t\t}"); + } + ob.Append("\n\t\t}"); //Layer 0 end + + if ((bool)Properties.Settings.Default["exportUVs"] && m_Mesh.m_UV2 != null && m_Mesh.m_UV2.Length > 0) + { + ob.Append("\n\t\tLayer: 1 {"); + ob.Append("\n\t\t\tVersion: 100"); + ob.Append("\n\t\t\tLayerElement: {"); + ob.Append("\n\t\t\t\tType: \"LayerElementUV\""); + ob.Append("\n\t\t\t\tTypedIndex: 1"); + ob.Append("\n\t\t\t}"); + ob.Append("\n\t\t}"); //Layer 1 end + } + + if ((bool)Properties.Settings.Default["exportUVs"] && m_Mesh.m_UV3 != null && m_Mesh.m_UV3.Length > 0) + { + ob.Append("\n\t\tLayer: 2 {"); + ob.Append("\n\t\t\tVersion: 100"); + ob.Append("\n\t\t\tLayerElement: {"); + ob.Append("\n\t\t\t\tType: \"LayerElementUV\""); + ob.Append("\n\t\t\t\tTypedIndex: 2"); + ob.Append("\n\t\t\t}"); + ob.Append("\n\t\t}"); //Layer 2 end + } + + if ((bool)Properties.Settings.Default["exportUVs"] && m_Mesh.m_UV4 != null && m_Mesh.m_UV4.Length > 0) + { + ob.Append("\n\t\tLayer: 3 {"); + ob.Append("\n\t\t\tVersion: 100"); + ob.Append("\n\t\t\tLayerElement: {"); + ob.Append("\n\t\t\t\tType: \"LayerElementUV\""); + ob.Append("\n\t\t\t\tTypedIndex: 3"); + ob.Append("\n\t\t\t}"); + ob.Append("\n\t\t}"); //Layer 3 end + } + #endregion + + ob.Append("\n\t}"); //Geometry end + } + } + private static float[] QuatToEuler(float[] q) { double eax = 0; @@ -2661,6 +2817,7 @@ namespace Unity_Studio { if (exportableAssets.Count > 0) { + saveFolderDialog1.InitialDirectory = mainPath; if (saveFolderDialog1.ShowDialog() == DialogResult.OK) { var savePath = saveFolderDialog1.FileName; diff --git a/Unity Studio/app.config b/Unity Studio/app.config index 18d7535..a42a7f3 100644 --- a/Unity Studio/app.config +++ b/Unity Studio/app.config @@ -43,6 +43,12 @@ False + + True + + + True +