8939687f6a
Load vertex positions for layouts in rectangle class. This will be used for proper rotation adjusting. Add latest muunt editor files. Add somewhat functional mk8 camera bin editor. Points can be moved around. The map orientation determines the position of the icons to map over the model. Fix window content UV map for layouts. Add 2D KCL renderer for top down KCL preview for both muunt and camera editors.
514 lines
17 KiB
C#
514 lines
17 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Windows.Forms;
|
|
using System.Drawing;
|
|
using System.Runtime.InteropServices;
|
|
using Toolbox.Library.Forms;
|
|
|
|
namespace Toolbox.Library
|
|
{
|
|
public abstract class TreeNodeCustom : TreeNode
|
|
{
|
|
public virtual void OnClick(TreeView treeview) { }
|
|
public virtual void OnMouseLeftClick(TreeView treeview) { }
|
|
public virtual void OnMouseRightClick(TreeView treeview) { }
|
|
public virtual void OnDoubleMouseClick(TreeView treeview) { }
|
|
|
|
|
|
public TreeNodeCustom()
|
|
{
|
|
}
|
|
}
|
|
|
|
public class TreeNodeFile : TreeNodeCustom
|
|
{
|
|
public bool CanDelete
|
|
{
|
|
set
|
|
{
|
|
if (value == true)
|
|
{
|
|
if (ContextMenuStrip == null)
|
|
ContextMenuStrip = new STContextMenuStrip();
|
|
|
|
ContextMenuStrip.Items.Add(new STToolStipMenuItem("Delete", null, Delete, Keys.Control | Keys.Delete));
|
|
}
|
|
}
|
|
}
|
|
|
|
public virtual UserControl GetEditor() { return new STUserControl() { Dock = DockStyle.Fill }; }
|
|
public virtual void FillEditor(UserControl control) { }
|
|
|
|
public override void OnClick(TreeView treeview)
|
|
{
|
|
var Editor = GetEditor();
|
|
Editor.Dock = DockStyle.Fill;
|
|
|
|
var ActiveEditor = LibraryGUI.GetActiveContent(Editor.GetType());
|
|
if (ActiveEditor != null)
|
|
Editor = ActiveEditor;
|
|
else
|
|
LibraryGUI.LoadEditor(Editor);
|
|
|
|
FillEditor(Editor);
|
|
}
|
|
|
|
public TreeNodeFile()
|
|
{
|
|
|
|
}
|
|
|
|
public TreeNodeFile(string text)
|
|
{
|
|
Text = text;
|
|
}
|
|
|
|
private void Delete(object sender, EventArgs args)
|
|
{
|
|
var editor = LibraryGUI.GetObjectEditor();
|
|
if (editor != null)
|
|
{
|
|
editor.ResetControls();
|
|
}
|
|
}
|
|
|
|
public virtual void OnAfterAdded() //After added to treeview
|
|
{
|
|
|
|
}
|
|
}
|
|
|
|
public class TreeViewCustom : TreeView
|
|
{
|
|
private readonly Dictionary<int, TreeNode> _treeNodes = new Dictionary<int, TreeNode>();
|
|
|
|
public List<ITextureIconLoader> TextureIcons = new List<ITextureIconLoader>();
|
|
public List<ISingleTextureIconLoader> SingleTextureIcons = new List<ISingleTextureIconLoader>();
|
|
|
|
public TreeViewCustom()
|
|
{
|
|
ReloadImages();
|
|
|
|
BackColor = FormThemes.BaseTheme.FormBackColor;
|
|
ForeColor = FormThemes.BaseTheme.FormForeColor;
|
|
}
|
|
|
|
public static ImageList imgList = new ImageList();
|
|
|
|
public void AddImage(Image image)
|
|
{
|
|
imgList.Images.Add(image);
|
|
}
|
|
|
|
private Thread Thread;
|
|
public void ReloadTextureIcons(bool CanAbortThread)
|
|
{
|
|
if (Thread != null && Thread.IsAlive && CanAbortThread)
|
|
Thread.Abort();
|
|
|
|
Thread = new Thread((ThreadStart)(() =>
|
|
{
|
|
for (int i = 0; i < TextureIcons.Count; i++)
|
|
{
|
|
foreach (TreeNode node in TextureIcons[i].IconTextureList)
|
|
{
|
|
if (node is STGenericTexture)
|
|
{
|
|
var image = ((STGenericTexture)node).GetBitmap();
|
|
if (image != null)
|
|
AddImageOnThread(image, node);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < SingleTextureIcons.Count; i++)
|
|
{
|
|
if (SingleTextureIcons[i] == null || SingleTextureIcons[i].IconTexture == null)
|
|
continue;
|
|
|
|
var image = SingleTextureIcons[i].IconTexture.GetBitmap();
|
|
if (image != null)
|
|
AddImageOnThread(image, SingleTextureIcons[i].IconTexture);
|
|
}
|
|
}));
|
|
Thread.Start();
|
|
}
|
|
|
|
public void ReloadTextureIcons(List<ISingleTextureIconLoader> textureIcons, bool CanAbortThread)
|
|
{
|
|
if (Thread != null && Thread.IsAlive && CanAbortThread)
|
|
Thread.Abort();
|
|
|
|
this.BeginUpdate();
|
|
|
|
Thread = new Thread((ThreadStart)(() =>
|
|
{
|
|
List<TreeNode> treeNodes = new List<TreeNode>();
|
|
List<Image> imageIcons = new List<Image>();
|
|
|
|
foreach (TreeNode node in textureIcons)
|
|
{
|
|
if (node is STGenericTexture)
|
|
{
|
|
try
|
|
{
|
|
var image = ((STGenericTexture)node).GetBitmap();
|
|
if (image != null)
|
|
{
|
|
image = ((STGenericTexture)node).GetComponentBitmap(image);
|
|
|
|
imageIcons.Add(image);
|
|
treeNodes.Add(node);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine(ex.ToString());
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
for (int i = 0; i < treeNodes.Count; i++)
|
|
{
|
|
AddImageOnThread(i, treeNodes[i]);
|
|
}
|
|
|
|
if (this.InvokeRequired)
|
|
{
|
|
this.Invoke((MethodInvoker)delegate
|
|
{
|
|
this.ImageList.Images.AddRange(imageIcons.ToArray());
|
|
});
|
|
}
|
|
|
|
for (int i = 0; i < treeNodes.Count; i++)
|
|
imageIcons[i].Dispose();
|
|
|
|
imageIcons.Clear();
|
|
treeNodes.Clear();
|
|
textureIcons.Clear();
|
|
|
|
if (this.InvokeRequired)
|
|
{
|
|
this.Invoke((MethodInvoker)delegate
|
|
{
|
|
this.EndUpdate();
|
|
});
|
|
}
|
|
}));
|
|
Thread.Start();
|
|
}
|
|
|
|
public void ReloadTextureIcons(ISingleTextureIconLoader textureIcon, Image image)
|
|
{
|
|
if (this.InvokeRequired)
|
|
{
|
|
this.Invoke((MethodInvoker)delegate
|
|
{
|
|
ReloadTextureIcons(textureIcon.IconTexture, image);
|
|
});
|
|
}
|
|
else
|
|
{
|
|
ReloadTextureIcons(textureIcon.IconTexture, image);
|
|
}
|
|
}
|
|
|
|
private void ReloadTextureIcons(TreeNode node, Image image)
|
|
{
|
|
image = BitmapExtension.Resize(image, this.ImageList.ImageSize);
|
|
|
|
if (node.ImageIndex != -1 && node.ImageIndex < this.ImageList.Images.Count)
|
|
this.ImageList.Images[node.ImageIndex] = image;
|
|
else
|
|
{
|
|
node.ImageIndex = this.ImageList.Images.Count;
|
|
node.SelectedImageIndex = node.ImageIndex;
|
|
|
|
this.ImageList.Images.Add(image);
|
|
}
|
|
this.Refresh();
|
|
}
|
|
|
|
public void ReloadTextureIcons(ISingleTextureIconLoader textureIcon, bool CanAbortThread)
|
|
{
|
|
if (Thread != null && Thread.IsAlive && CanAbortThread)
|
|
Thread.Abort();
|
|
|
|
Thread = new Thread((ThreadStart)(() =>
|
|
{
|
|
try
|
|
{
|
|
var image = textureIcon.IconTexture.GetBitmap();
|
|
image = textureIcon.IconTexture.GetComponentBitmap(image);
|
|
AddImageOnThread(image, textureIcon.IconTexture);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine(ex.ToString());
|
|
}
|
|
}));
|
|
Thread.Start();
|
|
}
|
|
|
|
public void ReloadTextureIcons(ITextureIconLoader textureIconList)
|
|
{
|
|
if (Thread != null && Thread.IsAlive)
|
|
Thread.Abort();
|
|
|
|
this.BeginUpdate();
|
|
|
|
Thread = new Thread((ThreadStart)(() =>
|
|
{
|
|
List<TreeNode> treeNodes = new List<TreeNode>();
|
|
List<Image> imageIcons = new List<Image>();
|
|
|
|
foreach (TreeNode node in textureIconList.IconTextureList)
|
|
{
|
|
if (node is STGenericTexture)
|
|
{
|
|
try
|
|
{
|
|
var image = ((STGenericTexture)node).GetBitmap();
|
|
if (image != null)
|
|
{
|
|
image = ((STGenericTexture)node).GetComponentBitmap(image);
|
|
treeNodes.Add(node);
|
|
imageIcons.Add(image);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine(ex.ToString());
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
for (int i = 0; i < treeNodes.Count; i++)
|
|
{
|
|
AddImageOnThread(i, treeNodes[i]);
|
|
}
|
|
|
|
if (this.InvokeRequired)
|
|
{
|
|
this.Invoke((MethodInvoker)delegate
|
|
{
|
|
this.ImageList.Images.AddRange(imageIcons.ToArray());
|
|
});
|
|
}
|
|
|
|
for (int i = 0; i < treeNodes.Count; i++)
|
|
imageIcons[i].Dispose();
|
|
|
|
imageIcons.Clear();
|
|
treeNodes.Clear();
|
|
|
|
if (this.InvokeRequired)
|
|
{
|
|
this.Invoke((MethodInvoker)delegate
|
|
{
|
|
this.EndUpdate();
|
|
});
|
|
}
|
|
}));
|
|
Thread.Start();
|
|
}
|
|
|
|
public void AddImageOnThread(Image image, TreeNode node)
|
|
{
|
|
if (this.InvokeRequired)
|
|
{
|
|
this.Invoke((MethodInvoker)delegate {
|
|
// Running on the UI thread
|
|
|
|
node.ImageIndex = this.ImageList.Images.Count;
|
|
node.SelectedImageIndex = node.ImageIndex;
|
|
|
|
imgList.Images.Add(image);
|
|
|
|
image.Dispose();
|
|
});
|
|
}
|
|
}
|
|
|
|
public void AddImageOnThread(int index, TreeNode node)
|
|
{
|
|
if (this.InvokeRequired)
|
|
{
|
|
this.Invoke((MethodInvoker)delegate {
|
|
// Running on the UI thread
|
|
|
|
node.ImageIndex = this.ImageList.Images.Count + index;
|
|
node.SelectedImageIndex = node.ImageIndex;
|
|
});
|
|
}
|
|
}
|
|
|
|
public void ReloadImages(int Width = 22, int Height = 22)
|
|
{
|
|
imgList = new ImageList();
|
|
imgList.ColorDepth = ColorDepth.Depth32Bit;
|
|
imgList.ImageSize = new Size(Width, Height);
|
|
imgList.Images.Add("folder", Properties.Resources.Folder);
|
|
imgList.Images.Add("resource", Properties.Resources.Folder);
|
|
imgList.Images.Add("Texture", Properties.Resources.Texture);
|
|
imgList.Images.Add("fileBlank", Properties.Resources.FileBlank);
|
|
imgList.Images.Add("bfres", Properties.Resources.Bfres);
|
|
imgList.Images.Add("byaml", Properties.Resources.Byaml);
|
|
imgList.Images.Add("aamp", Properties.Resources.Aamp);
|
|
imgList.Images.Add("bntx", Properties.Resources.Bntx);
|
|
imgList.Images.Add("bfsha", Properties.Resources.Bfsha);
|
|
imgList.Images.Add("bnsh", Properties.Resources.Bnsh);
|
|
imgList.Images.Add("mesh", Properties.Resources.mesh);
|
|
imgList.Images.Add("skeletonAnimation", Properties.Resources.skeletonAnimation);
|
|
imgList.Images.Add("bone", Properties.Resources.Bone);
|
|
imgList.Images.Add("bfwav", Properties.Resources.Music1);
|
|
imgList.Images.Add("bfstp", Properties.Resources.Music2);
|
|
imgList.Images.Add("material", Properties.Resources.materialSphere);
|
|
imgList.Images.Add("model", Properties.Resources.model);
|
|
imgList.Images.Add("folder", Properties.Resources.skeleton);
|
|
imgList.Images.Add("TextureMaterialMap", Properties.Resources.TextureMaterialMap);
|
|
|
|
imgList.Images.Add("MetaInfo", Properties.Resources.MetaInfo);
|
|
|
|
imgList.Images.Add("MaterialTranslucent", Properties.Resources.materialSphereTranslucent);
|
|
imgList.Images.Add("MaterialTransparent", Properties.Resources.materialSphereTransparent);
|
|
|
|
//Data types
|
|
imgList.Images.Add("bool", Properties.Resources.IconBool);
|
|
imgList.Images.Add("buffer", Properties.Resources.IconBuffer);
|
|
imgList.Images.Add("curve", Properties.Resources.IconCurve);
|
|
imgList.Images.Add("float", Properties.Resources.IconFloat);
|
|
imgList.Images.Add("int", Properties.Resources.IconInt);
|
|
imgList.Images.Add("list", Properties.Resources.IconList);
|
|
imgList.Images.Add("object", Properties.Resources.IconObject);
|
|
imgList.Images.Add("vec2", Properties.Resources.IconVec2);
|
|
imgList.Images.Add("vec3", Properties.Resources.IconVec3);
|
|
imgList.Images.Add("vec4", Properties.Resources.IconVec4);
|
|
|
|
Bitmap bmp = new Bitmap(Width, Height);
|
|
Graphics g = Graphics.FromImage(bmp);
|
|
g.Clear(Color.Transparent);
|
|
|
|
imgList.Images.Add("empty", bmp);
|
|
|
|
|
|
this.ImageList = imgList;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Load the TreeView with items.
|
|
/// </summary>
|
|
/// <typeparam name="T">Item type</typeparam>
|
|
/// <param name="items">Collection of items</param>
|
|
/// <param name="getId">Function to parse Id value from item object</param>
|
|
/// <param name="getParentId">Function to parse parentId value from item object</param>
|
|
/// <param name="getDisplayName">Function to parse display name
|
|
/// value from item object. This is used as node text.</param>
|
|
public void LoadItems<T>(IEnumerable<T> items, Func<T, int> getId,
|
|
Func<T, int?> getParentId, Func<T, string> getDisplayName)
|
|
{
|
|
// Clear view and internal dictionary
|
|
Nodes.Clear();
|
|
_treeNodes.Clear();
|
|
|
|
// Load internal dictionary with nodes
|
|
foreach (var item in items)
|
|
{
|
|
var id = getId(item);
|
|
var displayName = getDisplayName(item);
|
|
var node = new TreeNode
|
|
{
|
|
Name = id.ToString(),
|
|
Text = displayName,
|
|
Tag = item
|
|
};
|
|
_treeNodes.Add(getId(item), node);
|
|
}
|
|
|
|
// Create hierarchy and load into view
|
|
foreach (var id in _treeNodes.Keys)
|
|
{
|
|
var node = GetNode(id);
|
|
var obj = (T)node.Tag;
|
|
var parentId = getParentId(obj);
|
|
if (parentId.HasValue)
|
|
{
|
|
var parentNode = GetNode(parentId.Value);
|
|
parentNode.Nodes.Add(node);
|
|
}
|
|
else
|
|
{
|
|
Nodes.Add(node);
|
|
}
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Retrieve TreeNode by Id.
|
|
/// Useful when you want to select a specific node.
|
|
/// </summary>
|
|
/// <param name="id">Item id</param>
|
|
public TreeNode GetNode(int id)
|
|
{
|
|
return _treeNodes[id];
|
|
}
|
|
}
|
|
public static class TreeViewExtensions
|
|
{
|
|
public static IEnumerable<TreeNode> Collect(TreeNodeCollection nodes)
|
|
{
|
|
foreach (TreeNode node in nodes)
|
|
{
|
|
yield return node;
|
|
|
|
foreach (var child in Collect(node.Nodes))
|
|
yield return child;
|
|
}
|
|
}
|
|
|
|
|
|
private const int TVIF_STATE = 0x8;
|
|
private const int TVIS_STATEIMAGEMASK = 0xF000;
|
|
private const int TV_FIRST = 0x1100;
|
|
private const int TVM_SETITEM = TV_FIRST + 63;
|
|
|
|
[StructLayout(LayoutKind.Sequential, Pack = 8, CharSet = CharSet.Auto)]
|
|
private struct TVITEM
|
|
{
|
|
public int mask;
|
|
public IntPtr hItem;
|
|
public int state;
|
|
public int stateMask;
|
|
[MarshalAs(UnmanagedType.LPTStr)]
|
|
public string lpszText;
|
|
public int cchTextMax;
|
|
public int iImage;
|
|
public int iSelectedImage;
|
|
public int cChildren;
|
|
public IntPtr lParam;
|
|
}
|
|
|
|
[DllImport("user32.dll", CharSet = CharSet.Auto)]
|
|
private static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam,
|
|
ref TVITEM lParam);
|
|
|
|
/// <summary>
|
|
/// Hides the checkbox for the specified node on a TreeView control.
|
|
/// </summary>
|
|
public static void HideCheckBox(this TreeNode node)
|
|
{
|
|
TVITEM tvi = new TVITEM();
|
|
tvi.hItem = node.Handle;
|
|
tvi.mask = TVIF_STATE;
|
|
tvi.stateMask = TVIS_STATEIMAGEMASK;
|
|
tvi.state = 0;
|
|
SendMessage(node.TreeView.Handle, TVM_SETITEM, IntPtr.Zero, ref tvi);
|
|
}
|
|
}
|
|
}
|