Skip to content

added 3D Preview of the models #168

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
263 changes: 174 additions & 89 deletions TankLib/Chunks/teModelChunk_RenderMesh.cs

Large diffs are not rendered by default.

36 changes: 36 additions & 0 deletions TankLib/Math/teTriangle.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;

namespace TankLib.Math {
[StructLayout(LayoutKind.Sequential, Pack = 4)]
[DebuggerDisplay("A: {IndexA}, B: {IndexB}, C: {IndexC}")]
public struct teTriangle {

/// <summary>Index 1</summary>
public int IndexA;

/// <summary>Index 2</summary>
public int IndexB;

/// <summary>Index 3</summary>
public int IndexC;

public teTriangle(ushort indexA, ushort indexB, ushort indexC) {
IndexA = (int) indexA;
IndexB = (int) indexB;
IndexC = (int) indexC;
}

public teTriangle(IReadOnlyList<ushort> val) {
if (val.Count != 3) {
throw new InvalidDataException();
}
IndexA = val[0];
IndexB = val[1];
IndexC = val[2];
}

}
}
15 changes: 11 additions & 4 deletions TankView/MainWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,12 @@
IsChecked="{Binding OnlyShowNewFiles, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
IsCheckable="True" />
</MenuItem>
<MenuItem Header="Extract" Click="ExtractFiles"
<MenuItem Header="Extract" Click="ExtractFiles" Width="100"
IsEnabled="{Binding IsDataReady, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}" Background="Transparent"
HorizontalContentAlignment="Center" VerticalContentAlignment="Center"/>
HorizontalContentAlignment="Left" VerticalContentAlignment="Center"/>
<MenuItem Header="Obj Export" Click="ExtractAsObj" Width="100"
IsEnabled="{Binding IsDataReady, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}" Background="Transparent"
HorizontalContentAlignment="Left" VerticalContentAlignment="Center"/>
<MenuItem IsEnabled="{Binding IsDataReady, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}" Background="Transparent"
HorizontalContentAlignment="Center" VerticalContentAlignment="Center">
<MenuItem.Header>
Expand Down Expand Up @@ -209,15 +212,19 @@
IsEnabled="{Binding ShowPreview, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}"
Visibility="{Binding ShowPreview, UpdateSourceTrigger=PropertyChanged, Mode=OneWay, Converter={StaticResource BoolVisbilityConverter}}"
Grid.Row="0" Height="3" HorizontalAlignment="Stretch" VerticalAlignment="Bottom"
ResizeDirection="Rows" ShowsPreview="True" ResizeBehavior="CurrentAndNext" />
ResizeDirection="Rows" ShowsPreview="True" ResizeBehavior="CurrentAndNext">
<GridSplitter.Background>
<SolidColorBrush Color="White"/>
</GridSplitter.Background>
</GridSplitter>
<DockPanel IsEnabled="{Binding ShowPreview, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}"
Visibility="{Binding ShowPreview, UpdateSourceTrigger=PropertyChanged, Mode=OneWay, Converter={StaticResource BoolVisbilityConverter}}"
Grid.Row="1">
<ContentControl Content="{Binding PreviewControl}" />
</DockPanel>
</Grid>
</TabItem>
<TabItem Header="Image" IsEnabled="{Binding ShowPreviewList, UpdateSourceTrigger=PropertyChanged, Mode=OneWay, Converter={StaticResource BoolVisbilityConverter}}">
<TabItem Header="Image" IsEnabled="{Binding ShowPreviewList, UpdateSourceTrigger=PropertyChanged, Mode=OneWay, Converter={StaticResource BoolVisbilityConverter}}" HorizontalAlignment="Right" Width="49">
<ListView x:Name="FolderImageList" ItemsSource="{Binding SelectedEntries, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}" VirtualizingPanel.CacheLengthUnit="Page" VirtualizingPanel.CacheLength="1, 1" VirtualizingPanel.ScrollUnit="Item" VirtualizingPanel.VirtualizationMode="Recycling">
<ListView.Resources>
<Style x:Key="{x:Type ListViewItem}" TargetType="ListViewItem" BasedOn="{StaticResource {x:Type ListViewItem}}">
Expand Down
160 changes: 144 additions & 16 deletions TankView/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ void GridViewColumnHeaderClickedHandler(object sender, RoutedEventArgs e) {
if (headerClicked.Role == GridViewColumnHeaderRole.Padding) return;

ListSortDirection direction;
if (headerClicked != _lastHeaderClicked) {
if (headerClicked != _lastHeaderClicked) {
direction = ListSortDirection.Descending;
} else {
direction = _lastDirection == ListSortDirection.Ascending ? ListSortDirection.Descending : ListSortDirection.Ascending;
Expand Down Expand Up @@ -324,21 +324,21 @@ private void ChangeActiveNode(object sender, RoutedEventArgs e) {
}

private void ExtractFiles(object sender, RoutedEventArgs e) {
GUIDEntry[] files = {};
GUIDEntry[] files = { };

switch (Tabs.SelectedIndex) {
case 0: {
files = FolderItemList.SelectedItems.OfType<GUIDEntry>().ToArray();
if (files.Length == 0) {
files = FolderItemList.Items.OfType<GUIDEntry>().ToArray();
case 0: {
files = FolderItemList.SelectedItems.OfType<GUIDEntry>().ToArray();
if (files.Length == 0) {
files = FolderItemList.Items.OfType<GUIDEntry>().ToArray();
}

break;
}
case 1: {
files = FolderImageList.SelectedItems.OfType<GUIDEntry>().ToArray();
break;
}

break;
}
case 1: {
files = FolderImageList.SelectedItems.OfType<GUIDEntry>().ToArray();
break;
}
}

if (files.Length == 0) {
Expand All @@ -354,7 +354,7 @@ private void ExtractFiles(object sender, RoutedEventArgs e) {
}
}

private void ExtractFiles(string outPath, IEnumerable<GUIDEntry> files) {
private void ExtractFiles_OLD(string outPath, IEnumerable<GUIDEntry> files) {
IsReady = false;

IEnumerable<GUIDEntry> guidEntries = files as GUIDEntry[] ?? files.ToArray();
Expand Down Expand Up @@ -421,7 +421,80 @@ private void ExtractFiles(string outPath, IEnumerable<GUIDEntry> files) {

ViewContext.Send(delegate { IsReady = true; }, null);
});
}
}

private void ExtractFiles(string outPath, IEnumerable<GUIDEntry> files) {
IsReady = false;

IEnumerable<GUIDEntry> guidEntries = files as GUIDEntry[] ?? files.ToArray();
HashSet<string> directories = new HashSet<string>(guidEntries.Select(x => Path.Combine(outPath, Path.GetDirectoryName(x.FullPath.Substring(1)) ?? string.Empty)));
foreach (string directory in directories) {
if (!Directory.Exists(directory)) {
Directory.CreateDirectory(directory);
}
}

var imageExtractFlags = new ExtractFlags {
ConvertTexturesType = Settings.Default.ImageExtractionFormat
};

//Task.Run(delegate {
int c = 0;
int t = guidEntries.Count();
_progressWorker?.ReportProgress(0, "Saving files...");
//Parallel.ForEach(guidEntries, new ParallelOptions { MaxDegreeOfParallelism = 4 },
//(entry) => {

foreach (var entry in guidEntries) {


c++;
if (c % ((int) (t * 0.005) + 1) == 0) {
var progress = (int) ((c / (float) t) * 100);
_progressWorker?.ReportProgress(progress, $"Saving files... {progress}% ({c}/{t})");
}

var dataType = DataHelper.GetDataType(teResourceGUID.Type(entry.GUID));
var fileType = Path.GetExtension(entry.FullPath)?.Substring(1);
var filePath = Path.ChangeExtension(entry.FullPath.Substring(1), null);
var fileOutput = $"{filePath}.{GetFileType(dataType) ?? fileType}";

try {
if (dataType == DataHelper.DataType.Image && ExtractionSettings.EnableConvertImages) {
DataTool.FindLogic.Combo.ComboInfo info = new DataTool.FindLogic.Combo.ComboInfo();
DataTool.FindLogic.Combo.Find(info, entry.GUID);
var newPath = Path.GetFullPath(Path.Combine(outPath, filePath, @"..\")); // filepath includes the filename which we don't want here as combo already does that
var context = new Combo.SaveContext(info);
Combo.SaveLooseTextures(imageExtractFlags, newPath, context);

return;
}

using (Stream i = IOHelper.OpenFile(entry))
using (Stream o = File.OpenWrite(Path.Combine(outPath, fileOutput))) {
switch (dataType) {
case DataHelper.DataType.Sound when ExtractionSettings.EnableConvertSounds:
o.SetLength(0);
Combo.ConvertSoundFileWw2Ogg(i, o);
break;
// not used, image extraction is handled above
case DataHelper.DataType.Image when ExtractionSettings.EnableConvertImages:
DataHelper.SaveImage(entry, i, o);
break;
default:
i.CopyTo(o);
break;
}
}
} catch {
// ignored
}
}
//});

ViewContext.Send(delegate { IsReady = true; }, null);
//});
}

private string GetFileType(DataHelper.DataType dataType) {
switch (dataType) {
Expand Down Expand Up @@ -475,6 +548,61 @@ private void FolderItemList_OnMouseDoubleClick(object sender, MouseButtonEventAr
if (e.Source is ListView listView && listView.SelectedItem is GUIDEntry guidEntry) {
Clipboard.SetText(guidEntry.Filename);
}
}
}

private void ExtractAsObj(object sender, RoutedEventArgs e) {

GUIDEntry[] files = { };

if (Tabs.SelectedIndex == 0) {
files = FolderItemList.SelectedItems.OfType<GUIDEntry>().ToArray();
if (files.Length == 0) {
files = FolderItemList.Items.OfType<GUIDEntry>().ToArray();
}
}
if (files.Length == 0) return;

CommonOpenFileDialog dialog = new CommonOpenFileDialog {
IsFolderPicker = true,
EnsurePathExists = true
};
if (dialog.ShowDialog() == CommonFileDialogResult.Ok) {
ExtractFilesAsObj(dialog.FileName, files);
}
}

private void ExtractFilesAsObj(string outPath, IEnumerable<GUIDEntry> files) {

var logFile = Path.Combine(outPath, "export.log");
if (File.Exists(logFile)) File.Delete(logFile);

foreach (var entry in files) {

try {

using (Stream i = IOHelper.OpenFile(entry)) {

var chunkedData = new teChunkedData(i);

foreach (var chunk in chunkedData.Chunks) {
if (chunk is TankLib.Chunks.teModelChunk_RenderMesh) {
ProgressInfo.State = $"Converting {entry.Filename} to obj";
(chunk as TankLib.Chunks.teModelChunk_RenderMesh).ExportToObj(path: outPath, file: entry.Filename + ".obj");

}
}

}
} catch (Exception ex) {

using (TextWriter str = new StreamWriter(path: logFile, append: true)) {
str.WriteLine($"Unable to convert { entry.Filename}");
str.WriteLine(ex.Message);
}

}
}

}
}
}
2 changes: 2 additions & 0 deletions TankView/TankView.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
<PackageReference Include="AdonisUI" Version="1.17.1" />
<PackageReference Include="AdonisUI.ClassicTheme" Version="1.17.1" />
<PackageReference Include="DirectXTexNet" Version="1.0.3" />
<PackageReference Include="HelixToolkit" Version="2.23.0" />
<PackageReference Include="HelixToolkit.Core.Wpf" Version="2.23.0" />
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
<PackageReference Include="NAudio" Version="2.1.0" />
<PackageReference Include="NAudio.Vorbis" Version="1.5.0" />
Expand Down
19 changes: 16 additions & 3 deletions TankView/View/PreviewDataModel.xaml
Original file line number Diff line number Diff line change
@@ -1,12 +1,25 @@
<UserControl x:Class="TankView.View.PreviewDataModel"
<UserControl x:Class="TankView.View.PreviewDataModel"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:TankView.View"
xmlns:local="clr-namespace:TankView.View"
xmlns:helix="http://helix-toolkit.org/wpf"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<TextBlock Margin="15,15,15,15">Soon!</TextBlock>
<helix:HelixViewport3D
x:Name="MyHelixViewport"
ZoomExtentsWhenLoaded="True"
CameraRotationMode="Trackball"
CameraChanged="MyHelixViewport_CameraChanged"
>
<helix:DefaultLights/>
<ModelVisual3D x:Name="Content3D">


</ModelVisual3D>
<helix:GridLinesVisual3D Width="3" Length="3" MinorDistance="1" MajorDistance="1" Thickness="0.01" ></helix:GridLinesVisual3D>
</helix:HelixViewport3D>
</Grid>
</UserControl>
Loading