diff --git a/ImportExport/Loaders/ExternalLoaders/DAELoader.cs b/ImportExport/Loaders/ExternalLoaders/DAELoader.cs index 73da052..0ed78b2 100644 --- a/ImportExport/Loaders/ExternalLoaders/DAELoader.cs +++ b/ImportExport/Loaders/ExternalLoaders/DAELoader.cs @@ -563,12 +563,21 @@ private int[] ReadSkinController(string id, string skeletonRoot, string geometry } } - if (jointNames.Length > 31) Console.WriteLine("WARN: More than 31 matrices, your model will not import correctly."); + if (jointNames.Length > 31) + { + Console.WriteLine("DAELoader: WARN: More than 31 matrices, your model will not import correctly."); + } for (int i = 0; i < jointNames.Length; i++) { Queue hierarchy = new Queue(); ModelBase.BoneDef child = m_Model.m_BoneTree.GetBoneByID(jointNames[i]); + if (child == null) + { + Console.WriteLine("DAELoader: WARN: Skin controller ["+ id + "] contains reference to joint name [" + + jointNames[i] + "] before joint has been read, skipping processing but failure likely"); + continue; + } hierarchy.Enqueue(child); while (child.m_Parent != null) { diff --git a/ImportExport/Loaders/ExternalLoaders/OBJLoader.cs b/ImportExport/Loaders/ExternalLoaders/OBJLoader.cs index 7a19301..8756df4 100644 --- a/ImportExport/Loaders/ExternalLoaders/OBJLoader.cs +++ b/ImportExport/Loaders/ExternalLoaders/OBJLoader.cs @@ -181,13 +181,15 @@ public override ModelBase LoadModel(float scale) } ModelBase.BoneDef bone = m_Model.m_BoneTree.GetBoneByID(currentBone); - if (!bone.m_Geometries.Values.ElementAt(0).m_PolyLists.ContainsKey(curmaterial)) + ModelBase.GeometryDef geomDef = bone.m_Geometries.Values.ElementAt(0); + string polyListKey = "polylist-" + curmaterial; + ModelBase.PolyListDef polyList; + if (!geomDef.m_PolyLists.TryGetValue(polyListKey, out polyList)) { - ModelBase.PolyListDef tmp = new ModelBase.PolyListDef(currentBone + "." + curmaterial, curmaterial); - tmp.m_FaceLists.Add(new ModelBase.FaceListDef()); - bone.m_Geometries.Values.ElementAt(0).m_PolyLists.Add(curmaterial, tmp); + polyList = new ModelBase.PolyListDef(polyListKey, curmaterial); + polyList.m_FaceLists.Add(new ModelBase.FaceListDef()); + geomDef.m_PolyLists.Add(polyList.m_ID, polyList); } - ModelBase.PolyListDef polyList = bone.m_Geometries.Values.ElementAt(0).m_PolyLists[curmaterial]; ModelBase.FaceDef face = new ModelBase.FaceDef(nvtx); @@ -500,7 +502,7 @@ protected void LoadBoneDefinitionsForOBJ(string filename) bone.SetTranslation(translation); } break; - case "billboard": // Always rendered facing camera (not yet implemented) + case "billboard": // Always rendered facing camera { if (parts.Length < 2) continue; bool billboard = (short.Parse(parts[1]) == 1); diff --git a/ImportExport/Loaders/InternalLoaders/BMDLoader.cs b/ImportExport/Loaders/InternalLoaders/BMDLoader.cs index e8d1a43..c1a3d92 100644 --- a/ImportExport/Loaders/InternalLoaders/BMDLoader.cs +++ b/ImportExport/Loaders/InternalLoaders/BMDLoader.cs @@ -31,7 +31,8 @@ public override ModelBase LoadModel(float scale) ModelBase.BoneDef bone = new ModelBase.BoneDef(mdchunk.m_Name); bone.SetScale(mdchunk.m_20_12Scale); bone.SetRotation(mdchunk.m_4_12Rotation); - bone.SetTranslation(mdchunk.m_20_12Translation); + bone.SetTranslation(mdchunk.m_20_12Translation); + bone.m_Billboard = mdchunk.m_Billboard; if (mdchunk.m_ParentOffset == 0) { diff --git a/ImportExport/ModelBase.cs b/ImportExport/ModelBase.cs index 545a1d2..1c8be03 100644 --- a/ImportExport/ModelBase.cs +++ b/ImportExport/ModelBase.cs @@ -202,7 +202,7 @@ public class BoneDef public bool m_HasChildren { get { return m_Children.Count > 0; } } - public bool m_Billboard;// Not used as not working + public bool m_Billboard; public BoneDef(string id) { @@ -574,6 +574,33 @@ public MaterialDef(string id) m_TexGenMode = TexGenMode.None; } + public MaterialDef(string id, MaterialDef that) + { + m_ID = id; + m_TextureDefID = that.m_TextureDefID; + m_Lights = new bool[4]; + Array.Copy(that.m_Lights, m_Lights, 4); + m_PolygonDrawingFace = that.m_PolygonDrawingFace; + m_Alpha = that.m_Alpha; + m_WireMode = that.m_WireMode; + m_PolygonMode = that.m_PolygonMode; + m_FogFlag = that.m_FogFlag; + m_DepthTestDecal = that.m_DepthTestDecal; + m_RenderOnePixelPolygons = that.m_RenderOnePixelPolygons; + m_FarClipping = that.m_FarClipping; + m_Diffuse = that.m_Diffuse; + m_Ambient = that.m_Ambient; + m_Specular = that.m_Specular; + m_Emission = that.m_Emission; + m_ShininessTableEnabled = that.m_ShininessTableEnabled; + m_TexTiling = new TexTiling[2]; + Array.Copy(that.m_TexTiling, m_TexTiling, 2); + m_TextureScale = that.m_TextureScale; + m_TextureRotation = that.m_TextureRotation; + m_TextureTranslation = that.m_TextureTranslation; + m_TexGenMode = that.m_TexGenMode; + } + public enum PolygonDrawingFace { Front, diff --git a/ImportExport/Writers/ExternalWriters/OBJWriter.cs b/ImportExport/Writers/ExternalWriters/OBJWriter.cs index db7f8fe..b7b2eed 100644 --- a/ImportExport/Writers/ExternalWriters/OBJWriter.cs +++ b/ImportExport/Writers/ExternalWriters/OBJWriter.cs @@ -60,20 +60,25 @@ public override void WriteModel(bool save = true) if (objSplitBoneID != boneIndex) { ModelBase.BoneDef newBone = flatBoneList[objSplitBoneID]; - - if (!newBone.m_Geometries.ContainsKey(geometry.m_ID)) - newBone.m_Geometries.Add(geometry.m_ID, new ModelBase.GeometryDef(geometry.m_ID)); - if (!newBone.m_Geometries[geometry.m_ID].m_PolyLists.ContainsKey(polyList.m_MaterialName)) + // For models using "areas" (multiple-parent bones) the vertices all seem to be + // assigned to the first parent bone. We don't want to move faces about in such + // cases so only move faces between bones within the same branch. + if (bone.GetBranch().Contains(newBone)) { - ModelBase.PolyListDef tmp = new ModelBase.PolyListDef(polyList.m_ID, polyList.m_MaterialName); - tmp.m_FaceLists.Add(new ModelBase.FaceListDef()); - newBone.m_Geometries[geometry.m_ID].m_PolyLists.Add(polyList.m_MaterialName, tmp); + if (!newBone.m_Geometries.ContainsKey(geometry.m_ID)) + newBone.m_Geometries.Add(geometry.m_ID, new ModelBase.GeometryDef(geometry.m_ID)); + if (!newBone.m_Geometries[geometry.m_ID].m_PolyLists.ContainsKey(polyList.m_MaterialName)) + { + ModelBase.PolyListDef tmp = new ModelBase.PolyListDef(polyList.m_ID, polyList.m_MaterialName); + tmp.m_FaceLists.Add(new ModelBase.FaceListDef()); + newBone.m_Geometries[geometry.m_ID].m_PolyLists.Add(polyList.m_MaterialName, tmp); + } + if (!newBone.m_MaterialsInBranch.Contains(polyList.m_MaterialName)) + newBone.m_MaterialsInBranch.Add(polyList.m_MaterialName); + + newBone.m_Geometries[geometry.m_ID].m_PolyLists[polyList.m_MaterialName].m_FaceLists[0].m_Faces.Add(face); + faceList.m_Faces.RemoveAt(f); } - if (!newBone.m_MaterialsInBranch.Contains(polyList.m_MaterialName)) - newBone.m_MaterialsInBranch.Add(polyList.m_MaterialName); - - newBone.m_Geometries[geometry.m_ID].m_PolyLists[polyList.m_MaterialName].m_FaceLists[0].m_Faces.Add(face); - faceList.m_Faces.RemoveAt(f); } f++; diff --git a/ImportExport/Writers/InternalWriters/BMDWriter.cs b/ImportExport/Writers/InternalWriters/BMDWriter.cs index 29d5782..f4f14c5 100644 --- a/ImportExport/Writers/InternalWriters/BMDWriter.cs +++ b/ImportExport/Writers/InternalWriters/BMDWriter.cs @@ -308,6 +308,70 @@ public override void WriteModel(bool save = true) GXDisplayListPacker dlpacker = new GXDisplayListPacker(); ModelBase.BoneDefRoot boneTree = m_Model.m_BoneTree; + + // Materials cannot be shared across root-level bones; iterate through each + // pair or root-level bones and duplicate any materials that they share, assigning + // the original to one bone and the duplicate to the other e.g.: + // - r0 has materials matA, matB and matC + // - r1 has materials matC and matD + // - duplicate matC into matC_1 + // - assign matB to r0 polylists and matB_1 to r1 polylists so that: + // - r0 has materials matA, matB and matC + // - r1 has materials matC_1 and matD + List rootBones = boneTree.GetRootBones(); + for (int i = 0; i < rootBones.Count; i++) + { + for (int j = i + 1; j < rootBones.Count; j++) + { + ModelBase.BoneDef rootA = rootBones[i]; + ModelBase.BoneDef rootB = rootBones[j]; + + foreach (string materialID in rootA.m_MaterialsInBranch) + { + if (rootB.m_MaterialsInBranch.Contains(materialID)) + { + string duplicateMaterialID; + int counter = 1; + + do + { + duplicateMaterialID = materialID + '_' + counter++; + } + while (m_Model.m_Materials.ContainsKey(duplicateMaterialID) && counter < 100); + + if (counter >= 100) + { + duplicateMaterialID = materialID + '_' + System.Guid.NewGuid().ToString(); + } + + ModelBase.MaterialDef duplicateMaterial = + new ModelBase.MaterialDef(duplicateMaterialID, m_Model.m_Materials[materialID]); + + m_Model.m_Materials.Add(duplicateMaterialID, duplicateMaterial); + + foreach (ModelBase.BoneDef bone in rootB.GetBranch()) + { + foreach (ModelBase.GeometryDef geometry in bone.m_Geometries.Values) + { + foreach (ModelBase.PolyListDef polyList in geometry.m_PolyLists.Values) + { + polyList.m_MaterialName = duplicateMaterialID; + } + } + } + + rootB.m_MaterialsInBranch.Remove(materialID); + rootB.m_MaterialsInBranch.Add(duplicateMaterialID); + + string msg = String.Format("Found duplicate material [{0}] between bones " + + "[{1}] and [{2}], replacing with material [{3}] in [{2}]", + materialID, rootA.m_ID, rootB.m_ID, duplicateMaterialID); + Console.WriteLine(msg); + } + } + } + } + List materialsInFixedOrder = m_Model.m_Materials.Values.ToList(); Dictionary materialFixedIndicesByID = new Dictionary(); foreach (ModelBase.MaterialDef material in materialsInFixedOrder) diff --git a/Level.cs b/Level.cs index fa53f3b..8cdc7a8 100644 --- a/Level.cs +++ b/Level.cs @@ -617,15 +617,21 @@ private void SaveMiscObjs(BinaryWriter binWriter) SaveObjList(binWriter, m_LevelObjects.Values, k_MiscLevelObjTypeOrder); } + public int CalculateNumberOfAreas() + { + int numAreas = m_LevelObjects.Max(x => x.Value.m_Area); + numAreas = Math.Max(numAreas, m_LevelObjects.Values.Where(x => x is EntranceObject) + .Select(x => x.Parameters[3] & 7).Max() + 1); //include entrance areas + numAreas = Math.Max(numAreas, m_TexAnims.FindLastIndex(x => x.m_Defs.Count != 0) + 1); + return numAreas; + } + private void SaveRegularObjs(BinaryWriter binWriter, out uint areaTableOffset) { List> objsByArea = new List>(); for (int i = 0; i < 8; ++i) objsByArea.Add(m_LevelObjects.Values.Where(x => x.m_Area == i).ToList()); - m_NumAreas = objsByArea.FindLastIndex(x => x.Count != 0) + 1; - m_NumAreas = Math.Max(m_NumAreas, m_LevelObjects.Values.Where(x => x is EntranceObject) - .Select(x => x.Parameters[3] & 7).Max() + 1); //include entrance areas - m_NumAreas = Math.Max(m_NumAreas, m_TexAnims.FindLastIndex(x => x.m_Defs.Count != 0) + 1); + m_NumAreas = Math.Max(m_NumAreas, CalculateNumberOfAreas()); if (m_NumAreas > k_MaxNumAreas) throw new InvalidDataException("The game can support only " + k_MaxNumAreas + " areas. You have " + m_NumAreas + "."); diff --git a/LevelEditorForm.cs b/LevelEditorForm.cs index 636c571..0c408ae 100644 --- a/LevelEditorForm.cs +++ b/LevelEditorForm.cs @@ -1555,7 +1555,7 @@ private void tvObjectList_DrawNode(object sender, DrawTreeNodeEventArgs e) private void btnLevelSettings_Click(object sender, EventArgs e) { - new LevelSettingsForm(m_Level.m_LevelSettings).ShowDialog(this); + new LevelSettingsForm(m_Level).ShowDialog(this); m_Level.DetermineAvailableObjects(); tvObjectList.Refresh(); } diff --git a/LevelSettingsForm.Designer.cs b/LevelSettingsForm.Designer.cs index 4baf827..3ccf73c 100644 --- a/LevelSettingsForm.Designer.cs +++ b/LevelSettingsForm.Designer.cs @@ -30,6 +30,10 @@ private void InitializeComponent() { this.cbxBank0 = new System.Windows.Forms.ComboBox(); this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.nudGeneralMinimumNumberOfAreas = new System.Windows.Forms.NumericUpDown(); + this.lblGeneralMinimumNumberOfAreas = new System.Windows.Forms.Label(); + this.txtActSelectorID = new System.Windows.Forms.TextBox(); + this.label10 = new System.Windows.Forms.Label(); this.cbxBackground = new System.Windows.Forms.ComboBox(); this.label1 = new System.Windows.Forms.Label(); this.groupBox2 = new System.Windows.Forms.GroupBox(); @@ -57,9 +61,8 @@ private void InitializeComponent() this.label13 = new System.Windows.Forms.Label(); this.label12 = new System.Windows.Forms.Label(); this.label11 = new System.Windows.Forms.Label(); - this.label10 = new System.Windows.Forms.Label(); - this.txtActSelectorID = new System.Windows.Forms.TextBox(); this.groupBox1.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.nudGeneralMinimumNumberOfAreas)).BeginInit(); this.groupBox2.SuspendLayout(); this.groupBox3.SuspendLayout(); this.SuspendLayout(); @@ -80,17 +83,66 @@ private void InitializeComponent() // // groupBox1 // + this.groupBox1.Controls.Add(this.nudGeneralMinimumNumberOfAreas); + this.groupBox1.Controls.Add(this.lblGeneralMinimumNumberOfAreas); this.groupBox1.Controls.Add(this.txtActSelectorID); this.groupBox1.Controls.Add(this.label10); this.groupBox1.Controls.Add(this.cbxBackground); this.groupBox1.Controls.Add(this.label1); this.groupBox1.Location = new System.Drawing.Point(12, 12); this.groupBox1.Name = "groupBox1"; - this.groupBox1.Size = new System.Drawing.Size(381, 81); + this.groupBox1.Size = new System.Drawing.Size(381, 105); this.groupBox1.TabIndex = 1; this.groupBox1.TabStop = false; this.groupBox1.Text = "General settings"; // + // nudGeneralMinimumNumberOfAreas + // + this.nudGeneralMinimumNumberOfAreas.Location = new System.Drawing.Point(225, 77); + this.nudGeneralMinimumNumberOfAreas.Maximum = new decimal(new int[] { + 8, + 0, + 0, + 0}); + this.nudGeneralMinimumNumberOfAreas.Minimum = new decimal(new int[] { + 1, + 0, + 0, + 0}); + this.nudGeneralMinimumNumberOfAreas.Name = "nudGeneralMinimumNumberOfAreas"; + this.nudGeneralMinimumNumberOfAreas.Size = new System.Drawing.Size(141, 20); + this.nudGeneralMinimumNumberOfAreas.TabIndex = 5; + this.nudGeneralMinimumNumberOfAreas.Value = new decimal(new int[] { + 1, + 0, + 0, + 0}); + // + // lblGeneralMinimumNumberOfAreas + // + this.lblGeneralMinimumNumberOfAreas.AutoSize = true; + this.lblGeneralMinimumNumberOfAreas.Location = new System.Drawing.Point(15, 79); + this.lblGeneralMinimumNumberOfAreas.Name = "lblGeneralMinimumNumberOfAreas"; + this.lblGeneralMinimumNumberOfAreas.Size = new System.Drawing.Size(110, 13); + this.lblGeneralMinimumNumberOfAreas.TabIndex = 4; + this.lblGeneralMinimumNumberOfAreas.Text = "Minimum No. of Areas"; + // + // txtActSelectorID + // + this.txtActSelectorID.Location = new System.Drawing.Point(225, 51); + this.txtActSelectorID.Name = "txtActSelectorID"; + this.txtActSelectorID.Size = new System.Drawing.Size(141, 20); + this.txtActSelectorID.TabIndex = 3; + // + // label10 + // + this.label10.AutoSize = true; + this.label10.Location = new System.Drawing.Point(15, 54); + this.label10.Name = "label10"; + this.label10.Size = new System.Drawing.Size(82, 13); + this.label10.TabIndex = 2; + this.label10.Text = "Act Selector ID:"; + // // cbxBackground // this.cbxBackground.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; @@ -108,9 +160,9 @@ private void InitializeComponent() "[9] Foggy forest", "[10] Bowser in the Dark World", "[11] Bowser in the Sky"}); - this.cbxBackground.Location = new System.Drawing.Point(103, 24); + this.cbxBackground.Location = new System.Drawing.Point(225, 24); this.cbxBackground.Name = "cbxBackground"; - this.cbxBackground.Size = new System.Drawing.Size(263, 21); + this.cbxBackground.Size = new System.Drawing.Size(141, 21); this.cbxBackground.TabIndex = 1; this.cbxBackground.SelectedIndexChanged += new System.EventHandler(this.cbxBackground_SelectedIndexChanged); // @@ -141,7 +193,7 @@ private void InitializeComponent() this.groupBox2.Controls.Add(this.cbxBank1); this.groupBox2.Controls.Add(this.label2); this.groupBox2.Controls.Add(this.cbxBank0); - this.groupBox2.Location = new System.Drawing.Point(12, 99); + this.groupBox2.Location = new System.Drawing.Point(12, 123); this.groupBox2.Name = "groupBox2"; this.groupBox2.Size = new System.Drawing.Size(381, 230); this.groupBox2.TabIndex = 2; @@ -321,7 +373,7 @@ private void InitializeComponent() // btnCancel // this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; - this.btnCancel.Location = new System.Drawing.Point(318, 462); + this.btnCancel.Location = new System.Drawing.Point(318, 465); this.btnCancel.Name = "btnCancel"; this.btnCancel.Size = new System.Drawing.Size(75, 26); this.btnCancel.TabIndex = 3; @@ -331,7 +383,7 @@ private void InitializeComponent() // btnOk // this.btnOk.DialogResult = System.Windows.Forms.DialogResult.OK; - this.btnOk.Location = new System.Drawing.Point(237, 462); + this.btnOk.Location = new System.Drawing.Point(237, 465); this.btnOk.Name = "btnOk"; this.btnOk.Size = new System.Drawing.Size(75, 26); this.btnOk.TabIndex = 4; @@ -347,7 +399,7 @@ private void InitializeComponent() this.groupBox3.Controls.Add(this.label13); this.groupBox3.Controls.Add(this.label12); this.groupBox3.Controls.Add(this.label11); - this.groupBox3.Location = new System.Drawing.Point(12, 336); + this.groupBox3.Location = new System.Drawing.Point(12, 360); this.groupBox3.Name = "groupBox3"; this.groupBox3.Size = new System.Drawing.Size(381, 99); this.groupBox3.TabIndex = 5; @@ -402,22 +454,6 @@ private void InitializeComponent() this.label11.TabIndex = 1; this.label11.Text = "Byte 01: (SWAR entry address - 4) / 4"; // - // label10 - // - this.label10.AutoSize = true; - this.label10.Location = new System.Drawing.Point(15, 54); - this.label10.Name = "label10"; - this.label10.Size = new System.Drawing.Size(82, 13); - this.label10.TabIndex = 2; - this.label10.Text = "Act Selector ID:"; - // - // txtActSelectorID - // - this.txtActSelectorID.Location = new System.Drawing.Point(266, 51); - this.txtActSelectorID.Name = "txtActSelectorID"; - this.txtActSelectorID.Size = new System.Drawing.Size(100, 20); - this.txtActSelectorID.TabIndex = 3; - // // LevelSettingsForm // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -437,6 +473,7 @@ private void InitializeComponent() this.Load += new System.EventHandler(this.LevelSettingsForm_Load); this.groupBox1.ResumeLayout(false); this.groupBox1.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.nudGeneralMinimumNumberOfAreas)).EndInit(); this.groupBox2.ResumeLayout(false); this.groupBox2.PerformLayout(); this.groupBox3.ResumeLayout(false); @@ -478,5 +515,7 @@ private void InitializeComponent() private System.Windows.Forms.Label label11; private System.Windows.Forms.TextBox txtActSelectorID; private System.Windows.Forms.Label label10; + private System.Windows.Forms.NumericUpDown nudGeneralMinimumNumberOfAreas; + private System.Windows.Forms.Label lblGeneralMinimumNumberOfAreas; } } \ No newline at end of file diff --git a/LevelSettingsForm.cs b/LevelSettingsForm.cs index d96361c..ef21e1b 100644 --- a/LevelSettingsForm.cs +++ b/LevelSettingsForm.cs @@ -29,12 +29,14 @@ namespace SM64DSe { public partial class LevelSettingsForm : Form { + private Level m_Level; private LevelSettings m_LevelSettings; - public LevelSettingsForm(LevelSettings settings) + public LevelSettingsForm(Level level) { InitializeComponent(); - m_LevelSettings = settings; + m_Level = level; + m_LevelSettings = level.m_LevelSettings; } private void LevelSettingsForm_Load(object sender, EventArgs e) @@ -85,6 +87,7 @@ private void LevelSettingsForm_Load(object sender, EventArgs e) } cbxBackground.SelectedIndex = m_LevelSettings.Background; + nudGeneralMinimumNumberOfAreas.Value = m_Level.m_NumAreas; txtMusicByte01.Text = m_LevelSettings.MusicBytes[0].ToString(); txtMusicByte02.Text = m_LevelSettings.MusicBytes[1].ToString(); @@ -144,6 +147,7 @@ private void cbxBankX_DrawItem(object sender, DrawItemEventArgs e) private void btnOk_Click(object sender, EventArgs e) { m_LevelSettings.Background = (byte)cbxBackground.SelectedIndex; + m_Level.m_NumAreas = (byte)(nudGeneralMinimumNumberOfAreas.Value); m_LevelSettings.ObjectBanks[0] = (uint)cbxBank0.SelectedIndex; m_LevelSettings.ObjectBanks[1] = (uint)cbxBank1.SelectedIndex; m_LevelSettings.ObjectBanks[2] = (uint)cbxBank2.SelectedIndex; diff --git a/ModelAndCollisionMapEditor.Designer.cs b/ModelAndCollisionMapEditor.Designer.cs index fb80515..9e0d11f 100644 --- a/ModelAndCollisionMapEditor.Designer.cs +++ b/ModelAndCollisionMapEditor.Designer.cs @@ -220,10 +220,12 @@ private void InitializeComponent() this.mnitExportTextures = new System.Windows.Forms.ToolStripMenuItem(); this.mnitExportTexturesPNG = new System.Windows.Forms.ToolStripMenuItem(); this.mnitExportTexturesBMP = new System.Windows.Forms.ToolStripMenuItem(); + this.grpModelBonesSettings = new System.Windows.Forms.GroupBox(); + this.chkModelBonesSettingsBillboard = new System.Windows.Forms.CheckBox(); this.ssMain.SuspendLayout(); this.tcMain.SuspendLayout(); this.tpgModel.SuspendLayout(); - ((System.ComponentModel.ISupportInitialize)(this.splModel)).BeginInit(); + //((System.ComponentModel.ISupportInitialize)(this.splModel)).BeginInit(); this.splModel.Panel1.SuspendLayout(); this.splModel.Panel2.SuspendLayout(); this.splModel.SuspendLayout(); @@ -243,19 +245,19 @@ private void InitializeComponent() this.grpModelMaterialSettings.SuspendLayout(); this.grpModelMaterialTextureSettings.SuspendLayout(); this.grpModelMaterialColours.SuspendLayout(); - ((System.ComponentModel.ISupportInitialize)(this.nudModelMaterialAlpha)).BeginInit(); + //((System.ComponentModel.ISupportInitialize)(this.nudModelMaterialAlpha)).BeginInit(); this.grpModelMaterialFlags.SuspendLayout(); this.tpgModelTextures.SuspendLayout(); this.grpModelTexturesPreview.SuspendLayout(); this.pnlModelTexturesPreviewPanel.SuspendLayout(); - ((System.ComponentModel.ISupportInitialize)(this.pbxModelTexturesPreview)).BeginInit(); + //((System.ComponentModel.ISupportInitialize)(this.pbxModelTexturesPreview)).BeginInit(); this.grpModelTexturesSettings.SuspendLayout(); this.tpgPalettes.SuspendLayout(); this.grpModelPalettesColours.SuspendLayout(); - ((System.ComponentModel.ISupportInitialize)(this.gridModelPalettesPaletteColours)).BeginInit(); + //((System.ComponentModel.ISupportInitialize)(this.gridModelPalettesPaletteColours)).BeginInit(); this.tsModelPreview.SuspendLayout(); this.tpgCollisionMap.SuspendLayout(); - ((System.ComponentModel.ISupportInitialize)(this.splCollisionMap)).BeginInit(); + //((System.ComponentModel.ISupportInitialize)(this.splCollisionMap)).BeginInit(); this.splCollisionMap.Panel1.SuspendLayout(); this.splCollisionMap.Panel2.SuspendLayout(); this.splCollisionMap.SuspendLayout(); @@ -264,10 +266,11 @@ private void InitializeComponent() this.grpCollisionMapGeneralScale.SuspendLayout(); this.grpCollisionMapGeneralTarget.SuspendLayout(); this.groupBox1.SuspendLayout(); - ((System.ComponentModel.ISupportInitialize)(this.gridCollisionMapGeneralMaterialCollisionTypes)).BeginInit(); + //((System.ComponentModel.ISupportInitialize)(this.gridCollisionMapGeneralMaterialCollisionTypes)).BeginInit(); this.tpgCollisionMapPlanes.SuspendLayout(); this.grpCollisionMapPlanesDetails.SuspendLayout(); this.mstrMain.SuspendLayout(); + this.grpModelBonesSettings.SuspendLayout(); this.SuspendLayout(); // // ssMain @@ -534,6 +537,7 @@ private void InitializeComponent() // tpgModelBones // this.tpgModelBones.AutoScroll = true; + this.tpgModelBones.Controls.Add(this.grpModelBonesSettings); this.tpgModelBones.Controls.Add(this.btnModelBonesRenameBone); this.tpgModelBones.Controls.Add(this.txtModelBonesName); this.tpgModelBones.Controls.Add(this.grpModelBonesGeometries); @@ -574,7 +578,7 @@ private void InitializeComponent() this.grpModelBonesGeometries.Controls.Add(this.grpModelBonesPolylists); this.grpModelBonesGeometries.Controls.Add(this.btnModelBonesCutGeometry); this.grpModelBonesGeometries.Controls.Add(this.btnModelBonesRemoveGeometry); - this.grpModelBonesGeometries.Location = new System.Drawing.Point(6, 202); + this.grpModelBonesGeometries.Location = new System.Drawing.Point(6, 252); this.grpModelBonesGeometries.Name = "grpModelBonesGeometries"; this.grpModelBonesGeometries.Size = new System.Drawing.Size(271, 338); this.grpModelBonesGeometries.TabIndex = 15; @@ -2260,6 +2264,27 @@ private void InitializeComponent() this.mnitExportTexturesBMP.Text = "Export as BMP"; this.mnitExportTexturesBMP.Click += new System.EventHandler(this.mnitExportTexturesBMP_Click); // + // grpModelBonesSettings + // + this.grpModelBonesSettings.Controls.Add(this.chkModelBonesSettingsBillboard); + this.grpModelBonesSettings.Location = new System.Drawing.Point(6, 202); + this.grpModelBonesSettings.Name = "grpModelBonesSettings"; + this.grpModelBonesSettings.Size = new System.Drawing.Size(271, 44); + this.grpModelBonesSettings.TabIndex = 21; + this.grpModelBonesSettings.TabStop = false; + this.grpModelBonesSettings.Text = "Settings"; + // + // chkModelBonesSettingsBillboard + // + this.chkModelBonesSettingsBillboard.AutoSize = true; + this.chkModelBonesSettingsBillboard.Location = new System.Drawing.Point(9, 19); + this.chkModelBonesSettingsBillboard.Name = "chkModelBonesSettingsBillboard"; + this.chkModelBonesSettingsBillboard.Size = new System.Drawing.Size(210, 17); + this.chkModelBonesSettingsBillboard.TabIndex = 0; + this.chkModelBonesSettingsBillboard.Text = "Always Render Facing Camera (\"Billboard\")"; + this.chkModelBonesSettingsBillboard.UseVisualStyleBackColor = true; + this.chkModelBonesSettingsBillboard.CheckedChanged += new System.EventHandler(chkModelBonesSettingsBillboard_CheckedChanged); + // // ModelAndCollisionMapEditor // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -2281,7 +2306,7 @@ private void InitializeComponent() this.splModel.Panel1.ResumeLayout(false); this.splModel.Panel2.ResumeLayout(false); this.splModel.Panel2.PerformLayout(); - ((System.ComponentModel.ISupportInitialize)(this.splModel)).EndInit(); + //((System.ComponentModel.ISupportInitialize)(this.splModel)).EndInit(); this.splModel.ResumeLayout(false); this.tcModelSettings.ResumeLayout(false); this.tpgModelGeneral.ResumeLayout(false); @@ -2309,28 +2334,28 @@ private void InitializeComponent() this.grpModelMaterialTextureSettings.PerformLayout(); this.grpModelMaterialColours.ResumeLayout(false); this.grpModelMaterialColours.PerformLayout(); - ((System.ComponentModel.ISupportInitialize)(this.nudModelMaterialAlpha)).EndInit(); + //((System.ComponentModel.ISupportInitialize)(this.nudModelMaterialAlpha)).EndInit(); this.grpModelMaterialFlags.ResumeLayout(false); this.grpModelMaterialFlags.PerformLayout(); this.tpgModelTextures.ResumeLayout(false); this.tpgModelTextures.PerformLayout(); this.grpModelTexturesPreview.ResumeLayout(false); this.pnlModelTexturesPreviewPanel.ResumeLayout(false); - ((System.ComponentModel.ISupportInitialize)(this.pbxModelTexturesPreview)).EndInit(); + //((System.ComponentModel.ISupportInitialize)(this.pbxModelTexturesPreview)).EndInit(); this.grpModelTexturesSettings.ResumeLayout(false); this.grpModelTexturesSettings.PerformLayout(); this.tpgPalettes.ResumeLayout(false); this.tpgPalettes.PerformLayout(); this.grpModelPalettesColours.ResumeLayout(false); this.grpModelPalettesColours.PerformLayout(); - ((System.ComponentModel.ISupportInitialize)(this.gridModelPalettesPaletteColours)).EndInit(); + //((System.ComponentModel.ISupportInitialize)(this.gridModelPalettesPaletteColours)).EndInit(); this.tsModelPreview.ResumeLayout(false); this.tsModelPreview.PerformLayout(); this.tpgCollisionMap.ResumeLayout(false); this.splCollisionMap.Panel1.ResumeLayout(false); this.splCollisionMap.Panel2.ResumeLayout(false); this.splCollisionMap.Panel2.PerformLayout(); - ((System.ComponentModel.ISupportInitialize)(this.splCollisionMap)).EndInit(); + //((System.ComponentModel.ISupportInitialize)(this.splCollisionMap)).EndInit(); this.splCollisionMap.ResumeLayout(false); this.tcCollisionMapSettings.ResumeLayout(false); this.tpgCollisionMapGeneral.ResumeLayout(false); @@ -2340,12 +2365,14 @@ private void InitializeComponent() this.grpCollisionMapGeneralTarget.PerformLayout(); this.groupBox1.ResumeLayout(false); this.groupBox1.PerformLayout(); - ((System.ComponentModel.ISupportInitialize)(this.gridCollisionMapGeneralMaterialCollisionTypes)).EndInit(); + //((System.ComponentModel.ISupportInitialize)(this.gridCollisionMapGeneralMaterialCollisionTypes)).EndInit(); this.tpgCollisionMapPlanes.ResumeLayout(false); this.grpCollisionMapPlanesDetails.ResumeLayout(false); this.grpCollisionMapPlanesDetails.PerformLayout(); this.mstrMain.ResumeLayout(false); this.mstrMain.PerformLayout(); + this.grpModelBonesSettings.ResumeLayout(false); + this.grpModelBonesSettings.PerformLayout(); this.ResumeLayout(false); this.PerformLayout(); @@ -2543,5 +2570,7 @@ private void InitializeComponent() private System.Windows.Forms.ToolStripLabel lblModelPreviewScale; private System.Windows.Forms.ToolStripMenuItem mnitExportTexturesPNG; private System.Windows.Forms.ToolStripMenuItem mnitExportTexturesBMP; + private System.Windows.Forms.GroupBox grpModelBonesSettings; + private System.Windows.Forms.CheckBox chkModelBonesSettingsBillboard; } } \ No newline at end of file diff --git a/ModelAndCollisionMapEditor.cs b/ModelAndCollisionMapEditor.cs index 36a4b5c..7b6d698 100644 --- a/ModelAndCollisionMapEditor.cs +++ b/ModelAndCollisionMapEditor.cs @@ -559,9 +559,18 @@ private BMD CallBMDImporter(bool save = false) foreach (ModelBase.BoneDef bone in m_ModelBase.m_BoneTree) { - bone.m_Geometries = originalGeometries[bone.m_ID]; + foreach (ModelBase.GeometryDef geometry in bone.m_Geometries.Values) + { + foreach (ModelBase.PolyListDef polyList in geometry.m_PolyLists.Values) + { + polyList.m_FaceLists = + originalGeometries[bone.m_ID][geometry.m_ID].m_PolyLists[polyList.m_ID].m_FaceLists; + } + } } + PopulateMaterialsList(); + return result; } @@ -627,7 +636,7 @@ private void PopulateBoneTree() { parentNodes[bone.m_Parent.m_ID].Nodes.Add(node); } - parentNodes.Add(bone.m_ID, node); + parentNodes[bone.m_ID] = node; } } @@ -639,6 +648,7 @@ private void PopulateBoneTree() SetEnabledStateModelBonePolylistControls(false); txtModelBonesName.Text = null; txtModelBonesName.BackColor = Color.White; + chkModelBonesSettingsBillboard.Checked = false; lbxModelBonesGeometries.Items.Clear(); lbxModelBonesPolylists.Items.Clear(); @@ -654,6 +664,7 @@ private void SetEnabledStateModelBoneSpecificControls(bool state) btnModelBonesPasteToBone.Enabled = (m_SourcePolylists != null || m_SourceGeometries != null); btnModelBonesRenameBone.Enabled = state; txtModelBonesName.Enabled = state; + chkModelBonesSettingsBillboard.Enabled = state; } private void SetEnabledStateModelBoneGeometryControls(bool state) @@ -959,7 +970,10 @@ private void mnitLoadRevertChanges_Click(object sender, EventArgs e) private void tcModelSettings_SelectedIndexChanged(object sender, System.EventArgs e) { - UpdateBMDModelAndPreview(); + if (m_ModelSourceLoaded) + { + UpdateBMDModelAndPreview(); + } } private bool IsModelBonesTabSelected() @@ -1182,6 +1196,7 @@ private void tvModelBonesBones_AfterSelect(object sender, TreeViewEventArgs e) SetEnabledStateModelBonePolylistControls(false); txtModelBonesName.Text = bone.m_ID; + chkModelBonesSettingsBillboard.Checked = bone.m_Billboard; DrawSkeleton(); @@ -2411,11 +2426,25 @@ private void btnModelBonesRenameBone_Click(object sender, EventArgs e) string boneIDNew = null; if (!GetValidNonAsciiTextBoxValue(txtModelBonesName, ref boneIDNew)) return; + string boneIDOld = bone.m_ID; + bone.m_ID = boneIDNew; + int boneTransform = m_ModelBase.m_BoneTransformsMap.GetByFirst(boneIDOld); + m_ModelBase.m_BoneTransformsMap.RemoveByFirst(boneIDOld); + m_ModelBase.m_BoneTransformsMap.Add(boneIDNew, boneTransform); + tvModelBonesBones.SelectedNode.Text = boneIDNew; } + private void chkModelBonesSettingsBillboard_CheckedChanged(object sender, System.EventArgs e) + { + ModelBase.BoneDef bone = GetSelectedBone(); + if (bone == null) return; + + bone.m_Billboard = chkModelBonesSettingsBillboard.Checked; + } + private string GenerateUniqueBoneID() { string boneID; @@ -2474,6 +2503,7 @@ private void mnitModelBonesAddBoneChild_Click(object sender, EventArgs e) ModelBase.BoneDef childBone = new ModelBase.BoneDef(boneID); selectedBone.AddChild(childBone); + m_ModelBase.m_BoneTransformsMap.Add(childBone.m_ID, m_ModelBase.m_BoneTransformsMap.Count); int childBoneIndex = m_ModelBase.m_BoneTree.GetBoneIndex(childBone); UpdateVertexBoneIndicesForBoneInsertionAt(childBoneIndex); @@ -2501,6 +2531,7 @@ private void mnitModelBonesAddBoneSibling_Click(object sender, EventArgs e) { m_ModelBase.m_BoneTree.AddRootBone(siblingBone); } + m_ModelBase.m_BoneTransformsMap.Add(siblingBone.m_ID, m_ModelBase.m_BoneTransformsMap.Count); int siblingBoneIndex = m_ModelBase.m_BoneTree.GetBoneIndex(siblingBone); UpdateVertexBoneIndicesForBoneInsertionAt(siblingBoneIndex); diff --git a/Program.cs b/Program.cs index a871d3c..ecacd23 100644 --- a/Program.cs +++ b/Program.cs @@ -26,8 +26,8 @@ namespace SM64DSe static class Program { public static string AppTitle = "SM64DS Editor"; - public static string AppVersion = "v2.3.3"; - public static string AppDate = "2017-06-14"; + public static string AppVersion = "v2.3.4"; + public static string AppDate = "2017-06-21"; public static string ServerURL = "http://kuribo64.net/"; diff --git a/SM64DSe.suo b/SM64DSe.suo index 24a93cc..1646cab 100644 Binary files a/SM64DSe.suo and b/SM64DSe.suo differ diff --git a/bin/Release/SM64DSe.exe b/bin/Release/SM64DSe.exe index ea808a7..5e4f394 100644 Binary files a/bin/Release/SM64DSe.exe and b/bin/Release/SM64DSe.exe differ diff --git a/bin/Release/SM64DSe.pdb b/bin/Release/SM64DSe.pdb index 9cc351c..0c3e823 100644 Binary files a/bin/Release/SM64DSe.pdb and b/bin/Release/SM64DSe.pdb differ