mirror of
https://mirror.ghproxy.com/https://github.com/dexyfex/CodeWalker
synced 2024-11-23 15:32:54 +08:00
529 lines
19 KiB
C#
529 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;
|
|
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)
|
|
{
|
|
Selection = item;
|
|
|
|
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.MultipleSelectionItems != null)
|
|
{
|
|
SelectionEntityTabPage.Text = "Multiple items";
|
|
SelEntityPropertyGrid.SelectedObject = item.MultipleSelectionItems;
|
|
}
|
|
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.CollisionVertex != null)
|
|
{
|
|
SelectionExtensionTabPage.Text = "Collision Vertex";
|
|
SelExtensionPropertyGrid.SelectedObject = item.CollisionVertex;
|
|
}
|
|
else if (item.CollisionPoly != null)
|
|
{
|
|
SelectionExtensionTabPage.Text = "Collision Polygon";
|
|
SelExtensionPropertyGrid.SelectedObject = item.CollisionPoly;
|
|
}
|
|
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);
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
}
|