diff --git a/PCK-Studio/Forms/Editor/ModelEditor.Designer.cs b/PCK-Studio/Forms/Editor/ModelEditor.Designer.cs
new file mode 100644
index 00000000..94d4d029
--- /dev/null
+++ b/PCK-Studio/Forms/Editor/ModelEditor.Designer.cs
@@ -0,0 +1,110 @@
+namespace PckStudio.Forms.Editor
+{
+ partial class ModelEditor
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.components = new System.ComponentModel.Container();
+ this.modelTreeView = new System.Windows.Forms.TreeView();
+ this.modelContextMenu = new MetroFramework.Controls.MetroContextMenu(this.components);
+ this.exportToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.editToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.removeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.modelContextMenu.SuspendLayout();
+ this.SuspendLayout();
+ //
+ // modelTreeView
+ //
+ this.modelTreeView.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(20)))), ((int)(((byte)(20)))), ((int)(((byte)(20)))));
+ this.modelTreeView.BorderStyle = System.Windows.Forms.BorderStyle.None;
+ this.modelTreeView.ContextMenuStrip = this.modelContextMenu;
+ this.modelTreeView.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.modelTreeView.ForeColor = System.Drawing.SystemColors.Window;
+ this.modelTreeView.Location = new System.Drawing.Point(20, 60);
+ this.modelTreeView.Name = "modelTreeView";
+ this.modelTreeView.PathSeparator = ".";
+ this.modelTreeView.Size = new System.Drawing.Size(335, 395);
+ this.modelTreeView.TabIndex = 0;
+ this.modelTreeView.BeforeSelect += new System.Windows.Forms.TreeViewCancelEventHandler(this.modelTreeView_BeforeSelect);
+ //
+ // modelContextMenu
+ //
+ this.modelContextMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
+ this.exportToolStripMenuItem,
+ this.editToolStripMenuItem,
+ this.removeToolStripMenuItem});
+ this.modelContextMenu.Name = "modelContextMenu";
+ this.modelContextMenu.Size = new System.Drawing.Size(118, 70);
+ //
+ // exportToolStripMenuItem
+ //
+ this.exportToolStripMenuItem.Name = "exportToolStripMenuItem";
+ this.exportToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
+ this.exportToolStripMenuItem.Text = "Export";
+ this.exportToolStripMenuItem.Click += new System.EventHandler(this.exportToolStripMenuItem_Click);
+ //
+ // editToolStripMenuItem
+ //
+ this.editToolStripMenuItem.Name = "editToolStripMenuItem";
+ this.editToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
+ this.editToolStripMenuItem.Text = "Edit";
+ this.editToolStripMenuItem.Visible = false;
+ //
+ // removeToolStripMenuItem
+ //
+ this.removeToolStripMenuItem.Name = "removeToolStripMenuItem";
+ this.removeToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
+ this.removeToolStripMenuItem.Text = "Remove";
+ this.removeToolStripMenuItem.Visible = false;
+ //
+ // ModelEditor
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.ClientSize = new System.Drawing.Size(375, 475);
+ this.Controls.Add(this.modelTreeView);
+ this.MaximizeBox = false;
+ this.MinimizeBox = false;
+ this.MinimumSize = new System.Drawing.Size(375, 475);
+ this.Name = "ModelEditor";
+ this.Style = MetroFramework.MetroColorStyle.Silver;
+ this.Text = "ModelEditor";
+ this.Theme = MetroFramework.MetroThemeStyle.Dark;
+ this.modelContextMenu.ResumeLayout(false);
+ this.ResumeLayout(false);
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.TreeView modelTreeView;
+ private MetroFramework.Controls.MetroContextMenu modelContextMenu;
+ private System.Windows.Forms.ToolStripMenuItem exportToolStripMenuItem;
+ private System.Windows.Forms.ToolStripMenuItem editToolStripMenuItem;
+ private System.Windows.Forms.ToolStripMenuItem removeToolStripMenuItem;
+ }
+}
\ No newline at end of file
diff --git a/PCK-Studio/Forms/Editor/ModelEditor.cs b/PCK-Studio/Forms/Editor/ModelEditor.cs
new file mode 100644
index 00000000..ba2a4064
--- /dev/null
+++ b/PCK-Studio/Forms/Editor/ModelEditor.cs
@@ -0,0 +1,128 @@
+using System;
+using System.IO;
+using System.Data;
+using System.Linq;
+using System.Drawing;
+using System.Diagnostics;
+using System.Windows.Forms;
+using System.Collections.Generic;
+
+using OMI.Formats.Model;
+using MetroFramework.Forms;
+
+using PckStudio.Internal;
+
+namespace PckStudio.Forms.Editor
+{
+ public partial class ModelEditor : MetroForm
+ {
+ private readonly ModelContainer _models;
+ private readonly TryGetTextureDelegate _tryGetTexture;
+
+
+ public delegate bool TryGetTextureDelegate(string path, out Image img);
+
+ public ModelEditor(ModelContainer models, TryGetTextureDelegate tryGetTexture)
+ {
+ InitializeComponent();
+ _models = models;
+ _tryGetTexture = tryGetTexture;
+ }
+
+ private class ModelNode : TreeNode
+ {
+ private Model _model;
+ public Model Model => _model;
+
+ public ModelNode(Model model)
+ : base(model.Name)
+ {
+ _model = model;
+ Nodes.AddRange(GetModelNodes(_model.GetParts()).ToArray());
+ }
+ private static IEnumerable GetModelNodes(IEnumerable parts)
+ {
+ return parts.Select(part => new ModelPartNode(part));
+ }
+ }
+
+ private class ModelPartNode : TreeNode
+ {
+ private ModelPart _part;
+
+ public ModelPart Part => _part;
+
+ public ModelPartNode(ModelPart part)
+ : base(part.Name)
+ {
+ _part = part;
+ Nodes.AddRange(GetModelPartNodeChildren(part.GetBoxes()).ToArray());
+ }
+ private static IEnumerable GetModelPartNodeChildren(IEnumerable boxes)
+ {
+ return boxes.Select(box => new ModelBoxNode(box));
+ }
+ }
+
+ private class ModelBoxNode : TreeNode
+ {
+ private ModelBox _modelBox;
+ public ModelBoxNode(ModelBox modelBox)
+ : base($"Box: pos:{modelBox.Position} size:{modelBox.Size}")
+ {
+ _modelBox = modelBox;
+ }
+ }
+
+ protected override void OnLoad(EventArgs e)
+ {
+ base.OnLoad(e);
+ modelTreeView.Nodes.AddRange(_models.Select(model => new ModelNode(model)).ToArray());
+ }
+
+ private void exportToolStripMenuItem_Click(object sender, EventArgs e)
+ {
+ if (modelTreeView.SelectedNode is ModelNode modelNode)
+ {
+ Model model = modelNode.Model;
+ Debug.Write(model.Name + "; ");
+ Debug.WriteLine(model.TextureSize);
+
+ GameModelImporter.Default.ExportSettings.CreateModelOutline =
+ MessageBox.Show(
+ $"Do you wish to have all model parts contained in a group called '{model.Name}'?",
+ "Group model parts", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes;
+
+ using SaveFileDialog openFileDialog = new SaveFileDialog();
+ openFileDialog.FileName = model.Name;
+ openFileDialog.Filter = GameModelImporter.Default.SupportedModelFileFormatsFilter;
+
+ IEnumerable GetModelTextures(string modelName)
+ {
+ if (!GameModelImporter.ModelMetaData.ContainsKey(modelName) || GameModelImporter.ModelMetaData[modelName]?.TextureLocations?.Length <= 0)
+ yield break;
+ foreach (var textureLocation in GameModelImporter.ModelMetaData[modelName].TextureLocations)
+ {
+ if (_tryGetTexture(textureLocation, out Image img))
+ yield return new NamedTexture(Path.GetFileName(textureLocation), img);
+ }
+ yield break;
+ }
+
+ if (openFileDialog.ShowDialog(this) == DialogResult.OK)
+ {
+ IEnumerable textures = GetModelTextures(model.Name);
+ var modelInfo = new GameModelInfo(model, textures);
+ GameModelImporter.Default.Export(openFileDialog.FileName, modelInfo);
+ }
+ }
+ }
+
+ private void modelTreeView_BeforeSelect(object sender, TreeViewCancelEventArgs e)
+ {
+ exportToolStripMenuItem.Visible = e.Node is ModelNode;
+ editToolStripMenuItem.Visible = e.Node is ModelBoxNode;
+ removeToolStripMenuItem.Visible = e.Node is ModelPartNode || e.Node is ModelBoxNode;
+ }
+ }
+}
diff --git a/PCK-Studio/Forms/Editor/ModelEditor.resx b/PCK-Studio/Forms/Editor/ModelEditor.resx
new file mode 100644
index 00000000..6874eb71
--- /dev/null
+++ b/PCK-Studio/Forms/Editor/ModelEditor.resx
@@ -0,0 +1,123 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ 17, 17
+
+
\ No newline at end of file
diff --git a/PCK-Studio/Internal/GameModelImporter.cs b/PCK-Studio/Internal/GameModelImporter.cs
index d88464f3..89430db5 100644
--- a/PCK-Studio/Internal/GameModelImporter.cs
+++ b/PCK-Studio/Internal/GameModelImporter.cs
@@ -15,8 +15,10 @@
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
**/
+using System;
using System.IO;
using System.Linq;
+using System.Drawing;
using System.Numerics;
using System.Diagnostics;
using System.Collections.Generic;
@@ -24,6 +26,7 @@ using System.Collections.ObjectModel;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
+
using OMI.Formats.Model;
using PckStudio.External.Format;
@@ -36,8 +39,12 @@ namespace PckStudio.Internal
{
public static GameModelImporter Default { get; } = new GameModelImporter();
+ public class ModelExportSettings
+ {
public bool CreateModelOutline { get; set; } = true;
+ }
+ public ModelExportSettings ExportSettings { get; } = new ModelExportSettings();
internal static ReadOnlyDictionary ModelMetaData { get; } = JsonConvert.DeserializeObject>(Resources.modelMetaData);
private GameModelImporter()
@@ -46,14 +53,16 @@ namespace PckStudio.Internal
InternalAddProvider(new FileDialogFilter("Block bench model(*.bbmodel)", "*.bbmodel"), null, ExportBlockBenchModel);
}
+ Vector3 bbModelTransformAxis = new Vector3(1, 1, 0);
+ Vector3 _heightOffset = Vector3.Zero;
+
private void ExportBlockBenchModel(string filepath, GameModelInfo modelInfo)
{
BlockBenchModel blockBenchModel = BlockBenchModel.Create(BlockBenchFormatInfos.BedrockEntity, modelInfo.Model.Name, modelInfo.Model.TextureSize, modelInfo.Textures.Select(nt => (Texture)nt));
+ blockBenchModel.ModelIdentifier = modelInfo.Model.Name;
Dictionary outliners = new Dictionary(5);
- List elements = new List(modelInfo.Model.Parts.Count);
-
- Vector3 transformAxis = new Vector3(1, 1, 0);
+ List elements = new List(modelInfo.Model.PartCount);
if (!ModelMetaData.TryGetValue(modelInfo.Model.Name, out JsonModelMetaData modelMetaData))
{
@@ -61,20 +70,23 @@ namespace PckStudio.Internal
return;
}
- foreach (ModelPart part in modelInfo.Model.Parts.Values)
+ _heightOffset = Vector3.UnitY * 24f;
+
+ foreach (ModelPart part in modelInfo.Model.GetParts())
{
var outline = new Outline(part.Name);
Vector3 partTranslation = part.Translation;
- outline.Origin = TransformSpace(partTranslation, Vector3.Zero, transformAxis);
- outline.Origin += Vector3.UnitY * 24f;
+ outline.Origin = TransformSpace(partTranslation, Vector3.Zero, bbModelTransformAxis);
+ outline.Origin += _heightOffset;
- Vector3 rotation = part.Rotation + part.AdditionalRotation;
- outline.Rotation = rotation * TransformSpace(Vector3.One, Vector3.Zero, transformAxis);
+ Vector3 rotation = part.Rotation;
+ outline.Rotation = rotation * TransformSpace(Vector3.One, Vector3.Zero, bbModelTransformAxis);
- foreach (ModelBox box in part.Boxes)
+ foreach (ModelBox box in part.GetBoxes())
{
Element element = CreateElement(part.Name, box, partTranslation);
+ element.Rotation = rotation * TransformSpace(Vector3.One, Vector3.Zero, bbModelTransformAxis);
element.Origin = outline.Origin;
elements.Add(element);
outline.Children.Add(element.Uuid);
@@ -86,7 +98,7 @@ namespace PckStudio.Internal
blockBenchModel.Elements = elements.ToArray();
IEnumerable outlines = outliners.Values.Where(value => modelMetaData.RootParts.Count == 0 || modelMetaData.RootParts.ContainsKey(value.Name));
- if (CreateModelOutline)
+ if (ExportSettings.CreateModelOutline)
outlines = new Outline[1]
{
new Outline(modelInfo.Model.Name) { Children = JArray.FromObject(outlines) }
@@ -112,7 +124,7 @@ namespace PckStudio.Internal
{
if (child.Type == JTokenType.String && outliners.TryGetValue(child.ToString(), out Outline childOutline))
{
- childOutline.Rotation += -partentOutline.Rotation;
+ childOutline.Rotation -= partentOutline.Rotation;
partentOutline.Children.Add(JToken.FromObject(childOutline));
}
if (child.Type == JTokenType.Object)
@@ -127,7 +139,7 @@ namespace PckStudio.Internal
continue;
}
childOutline = outliners[key];
- childOutline.Rotation += -partentOutline.Rotation;
+ childOutline.Rotation -= partentOutline.Rotation;
partentOutline.Children.Add(JToken.FromObject(childOutline));
}
}
@@ -135,12 +147,12 @@ namespace PckStudio.Internal
}
}
- private static Element CreateElement(string name, ModelBox box, Vector3 origin)
+ private Element CreateElement(string name, ModelBox box, Vector3 origin)
{
Vector3 pos = box.Position;
Vector3 size = box.Size;
- Vector3 transformPos = TransformSpace(pos + origin, size, new Vector3(1, 1, 0)) + 24f * Vector3.UnitY;
- return Element.CreateCube(name, box.Uv, transformPos, size, box.Scale, box.Mirror);
+ Vector3 transformPos = TransformSpace(pos + origin, size, bbModelTransformAxis) + _heightOffset;
+ return Element.CreateCube(name, box.Uv, transformPos, size, box.Inflate, box.Mirror);
}
}
}
diff --git a/PCK-Studio/MainForm.Designer.cs b/PCK-Studio/MainForm.Designer.cs
index 8c9e1cd4..1a655e2c 100644
--- a/PCK-Studio/MainForm.Designer.cs
+++ b/PCK-Studio/MainForm.Designer.cs
@@ -90,11 +90,11 @@
this.mashUpPackToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.openToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.recentlyOpenToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.closeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.packSettingsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.fullBoxSupportToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.saveToolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem();
this.saveToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
- this.closeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.exitToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.editToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.quickChangeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
diff --git a/PCK-Studio/MainForm.cs b/PCK-Studio/MainForm.cs
index 097eb41d..afd114f0 100644
--- a/PCK-Studio/MainForm.cs
+++ b/PCK-Studio/MainForm.cs
@@ -594,53 +594,30 @@ namespace PckStudio
}
}
- public void HandleModelsFile(PckAsset file)
+ public void HandleModelsFile(PckAsset asset)
{
- ModelContainer modelContainer = file.GetData(new ModelFileReader());
+ ModelContainer modelContainer = asset.GetData(new ModelFileReader());
if (modelContainer.ModelCount == 0)
{
MessageBox.Show("No models found.", "Empty Model file", MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
- using ItemSelectionPopUp itemSelection = new ItemSelectionPopUp(modelContainer.GetModelNames().ToArray());
- if (itemSelection.ShowDialog() == DialogResult.OK && modelContainer.ContainsModel(itemSelection.SelectedItem))
+ ModelEditor.TryGetTextureDelegate tryGetTexture =
+ (string path, out Image img) =>
{
- Model model = modelContainer.GetModelByName(itemSelection.SelectedItem);
- Debug.WriteLine(model.Name + "; ");
- Debug.WriteLine(model.TextureSize + "; ");
+ bool found = currentPCK.TryGetAsset(path + ".png", PckAssetType.TextureFile, out PckAsset asset) ||
+ currentPCK.TryGetAsset(path + ".tga", PckAssetType.TextureFile, out asset);
+ img = found ? asset.GetTexture() : default;
+ return found;
+ };
- GameModelImporter.Default.CreateModelOutline =
- MessageBox.Show(
- $"Do you wish to have all model parts contained in a group called '{model.Name}'?",
- "Group model parts", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes;
-
- using SaveFileDialog openFileDialog = new SaveFileDialog();
- openFileDialog.FileName = model.Name;
- openFileDialog.Filter = GameModelImporter.Default.SupportedModelFileFormatsFilter;
-
- IEnumerable GetModelTextures(string modelName)
+ var editor = new ModelEditor(modelContainer, tryGetTexture);
+ if (editor.ShowDialog() == DialogResult.OK)
{
- if (!GameModelImporter.ModelMetaData.ContainsKey(modelName) || GameModelImporter.ModelMetaData[modelName]?.TextureLocations?.Length <= 0)
- return Enumerable.Empty();
-
- return GameModelImporter.ModelMetaData[modelName].TextureLocations
- .Where(texturePath => currentPCK.Contains(texturePath + ".png", PckAssetType.TextureFile) || currentPCK.Contains(texturePath + ".tga", PckAssetType.TextureFile))
- .Select(texturePath =>
- {
- PckAsset modelTextureAsset = currentPCK.GetAsset(texturePath + ".png", PckAssetType.TextureFile) ?? currentPCK.GetAsset(texturePath + ".tga", PckAssetType.TextureFile);
- return new NamedTexture(Path.GetFileName(texturePath), modelTextureAsset.GetTexture());
- });
+ return;
}
-
- if (openFileDialog.ShowDialog() == DialogResult.OK)
- {
- IEnumerable textures = GetModelTextures(model.Name);
- var modelInfo = new GameModelInfo(model, textures);
- GameModelImporter.Default.Export(openFileDialog.FileName, modelInfo);
}
- }
- }
public void HandleBehavioursFile(PckAsset asset)
{
@@ -2216,7 +2193,7 @@ namespace PckStudio
{
if (treeViewMain.SelectedNode.TryGetTagData(out PckAsset asset))
{
- IEnumerable props = asset.SerializeProperties(seperater:" ");
+ IEnumerable props = asset.SerializeProperties(seperater: " ");
using (var input = new MultiTextPrompt(props))
{
if (input.ShowDialog(this) == DialogResult.OK)
@@ -2305,7 +2282,7 @@ namespace PckStudio
ButtonText = "OK"
};
- if(dialog.ShowDialog(this) == DialogResult.OK)
+ if (dialog.ShowDialog(this) == DialogResult.OK)
{
BinkaConverter.ToBinka(
fileDialog.FileNames,
diff --git a/PCK-Studio/PckStudio.csproj b/PCK-Studio/PckStudio.csproj
index 3b7dff26..fd0e175f 100644
--- a/PCK-Studio/PckStudio.csproj
+++ b/PCK-Studio/PckStudio.csproj
@@ -152,6 +152,12 @@
ContributorsForm.cs
+
+ Form
+
+
+ ModelEditor.cs
+
@@ -478,6 +484,9 @@
ContributorsForm.cs
+
+ ModelEditor.cs
+
CemuPanel.cs
diff --git a/Vendor/OMI-Lib b/Vendor/OMI-Lib
index 8da46067..d9faa0b7 160000
--- a/Vendor/OMI-Lib
+++ b/Vendor/OMI-Lib
@@ -1 +1 @@
-Subproject commit 8da46067972139bb68334c80da3914893b5aeca7
+Subproject commit d9faa0b7a09d1da9bfa291d917958e6666a18257