CodeWalker/WorldInfoForm.cs

521 lines
19 KiB
C#

using CodeWalker.GameFiles;
using CodeWalker.Rendering;
using CodeWalker.Utils;
using SharpDX;
using SharpDX.Direct3D11;
using SharpDX.DXGI;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace CodeWalker
{
public partial class WorldInfoForm : Form
{
WorldForm WorldForm;
MapSelection Selection;
List<MapSelection> SelectionItems;
string SelectionMode = "";
bool MouseSelectEnable = false;
public WorldInfoForm(WorldForm worldForm)
{
WorldForm = worldForm;
InitializeComponent();
//SelectionModeComboBox.SelectedIndex = 0;
}
private void MouseSelectCheckBox_CheckedChanged(object sender, EventArgs e)
{
if (MouseSelectCheckBox.Checked != MouseSelectEnable)
{
MouseSelectEnable = MouseSelectCheckBox.Checked;
WorldForm.OnInfoFormSelectionModeChanged(SelectionMode, MouseSelectEnable);
}
}
private void SelectionModeComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
if (SelectionModeComboBox.Text != SelectionMode)
{
SelectionMode = SelectionModeComboBox.Text;
WorldForm.OnInfoFormSelectionModeChanged(SelectionMode, MouseSelectEnable);
}
}
public void SetSelectionMode(string mode, bool enable)
{
SelectionMode = mode;
MouseSelectEnable = enable;
SelectionModeComboBox.Text = mode;
MouseSelectCheckBox.Checked = enable;
}
public void SetSelection(MapSelection item, List<MapSelection> multiItems)
{
Selection = item;
SelectionItems = multiItems;
SelectionNameTextBox.Text = item.GetNameString("Nothing selected");
//SelEntityPropertyGrid.SelectedObject = item.EntityDef;
SelArchetypePropertyGrid.SelectedObject = item.Archetype;
SelDrawablePropertyGrid.SelectedObject = item.Drawable;
SelDrawableModelPropertyGrid.SelectedObject = null;
SelDrawableModelsTreeView.Nodes.Clear();
SelDrawableTexturesTreeView.Nodes.Clear();
SelDrawableTexturePropertyGrid.SelectedObject = null;
SelDrawableTexturePictureBox.Image = null;
HierarchyTreeView.Nodes.Clear();
if (item.Drawable != null)
{
AddSelectionDrawableModelsTreeNodes(item.Drawable.DrawableModelsHigh, "High Detail", true);
AddSelectionDrawableModelsTreeNodes(item.Drawable.DrawableModelsMedium, "Medium Detail", false);
AddSelectionDrawableModelsTreeNodes(item.Drawable.DrawableModelsLow, "Low Detail", false);
AddSelectionDrawableModelsTreeNodes(item.Drawable.DrawableModelsVeryLow, "Very Low Detail", false);
//AddSelectionDrawableModelsTreeNodes(item.Drawable.DrawableModelsX, "X Detail", false);
}
if (item.EntityDef != null)
{
AddSelectionEntityHierarchyNodes(item.EntityDef);
}
if (item.MultipleSelection)
{
SelectionEntityTabPage.Text = "Multiple items";
SelEntityPropertyGrid.SelectedObject = multiItems.ToArray();
}
else if (item.TimeCycleModifier != null)
{
SelectionEntityTabPage.Text = "Time Cycle Modifier";
SelEntityPropertyGrid.SelectedObject = item.TimeCycleModifier;
}
else if (item.CarGenerator != null)
{
SelectionEntityTabPage.Text = "Car Generator";
SelEntityPropertyGrid.SelectedObject = item.CarGenerator;
}
else if (item.DistantLodLights != null)
{
SelectionEntityTabPage.Text = "Distant LOD Lights";
SelEntityPropertyGrid.SelectedObject = item.DistantLodLights;
}
else if (item.GrassBatch != null)
{
SelectionEntityTabPage.Text = "Grass";
SelEntityPropertyGrid.SelectedObject = item.GrassBatch;
}
else if (item.BoxOccluder != null)
{
SelectionEntityTabPage.Text = "Box Occluder";
SelEntityPropertyGrid.SelectedObject = item.BoxOccluder;
}
else if (item.OccludeModel != null)
{
SelectionEntityTabPage.Text = "Occlude Model";
SelEntityPropertyGrid.SelectedObject = item.OccludeModel;
}
else if (item.WaterQuad != null)
{
SelectionEntityTabPage.Text = "Water Quad";
SelEntityPropertyGrid.SelectedObject = item.WaterQuad;
}
else if (item.NavPoly != null)
{
SelectionEntityTabPage.Text = "Nav Poly";
SelEntityPropertyGrid.SelectedObject = item.NavPoly;
}
else if (item.NavPoint != null)
{
SelectionEntityTabPage.Text = "Nav Point";
SelEntityPropertyGrid.SelectedObject = item.NavPoint;
}
else if (item.NavPortal != null)
{
SelectionEntityTabPage.Text = "Nav Portal";
SelEntityPropertyGrid.SelectedObject = item.NavPortal;
}
else if (item.PathNode != null)
{
SelectionEntityTabPage.Text = "Path Node";
SelEntityPropertyGrid.SelectedObject = item.PathNode;
}
else if (item.TrainTrackNode != null)
{
SelectionEntityTabPage.Text = "Train Track Node";
SelEntityPropertyGrid.SelectedObject = item.TrainTrackNode;
}
else if (item.ScenarioNode != null)
{
SelectionEntityTabPage.Text = item.ScenarioNode.FullTypeName;
SelEntityPropertyGrid.SelectedObject = item.ScenarioNode;
}
else if (item.Audio != null)
{
SelectionEntityTabPage.Text = item.Audio.FullTypeName;
SelEntityPropertyGrid.SelectedObject = item.Audio;
}
else
{
SelectionEntityTabPage.Text = "Entity";
SelEntityPropertyGrid.SelectedObject = item.EntityDef;
}
if (item.EntityExtension != null)
{
SelectionExtensionTabPage.Text = "Entity Extension";
SelExtensionPropertyGrid.SelectedObject = item.EntityExtension;
}
else if (item.ArchetypeExtension != null)
{
SelectionExtensionTabPage.Text = "Archetype Extension";
SelExtensionPropertyGrid.SelectedObject = item.ArchetypeExtension;
}
else if (item.CollisionBounds != null)
{
SelectionExtensionTabPage.Text = "Collision Bounds";
SelExtensionPropertyGrid.SelectedObject = item.CollisionBounds;
}
else
{
SelectionExtensionTabPage.Text = "Extension";
SelExtensionPropertyGrid.SelectedObject = null;
}
}
private void AddSelectionDrawableModelsTreeNodes(ResourcePointerList64<DrawableModel> models, string prefix, bool check)
{
if (models == null) return;
if (models.data_items == null) return;
for (int mi = 0; mi < models.data_items.Length; mi++)
{
var model = models.data_items[mi];
string mprefix = prefix + " " + (mi + 1).ToString();
var mnode = SelDrawableModelsTreeView.Nodes.Add(mprefix + " " + model.ToString());
mnode.Tag = model;
mnode.Checked = check;
var tmnode = SelDrawableTexturesTreeView.Nodes.Add(mprefix + " " + model.ToString());
tmnode.Tag = model;
if ((model.Geometries == null) || (model.Geometries.data_items == null)) continue;
foreach (var geom in model.Geometries.data_items)
{
var gname = geom.ToString();
var gnode = mnode.Nodes.Add(gname);
gnode.Tag = geom;
gnode.Checked = true;// check;
var tgnode = tmnode.Nodes.Add(gname);
tgnode.Tag = geom;
if ((geom.Shader != null) && (geom.Shader.ParametersList != null) && (geom.Shader.ParametersList.Hashes != null))
{
var pl = geom.Shader.ParametersList;
var h = pl.Hashes;
var p = pl.Parameters;
for (int ip = 0; ip < h.Length; ip++)
{
var hash = pl.Hashes[ip];
var parm = pl.Parameters[ip];
var tex = parm.Data as TextureBase;
if (tex != null)
{
var t = tex as Texture;
var tstr = tex.Name.Trim();
if (t != null)
{
tstr = string.Format("{0} ({1}x{2}, embedded)", tex.Name, t.Width, t.Height);
}
var tnode = tgnode.Nodes.Add(hash.ToString().Trim() + ": " + tstr);
tnode.Tag = tex;
}
}
tgnode.Expand();
}
}
mnode.Expand();
tmnode.Expand();
}
}
private void AddSelectionEntityHierarchyNodes(YmapEntityDef entity)
{
if (entity == null) return;
var e = entity;
TreeNode tn = null;
TreeNode seltn = null;
while (e != null)
{
var newtn = new TreeNode(e.Name);
newtn.Tag = e;
if (tn != null)
{
newtn.Nodes.Add(tn);
}
else
{
seltn = newtn;
}
if (e.Children != null)
{
foreach (var c in e.Children)
{
if ((tn != null) && (c == tn.Tag)) continue;
var ctn = new TreeNode(c.Name);
ctn.Tag = c;
newtn.Nodes.Add(ctn);
}
}
tn = newtn;
e = e.Parent;
}
if (tn != null)
{
HierarchyTreeView.Nodes.Add(tn);
tn.ExpandAll();
}
if (seltn != null)
{
HierarchyTreeView.SelectedNode = seltn;
}
}
private void DisplayTexture(Texture tex, int mip)
{
try
{
int cmip = Math.Min(Math.Max(mip, 0), tex.Levels - 1);
byte[] pixels = DDSIO.GetPixels(tex, cmip);
int w = tex.Width >> cmip;
int h = tex.Height >> cmip;
Bitmap bmp = new Bitmap(w, h, PixelFormat.Format32bppArgb);
if (pixels != null)
{
var BoundsRect = new System.Drawing.Rectangle(0, 0, w, h);
BitmapData bmpData = bmp.LockBits(BoundsRect, ImageLockMode.WriteOnly, bmp.PixelFormat);
IntPtr ptr = bmpData.Scan0;
int bytes = bmpData.Stride * bmp.Height;
Marshal.Copy(pixels, 0, ptr, bytes);
bmp.UnlockBits(bmpData);
}
SelDrawableTexturePictureBox.Image = bmp;
SelTextureDimensionsLabel.Text = w.ToString() + " x " + h.ToString();
}
catch (Exception ex)
{
MessageBox.Show("Error reading texture mip:\n" + ex.ToString());
SelDrawableTexturePictureBox.Image = null;
}
}
private void SelectTexture(TextureBase texbase, bool mipchange)
{
Texture tex = texbase as Texture;
YtdFile ytd = null;
string errstr = string.Empty;
if ((tex == null)&&(texbase!=null))
{
//need to load from txd.
var arch = Selection.Archetype;
uint texhash = texbase.NameHash;
uint txdHash = (arch != null) ? arch.TextureDict.Hash : 0;
tex = TryGetTextureFromYtd(texhash, txdHash, out ytd);
if (tex == null)
{ //search parent ytds...
uint ptxdhash = WorldForm.GameFileCache.TryGetParentYtdHash(txdHash);
while ((ptxdhash != 0) && (tex == null))
{
tex = TryGetTextureFromYtd(texhash, ptxdhash, out ytd);
if (tex == null)
{
ptxdhash = WorldForm.GameFileCache.TryGetParentYtdHash(ptxdhash);
}
else
{ }
}
if (tex == null)
{
ytd = WorldForm.GameFileCache.TryGetTextureDictForTexture(texhash);
if (ytd != null)
{
int tries = 0;
while (!ytd.Loaded && (tries < 500)) //wait upto ~5 sec
{
System.Threading.Thread.Sleep(10);
tries++;
}
if (ytd.Loaded)
{
tex = ytd.TextureDict.Lookup(texhash);
}
}
if (tex == null)
{
ytd = null;
errstr = "<Couldn't find texture!>";
}
}
}
}
if (tex != null)
{
int mip = 0;
if (mipchange)
{
mip = SelTextureMipTrackBar.Value;
if (mip >= tex.Levels) mip = tex.Levels - 1;
}
else
{
SelTextureMipTrackBar.Maximum = tex.Levels - 1;
}
DisplayTexture(tex, mip);
//try get owner drawable to get the name for the dictionary textbox...
object owner = null;
if (Selection.Drawable != null)
{
owner = Selection.Drawable.Owner;
}
YdrFile ydr = owner as YdrFile;
YddFile ydd = owner as YddFile;
YftFile yft = owner as YftFile;
SelTextureNameTextBox.Text = tex.Name;
SelTextureDictionaryTextBox.Text = (ytd != null) ? ytd.Name : (ydr != null) ? ydr.Name : (ydd != null) ? ydd.Name : (yft != null) ? yft.Name : string.Empty;
}
else
{
SelDrawableTexturePictureBox.Image = null;
SelTextureNameTextBox.Text = errstr;
SelTextureDictionaryTextBox.Text = string.Empty;
SelTextureMipTrackBar.Value = 0;
SelTextureMipTrackBar.Maximum = 0;
SelTextureDimensionsLabel.Text = "-";
}
}
private Texture TryGetTextureFromYtd(uint texHash, uint txdHash, out YtdFile ytd)
{
if (txdHash != 0)
{
ytd = WorldForm.GameFileCache.GetYtd(txdHash);
if (ytd != null)
{
int tries = 0;
while (!ytd.Loaded && (tries < 500)) //wait upto ~5 sec
{
System.Threading.Thread.Sleep(10);
tries++;
}
if (ytd.Loaded)
{
return ytd.TextureDict.Lookup(texHash);
}
}
}
ytd = null;
return null;
}
private void WorldInfoForm_Load(object sender, EventArgs e)
{
SetSelection(Selection, SelectionItems);
}
private void WorldInfoForm_FormClosed(object sender, FormClosedEventArgs e)
{
WorldForm.OnInfoFormClosed();
}
public void SyncSelDrawableModelsTreeNode(TreeNode node)
{
//called by the world form when a selection treeview node is checked/unchecked.
foreach (TreeNode mnode in SelDrawableModelsTreeView.Nodes)
{
if (mnode.Tag == node.Tag)
{
if (mnode.Checked != node.Checked)
{
mnode.Checked = node.Checked;
}
}
foreach (TreeNode gnode in mnode.Nodes)
{
if (gnode.Tag == node.Tag)
{
if (gnode.Checked != node.Checked)
{
gnode.Checked = node.Checked;
}
}
}
}
}
private void SelDrawableModelsTreeView_AfterCheck(object sender, TreeViewEventArgs e)
{
WorldForm.SyncSelDrawableModelsTreeNode(e.Node);
}
private void SelDrawableModelsTreeView_AfterSelect(object sender, TreeViewEventArgs e)
{
SelDrawableModelPropertyGrid.SelectedObject = e.Node?.Tag;
}
private void SelDrawableTexturesTreeView_AfterSelect(object sender, TreeViewEventArgs e)
{
SelDrawableTexturePropertyGrid.SelectedObject = e.Node?.Tag;
TextureBase texbase = e.Node?.Tag as TextureBase;
SelTextureMipTrackBar.Value = 0;
SelTextureMipLabel.Text = "0";
SelectTexture(texbase, false);
}
private void SelTextureMipTrackBar_Scroll(object sender, EventArgs e)
{
var node = SelDrawableTexturesTreeView.SelectedNode;
TextureBase texbase = node?.Tag as TextureBase;
SelTextureMipLabel.Text = SelTextureMipTrackBar.Value.ToString();
SelectTexture(texbase, true);
}
private void HierarchyTreeView_AfterSelect(object sender, TreeViewEventArgs e)
{
var sele = HierarchyTreeView.SelectedNode?.Tag as YmapEntityDef;
HierarchyPropertyGrid.SelectedObject = sele;
}
}
}