Add ModelEditor

This commit is contained in:
miku-666
2024-09-01 17:25:13 +02:00
parent 1f5f24b3bb
commit c91def4a77
8 changed files with 413 additions and 54 deletions

View File

@@ -0,0 +1,110 @@
namespace PckStudio.Forms.Editor
{
partial class ModelEditor
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
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;
}
}

View File

@@ -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<TreeNode> GetModelNodes(IEnumerable<ModelPart> 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<TreeNode> GetModelPartNodeChildren(IEnumerable<ModelBox> 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<NamedTexture> 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<NamedTexture> 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;
}
}
}

View File

@@ -0,0 +1,123 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="modelContextMenu.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
</root>

View File

@@ -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<string, JsonModelMetaData> ModelMetaData { get; } = JsonConvert.DeserializeObject<ReadOnlyDictionary<string, JsonModelMetaData>>(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<string, Outline> outliners = new Dictionary<string, Outline>(5);
List<Element> elements = new List<Element>(modelInfo.Model.Parts.Count);
Vector3 transformAxis = new Vector3(1, 1, 0);
List<Element> elements = new List<Element>(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<Outline> 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);
}
}
}

View File

@@ -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();

View File

@@ -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<NamedTexture> 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<NamedTexture>();
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<NamedTexture> 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<string> props = asset.SerializeProperties(seperater:" ");
IEnumerable<string> 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,

View File

@@ -152,6 +152,12 @@
<DependentUpon>ContributorsForm.cs</DependentUpon>
</Compile>
<Compile Include="Extensions\OpenTkMatrixExtensions.cs" />
<Compile Include="Forms\Editor\ModelEditor.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Forms\Editor\ModelEditor.Designer.cs">
<DependentUpon>ModelEditor.cs</DependentUpon>
</Compile>
<Compile Include="Interfaces\IModelImportProvider.cs" />
<Compile Include="Internal\App\Updater.cs" />
<Compile Include="Internal\GameModelInfo.cs" />
@@ -478,6 +484,9 @@
<EmbeddedResource Include="Forms\ContributorsForm.resx">
<DependentUpon>ContributorsForm.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Forms\Editor\ModelEditor.resx">
<DependentUpon>ModelEditor.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Forms\Features\CemuPanel.resx">
<DependentUpon>CemuPanel.cs</DependentUpon>
</EmbeddedResource>

2
Vendor/OMI-Lib vendored