private void OnYakChildElementSelected(YakChildTreeViewItem childEntry) { SelectedNodeImage = TexDecoder.Decode(childEntry.YakFile.FileData, childEntry.Value.TextureOffset + childEntry.Value.VifOffset, childEntry.Value.VifLength - childEntry.Value.TextureOffset); var log = new StringLogger(); _modelViewModel.Texture = SelectedNodeImage; _modelViewModel.AnimData = null; Model model = new Model(); model.meshList = VifDecoder.Decode( log, childEntry.YakFile.FileData, childEntry.Value.VifOffset, childEntry.Value.TextureOffset, SelectedNodeImage.PixelWidth, SelectedNodeImage.PixelHeight); _modelViewModel.VifModel = model; LogText += log.ToString(); _window.tabControl.SelectedIndex = 1; // Model View _window.ResetCamera(); _window.SetViewportText(1, childEntry.Text + " of " + ((YakTreeViewItem)childEntry.Parent).Text, ""); }
private void OnWorldEntrySelected(WorldFileTreeViewModel worldFileModel) { var engineVersion = App.Settings.Get<EngineVersion>("Core.EngineVersion", EngineVersion.DarkAlliance); var lmpFile = worldFileModel.LmpFileProperty; var entry = lmpFile.Directory[worldFileModel.Text]; WorldFileDecoder decoder = new WorldFileDecoder(); var log = new StringLogger(); _world.worldData = decoder.Decode(engineVersion, _worldTreeViewModel.World().WorldTex, log, lmpFile.FileData, entry.StartOffset, entry.Length); worldFileModel.ReloadChildren(); _levelViewModel.WorldNode = worldFileModel; _levelViewModel.WorldData = _world.worldData; LogText = log.ToString(); LogText += _world.worldData.ToString(); _window.tabControl.SelectedIndex = 3; // Level View _window.ResetCamera(); _window.SetViewportText(3, worldFileModel.Text, ""); // Set Level View Text }
private void OnLmpEntrySelected(LmpEntryTreeViewModel lmpEntry) { var lmpFile = lmpEntry.LmpFileProperty; var entry = lmpFile.Directory[lmpEntry.Text]; var ext = (Path.GetExtension(lmpEntry.Text) ?? "").ToLower(); switch (ext) { case ".tex": { SelectedNodeImage = TexDecoder.Decode(lmpFile.FileData, entry.StartOffset, entry.Length); _window.tabControl.SelectedIndex = 0; // Texture View } break; case ".vif": { string texFilename = Path.GetFileNameWithoutExtension(lmpEntry.Text) + ".tex"; var texEntry = lmpFile.Directory[texFilename]; SelectedNodeImage = TexDecoder.Decode(lmpFile.FileData, texEntry.StartOffset, texEntry.Length); var log = new StringLogger(); _modelViewModel.Texture = SelectedNodeImage; _modelViewModel.AnimData = null; Model model = new Model(); model.meshList = VifDecoder.Decode(log, lmpFile.FileData, entry.StartOffset, entry.Length, SelectedNodeImage.PixelWidth, SelectedNodeImage.PixelHeight); _modelViewModel.VifModel = model; /*// Load animation data var animData = LoadFirstAnim(lmpFile); // Make sure the animation will work with the model if (animData.Count > 0 && animData[0].NumBones == model.CountBones()) _modelViewModel.AnimData = animData.Count == 0 ? null : animData.First();*/ LogText += log.ToString(); _window.tabControl.SelectedIndex = 1; // Model View _window.ResetCamera(); _window.SetViewportText(1, lmpEntry.Text, ""); } break; case ".anm": { var engineVersion = App.Settings.Get("Core.EngineVersion", EngineVersion.DarkAlliance); var animData = AnmDecoder.Decode(engineVersion, lmpFile.FileData, entry.StartOffset, entry.Length); _skeletonViewModel.AnimData = animData; LogText = animData.ToString(); if (_modelViewModel.VifModel != null) { int boneCount = _modelViewModel.VifModel.CountBones(); if (boneCount != 0 && boneCount == animData.NumBones) { _modelViewModel.AnimData = animData; // Switch tab to animation tab only if the current tab isnt the model view tab if (_window.tabControl.SelectedIndex != 1) // Model View { _window.tabControl.SelectedIndex = 2; // Skeleton View _window.ResetCamera(); } } else { // Bone count doesn't match, switch to skeleton view _window.tabControl.SelectedIndex = 2; // Skeleton View _window.ResetCamera(); } } else { _window.tabControl.SelectedIndex = 2; // Skeleton View _window.ResetCamera(); } } _window.SetViewportText(2, lmpEntry.Text, ""); // Set Skeleton View Text break; case ".ob": var objects = ObDecoder.Decode(lmpFile.FileData, entry.StartOffset, entry.Length); var sb = new StringBuilder(); foreach (var obj in objects) { sb.AppendFormat("Name: {0}\n", obj.Name); sb.AppendFormat("I6: {0}\n", obj.I6.ToString("X4")); sb.AppendFormat("Floats: {0},{1},{2}\n", obj.Floats[0], obj.Floats[1], obj.Floats[2]); if (obj.Properties != null) { foreach (var prop in obj.Properties) { sb.AppendFormat("Property: {0}\n", prop); } } sb.Append("\n"); } LogText = sb.ToString(); _window.tabControl.SelectedIndex = 4; // Log View break; } }
public WorldData Decode(EngineVersion engineVersion, WorldTexFile texFile, ILogger log, byte[] data, int startOffset, int length) { WorldData worldData = new WorldData(); var reader = new DataReader(data, startOffset, length); int numElements = reader.ReadInt32(); // 0 reader.Skip(12); // Skipping 3 ints int numCols = reader.ReadInt32(); // x10 int numRows = reader.ReadInt32(); // x14 reader.Skip(12); // Skipping 3 ints // x18 x1c x20 int elementArrayStart = reader.ReadInt32(); // x24 reader.Skip(8); // Skipping 2 ints int off38Cols = reader.ReadInt32(); int off38Rows = reader.ReadInt32(); int off38 = reader.ReadInt32(); reader.Skip(28); int texll = reader.ReadInt32(); int texur = reader.ReadInt32(); int texX0 = texll % 100; int texY0 = texll / 100; int texX1 = texur % 100; int texY1 = texur / 100; reader.Skip(4); int worldTexOffsetsOffset = reader.ReadInt32(); worldData.textureChunkOffsets = readTextureChunkOffsets(engineVersion, data, startOffset + worldTexOffsetsOffset, texX0, texY0, texX1+1, texY1); worldData.worldElements = new List<WorldElement>(numElements); for (int elementIdx = 0; elementIdx < numElements; ++elementIdx) { var element = new WorldElement(); if (EngineVersion.ReturnToArms == engineVersion) { reader.SetOffset(elementArrayStart + elementIdx * 0x3C); } else // Default to Dark Allience version { reader.SetOffset(elementArrayStart + elementIdx * 0x38); } int vifDataOffset = reader.ReadInt32(); if (EngineVersion.DarkAlliance == engineVersion) { int tex2 = reader.ReadInt32(); if (tex2 != 0) { log.LogLine("Tex2=" + tex2); } } int vifLen = reader.ReadInt32(); log.LogLine("-----------"); log.LogLine("vifdata: " + vifDataOffset + ", " + vifLen); float x1 = reader.ReadFloat(); float y1 = reader.ReadFloat(); float z1 = reader.ReadFloat(); float x2 = reader.ReadFloat(); float y2 = reader.ReadFloat(); float z2 = reader.ReadFloat(); element.boundingBox = new Rect3D(x1, y1, z1, x2 - x1, y2 - y1, z2 - z1); log.LogLine("Bounding Box: " + element.boundingBox.ToString()); int textureNum = reader.ReadInt32() / 0x40; log.LogLine("Texture Num: " + textureNum); int texCellxy = reader.ReadInt16(); int y = texCellxy / 100; int x = texCellxy % 100; if (EngineVersion.ReturnToArms == engineVersion) { x += texX0; y += texY0; } if (textureNum != 0) { if (EngineVersion.ReturnToArms == engineVersion) { element.Texture = texFile.GetBitmapRTA(x, y, textureNum); } else { element.Texture = texFile.GetBitmap(worldData.textureChunkOffsets[y, x], textureNum); } } if (element.Texture != null) { log.LogLine("Found in texture chunk: " + x + ", " + y); } var vifLogger = new StringLogger(); int texWidth = 100; int texHeight = 100; if (element.Texture != null) { texWidth = element.Texture.PixelWidth; texHeight = element.Texture.PixelHeight; } byte nregs = data[startOffset + vifDataOffset + 0x10]; int vifStartOffset = (nregs + 2) * 0x10; element.VifDataOffset = startOffset + vifDataOffset + vifStartOffset; element.VifDataLength = vifLen*0x10 - vifStartOffset; element.model = decodeModel(engineVersion, vifLogger, data, startOffset + vifDataOffset + vifStartOffset, vifLen * 0x10 - vifStartOffset, texWidth, texHeight); if (EngineVersion.ReturnToArms == engineVersion) { int unk = reader.ReadInt16(); log.LogLine("Unknown: " + unk); } int posx = reader.ReadInt16(); int posy = reader.ReadInt16(); int posz = reader.ReadInt16(); log.LogLine("Position : " + posx + ", " + posy + ", " + posz); element.pos = new Vector3D(posx / 16.0, posy / 16.0, posz / 16.0); if (EngineVersion.ReturnToArms == engineVersion) { // Just a guess, maybe wrong. element.pos = new Vector3D(posx / 16.0, posz / 16.0, posy / 16.0); } // I don't think RTA uses this flags scheme. From the data it looks like there are // 2 shorts (or possibly floats) following. int flags = reader.ReadInt32(); if ((flags & 0x01) == 0) { log.LogLine("Flags : " + HexUtil.formatHexUShort(flags & 0xFFFF)); element.cosAlpha = (flags >> 16) / 32767.0; element.sinAlpha = reader.ReadInt16() / 32767.0; log.LogLine("cos alpha : " + element.cosAlpha); log.LogLine("sin alpha : " + element.sinAlpha); log.LogLine("alpha(cos, sin): " + Math.Acos(element.cosAlpha) * 180.0 / Math.PI + ", " + Math.Asin(element.sinAlpha) * 180.0 / Math.PI); element.usesRotFlags = false; } else { reader.ReadInt16(); // not necessary but makes the code more obvious. log.LogLine("Flags : " + HexUtil.formatHex(flags)); element.xyzRotFlags = (flags >> 16) & 7; element.usesRotFlags = true; log.LogLine("Rot Flags : " + element.xyzRotFlags); } element.negYaxis = (flags & 0x40) == 0x40; if (EngineVersion.ReturnToArms == engineVersion) { flags = 0; element.usesRotFlags = true; log.LogLine("Forcing flags to 0 until we know the format better"); } worldData.worldElements.Add(element); } return worldData; }
private Visual3D LoadModelFromOtherLmp(string lmpName, string file, string textureFile) { var par = _manager.LevelViewModel.WorldNode.Parent.Parent; if (par is GobTreeViewModel) { var gob = (GobTreeViewModel) par; foreach (LmpTreeViewModel child in gob.Children) { if (string.Compare(child.Text, lmpName, StringComparison.InvariantCultureIgnoreCase) == 0) { child.ForceLoadChildren(); var entry = child.LmpFileProperty.FindFile(file); var texEntry = child.LmpFileProperty.FindFile(textureFile); if (entry == null || texEntry == null) return CreateBox(5, Color.FromRgb(255,0,0)); var tex = TexDecoder.Decode(child.LmpFileProperty.FileData, texEntry.StartOffset, texEntry.Length); var logger = new StringLogger(); var vifModel = VifDecoder.Decode( logger, child.LmpFileProperty.FileData, entry.StartOffset, entry.Length, tex.PixelWidth, tex.PixelHeight); var model = new ModelVisual3D(); model.Content = VifDecoder.CreateModel3D(vifModel, tex, null, -1); model.Transform = new ScaleTransform3D(1.0 / 4, 1.0 / 4, 1.0 / 4); return model; } } } return CreateBox(5, Color.FromRgb(255, 0, 0)); }
void SaveParsedDataClicked(object sender, RoutedEventArgs e) { if (_menu.DataContext == null) return; if (_menu.DataContext is LmpEntryTreeViewModel) { var lmpEntry = (LmpEntryTreeViewModel)_menu.DataContext; var lmpFile = lmpEntry.LmpFileProperty; var entry = lmpFile.Directory[lmpEntry.Text]; var texEntry = lmpFile.Directory[Path.GetFileNameWithoutExtension(lmpEntry.Text)+".tex"]; var tex = TexDecoder.Decode(lmpFile.FileData, texEntry.StartOffset, texEntry.Length); if ((Path.GetExtension(lmpEntry.Text) ?? "").ToLower() != ".vif") { MessageBox.Show("Not a .vif file!", "Error"); return; } var dialog = new SaveFileDialog(); dialog.FileName = lmpEntry.Text+".txt"; bool? result = dialog.ShowDialog(); if (result.GetValueOrDefault(false)) { var exporter = new VifExporter(); var logger = new StringLogger(); var chunks = VifDecoder.DecodeChunks( logger, lmpFile.FileData, entry.StartOffset, entry.Length, tex.PixelWidth, tex.PixelHeight); exporter.WriteChunks(dialog.FileName, chunks); } } else if (_menu.DataContext is WorldElementTreeViewModel) { var worldElement = (WorldElementTreeViewModel)_menu.DataContext; var lmpEntry = (LmpTreeViewModel)worldElement.Parent; var lmpFile = lmpEntry.LmpFileProperty; var dialog = new SaveFileDialog(); dialog.FileName = worldElement.Text + ".txt"; bool? result = dialog.ShowDialog(); if (result.GetValueOrDefault(false)) { var exporter = new VifExporter(); var logger = new StringLogger(); var chunks = VifDecoder.ReadVerts( logger, lmpFile.FileData, worldElement.WorldElement.VifDataOffset, worldElement.WorldElement.VifDataOffset + worldElement.WorldElement.VifDataLength); exporter.WriteChunks(dialog.FileName, chunks); } } }