Initial release
This commit is contained in:
commit
8f7e17251f
330
.gitignore
vendored
Normal file
330
.gitignore
vendored
Normal file
@ -0,0 +1,330 @@
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
##
|
||||
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||
|
||||
# User-specific files
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
|
||||
# Visual Studio 2015/2017 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# Visual Studio 2017 auto generated files
|
||||
Generated\ Files/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUNIT
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# Benchmark Results
|
||||
BenchmarkDotNet.Artifacts/
|
||||
|
||||
# .NET Core
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
**/Properties/launchSettings.json
|
||||
|
||||
# StyleCop
|
||||
StyleCopReport.xml
|
||||
|
||||
# Files built by Visual Studio
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_i.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.iobj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.ipdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# Visual Studio Trace Files
|
||||
*.e2e
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# JustCode is a .NET coding add-in
|
||||
.JustCode
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# AxoCover is a Code Coverage Tool
|
||||
.axoCover/*
|
||||
!.axoCover/settings.json
|
||||
|
||||
# Visual Studio code coverage results
|
||||
*.coverage
|
||||
*.coveragexml
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||
# in these scripts will be unencrypted
|
||||
PublishScripts/
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/[Pp]ackages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/[Pp]ackages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/[Pp]ackages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignorable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Windows Store app package directories and files
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
Package.StoreAssociation.xml
|
||||
_pkginfo.txt
|
||||
*.appx
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.jfm
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
orleans.codegen.cs
|
||||
|
||||
# Including strong name files can present a security risk
|
||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||
#*.snk
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
ServiceFabricBackup/
|
||||
*.rptproj.bak
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
*.ndf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
*.rptproj.rsuser
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
node_modules/
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||
*.vbw
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
paket-files/
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
|
||||
# JetBrains Rider
|
||||
.idea/
|
||||
*.sln.iml
|
||||
|
||||
# CodeRush
|
||||
.cr/
|
||||
|
||||
# Python Tools for Visual Studio (PTVS)
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# Cake - Uncomment if you are using it
|
||||
# tools/**
|
||||
# !tools/packages.config
|
||||
|
||||
# Tabs Studio
|
||||
*.tss
|
||||
|
||||
# Telerik's JustMock configuration file
|
||||
*.jmconfig
|
||||
|
||||
# BizTalk build output
|
||||
*.btp.cs
|
||||
*.btm.cs
|
||||
*.odx.cs
|
||||
*.xsd.cs
|
||||
|
||||
# OpenCover UI analysis results
|
||||
OpenCover/
|
||||
|
||||
# Azure Stream Analytics local run output
|
||||
ASALocalRun/
|
||||
|
||||
# MSBuild Binary and Structured Log
|
||||
*.binlog
|
||||
|
||||
# NVidia Nsight GPU debugger configuration file
|
||||
*.nvuser
|
||||
|
||||
# MFractors (Xamarin productivity tool) working folder
|
||||
.mfractor/
|
29
README
Normal file
29
README
Normal file
@ -0,0 +1,29 @@
|
||||
## gitadora-texbintool.exe
|
||||
Convert archives of tex images.
|
||||
```
|
||||
usage: gitadora-texbintool.exe [--no-rect/--nr] [--no-split/--ns] input_filename
|
||||
--no-rect/--nr: Don't create a rect table (Some games like Jubeat don't use the rect table)
|
||||
--no-split/--ns: Don't split images into separate images if they use the rect table
|
||||
```
|
||||
|
||||
If you specify a .bin file as the `input_filename` then the tool will extract the textures into a folder with the same name as the .bin file.
|
||||
If you specify a folder as the `input_filename` then the tool will create a .bin file with the same name as the folder.
|
||||
|
||||
`--no-rect` is used for .bin creation. It skips writing the rect section at the end of the bin file.
|
||||
|
||||
`--no-split` is used during .bin extraction. Texbins can have multiple files, and within those files have multiple rects/subimages.
|
||||
This command will output the original images with a `metadata.xml` file containing the rect information.
|
||||
When creating a .bin from a folder with a `metadata.xml`, the `metadata.xml` is used to create the .bin. Any files in the folder not listed in the `metadata.xml` will be ignored.
|
||||
If you want to replace a specific subimage without modifying the original image file, you can modify the `ExternalFilename` part of the `metadata.xml` to point to the new image file while updating the X/Y (set to 0) and updating the W/H (set as required).
|
||||
|
||||
## gitadora-textool.exe
|
||||
Convert individual tex files.
|
||||
```
|
||||
usage: gitadora-textool.exe input_filename
|
||||
```
|
||||
|
||||
If you specify a .tex file as the `input_filename` then the tool will convert the .tex to .png.
|
||||
|
||||
If you specify a non-.tex file as the `input_filename` then the tool will try to convert the image file to .tex.
|
||||
The tool uses C#'s Bitmap class to load images, so any format supported normally by C# should work (PNG, JPG, BMP, etc).
|
||||
PNG is the only "officially" supported format but JPG should be safe as well, and probably others too.
|
6
gitadora-texbintool/App.config
Normal file
6
gitadora-texbintool/App.config
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
|
||||
</startup>
|
||||
</configuration>
|
693
gitadora-texbintool/Program.cs
Normal file
693
gitadora-texbintool/Program.cs
Normal file
@ -0,0 +1,693 @@
|
||||
using System;
|
||||
using System.CodeDom;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using System.Xml.Serialization;
|
||||
using gitadora_textool;
|
||||
|
||||
namespace gitadora_texbintool
|
||||
{
|
||||
public class EntryInfo
|
||||
{
|
||||
public int Id;
|
||||
public int Hash;
|
||||
public int Offset;
|
||||
public string Filename;
|
||||
|
||||
// For data entry
|
||||
public int Unk1;
|
||||
public int CompSize;
|
||||
public int DataOffset;
|
||||
}
|
||||
|
||||
public struct RectMetadata
|
||||
{
|
||||
public int ImageId;
|
||||
public ushort X;
|
||||
public ushort Y;
|
||||
public ushort W;
|
||||
public ushort H;
|
||||
public EntryInfo Entry;
|
||||
}
|
||||
|
||||
public class TexInfo
|
||||
{
|
||||
public List<RectInfo> RectInfo;
|
||||
|
||||
public TexInfo()
|
||||
{
|
||||
RectInfo = new List<RectInfo>();
|
||||
}
|
||||
}
|
||||
|
||||
class Program
|
||||
{
|
||||
static int ReadInt32(BinaryReader reader)
|
||||
{
|
||||
var data = reader.ReadBytes(4);
|
||||
Array.Reverse(data);
|
||||
return BitConverter.ToInt32(data, 0);
|
||||
}
|
||||
|
||||
static byte[] Decompress(BinaryReader reader)
|
||||
{
|
||||
var decompSize = ReadInt32(reader);
|
||||
var compSize = ReadInt32(reader);
|
||||
|
||||
if (compSize == 0)
|
||||
{
|
||||
return reader.ReadBytes(decompSize);
|
||||
}
|
||||
|
||||
var compData = reader.ReadBytes(compSize);
|
||||
|
||||
byte[] windowData = new byte[4096];
|
||||
byte[] outputData = new byte[decompSize];
|
||||
int compOffset = 0, decompOffset = 0, window = 4078;
|
||||
|
||||
uint controlByte = 0;
|
||||
int bitCount = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (bitCount == 0)
|
||||
{
|
||||
if (compOffset >= compSize)
|
||||
{
|
||||
//Console.WriteLine($"compOffset >= compSize: {compOffset} >= {compSize}");
|
||||
break;
|
||||
}
|
||||
|
||||
controlByte = compData[compOffset++];
|
||||
bitCount = 8;
|
||||
}
|
||||
|
||||
if ((controlByte & 0x01) != 0)
|
||||
{
|
||||
if (compOffset >= compSize)
|
||||
{
|
||||
//Console.WriteLine($"compOffset >= compSize: {compOffset} >= {compSize}");
|
||||
break;
|
||||
}
|
||||
|
||||
outputData[decompOffset] = windowData[window] = compData[compOffset];
|
||||
decompOffset++;
|
||||
window++;
|
||||
compOffset++;
|
||||
|
||||
if (decompOffset >= decompSize)
|
||||
{
|
||||
//Console.WriteLine($"decompOffset >= decompSize: {decompOffset} >= {decompSize}");
|
||||
break;
|
||||
}
|
||||
|
||||
window &= 0xfff;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (decompOffset >= decompSize - 1)
|
||||
{
|
||||
//Console.WriteLine($"decompOffset >= decompSize - 1: {decompOffset} >= {decompSize} - 1");
|
||||
break;
|
||||
}
|
||||
|
||||
var slideOffset = (((compData[compOffset + 1] & 0xf0) << 4) | compData[compOffset]) & 0xfff;
|
||||
var slideLength = (compData[compOffset + 1] & 0x0f) + 3;
|
||||
compOffset += 2;
|
||||
|
||||
if (decompOffset + slideLength > decompSize)
|
||||
{
|
||||
slideLength = decompSize - decompOffset;
|
||||
}
|
||||
|
||||
//Console.WriteLine("{0:x8} {1:x8}", slideOffset, slideLength);
|
||||
|
||||
while (slideLength > 0)
|
||||
{
|
||||
outputData[decompOffset] = windowData[window] = windowData[slideOffset];
|
||||
decompOffset++;
|
||||
window++;
|
||||
slideOffset++;
|
||||
|
||||
window &= 0xfff;
|
||||
slideOffset &= 0xfff;
|
||||
slideLength--;
|
||||
}
|
||||
}
|
||||
|
||||
controlByte >>= 1;
|
||||
bitCount--;
|
||||
}
|
||||
|
||||
return outputData;
|
||||
}
|
||||
|
||||
static int CalculateHash(string input)
|
||||
{
|
||||
int hash = 0;
|
||||
|
||||
foreach (var c in input)
|
||||
{
|
||||
for (int i = 0; i <= 5; i++)
|
||||
{
|
||||
hash = (hash >> 31) & 0x4C11DB7 ^ ((hash << 1) | ((c >> i) & 1));
|
||||
}
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
static void ReadDataEntrySection(BinaryReader reader, int offset, Int64 count, List<EntryInfo> entries)
|
||||
{
|
||||
reader.BaseStream.Seek(offset, SeekOrigin.Begin);
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
entries[i].Unk1 = reader.ReadInt32();
|
||||
entries[i].CompSize = reader.ReadInt32();
|
||||
entries[i].DataOffset = reader.ReadInt32();
|
||||
}
|
||||
}
|
||||
|
||||
static List<EntryInfo> ReadNameSection(BinaryReader reader, int offset)
|
||||
{
|
||||
reader.BaseStream.Seek(offset, SeekOrigin.Begin);
|
||||
|
||||
var nampMagic = Encoding.ASCII.GetString(reader.ReadBytes(4));
|
||||
if (nampMagic != "PMAN")
|
||||
{
|
||||
Console.WriteLine("Not a valid name section");
|
||||
Environment.Exit(1);
|
||||
}
|
||||
|
||||
var nampSectionSize = reader.ReadInt32();
|
||||
var unk1 = reader.ReadBytes(8);
|
||||
var fileCount = reader.ReadInt32();
|
||||
var unk2 = reader.ReadBytes(8);
|
||||
|
||||
var stringMetadata = new List<EntryInfo>();
|
||||
for (int i = 0; i < fileCount; i++)
|
||||
{
|
||||
int hash = reader.ReadInt32();
|
||||
int id = reader.ReadInt32();
|
||||
int strOffset = reader.ReadInt32();
|
||||
|
||||
var backupOffset = reader.BaseStream.Position;
|
||||
|
||||
reader.BaseStream.Seek(offset + strOffset, SeekOrigin.Begin);
|
||||
var strBytes = new List<byte>();
|
||||
while (reader.PeekChar() != 0)
|
||||
{
|
||||
strBytes.Add(reader.ReadByte());
|
||||
}
|
||||
|
||||
var str = Encoding.ASCII.GetString(strBytes.ToArray());
|
||||
|
||||
stringMetadata.Add(new EntryInfo() { Offset = strOffset, Id = id, Hash = hash, Filename = str });
|
||||
|
||||
reader.BaseStream.Seek(backupOffset, SeekOrigin.Begin);
|
||||
}
|
||||
|
||||
stringMetadata.Sort((x, y) => x.Id.CompareTo(y.Id));
|
||||
|
||||
return stringMetadata;
|
||||
}
|
||||
|
||||
static List<RectMetadata> ReadRectEntrySection(BinaryReader reader, int offset)
|
||||
{
|
||||
reader.BaseStream.Seek(offset, SeekOrigin.Begin);
|
||||
|
||||
var rectMagic = Encoding.ASCII.GetString(reader.ReadBytes(4));
|
||||
if (rectMagic != "TCER")
|
||||
{
|
||||
Console.WriteLine("Not a valid rect section");
|
||||
Environment.Exit(1);
|
||||
}
|
||||
|
||||
var unk1 = reader.ReadInt32();
|
||||
var unk2 = reader.ReadInt32();
|
||||
var rectSectionSize = reader.ReadInt32();
|
||||
var layerCount = reader.ReadInt32();
|
||||
var namOffset = reader.ReadInt32();
|
||||
var rectOffset = reader.ReadInt32();
|
||||
|
||||
var stringMetadata = ReadNameSection(reader, offset + namOffset);
|
||||
|
||||
reader.BaseStream.Seek(offset + rectOffset, SeekOrigin.Begin);
|
||||
|
||||
var rectInfoMetadata = new List<RectMetadata>();
|
||||
for (int i = 0; i < layerCount; i++)
|
||||
{
|
||||
var rect = new RectMetadata();
|
||||
rect.ImageId = reader.ReadInt32();
|
||||
rect.X = reader.ReadUInt16();
|
||||
rect.W = (ushort)(reader.ReadUInt16() - rect.X);
|
||||
rect.Y = reader.ReadUInt16();
|
||||
rect.H = (ushort)(reader.ReadUInt16() - rect.Y);
|
||||
rect.Entry = stringMetadata[i];
|
||||
rectInfoMetadata.Add(rect);
|
||||
|
||||
Console.WriteLine("{0:x4}x{1:x4} {2:x4}x{3:x4}", rect.X, rect.Y, rect.W, rect.H);
|
||||
}
|
||||
|
||||
return rectInfoMetadata;
|
||||
}
|
||||
|
||||
public static string Serialize<T>(T value, string outputFilename = null)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
try
|
||||
{
|
||||
var xmlserializer = new XmlSerializer(typeof(T));
|
||||
|
||||
XmlWriterSettings settings = new XmlWriterSettings();
|
||||
settings.Indent = true;
|
||||
settings.IndentChars = ("\t");
|
||||
|
||||
XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces();
|
||||
namespaces.Add(string.Empty, string.Empty);
|
||||
|
||||
if (outputFilename != null)
|
||||
{
|
||||
using (var writer = XmlWriter.Create(outputFilename, settings))
|
||||
{
|
||||
xmlserializer.Serialize(writer, value, namespaces);
|
||||
}
|
||||
}
|
||||
|
||||
var stringWriter = new StringWriter();
|
||||
|
||||
using (var writer = XmlWriter.Create(stringWriter, settings))
|
||||
{
|
||||
xmlserializer.Serialize(writer, value, namespaces);
|
||||
return stringWriter.ToString();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new Exception("An error occurred", ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static TexInfo Deserialize(string filename)
|
||||
{
|
||||
XmlSerializer serializer = new XmlSerializer(typeof(TexInfo));
|
||||
|
||||
StreamReader reader = new StreamReader(filename);
|
||||
var texInfoList = (TexInfo)serializer.Deserialize(reader);
|
||||
reader.Close();
|
||||
|
||||
for (var index = 0; index < texInfoList.RectInfo.Count; index++)
|
||||
{
|
||||
texInfoList.RectInfo[index] = new RectInfo
|
||||
{
|
||||
ExternalFilename = texInfoList.RectInfo[index].ExternalFilename,
|
||||
Filename = texInfoList.RectInfo[index].Filename,
|
||||
X = texInfoList.RectInfo[index].X,
|
||||
Y = texInfoList.RectInfo[index].Y,
|
||||
W = (ushort)(texInfoList.RectInfo[index].X + texInfoList.RectInfo[index].W),
|
||||
H = (ushort)(texInfoList.RectInfo[index].Y + texInfoList.RectInfo[index].H),
|
||||
};
|
||||
}
|
||||
|
||||
return texInfoList;
|
||||
}
|
||||
|
||||
static void ParseTexbinFile(string filename, bool splitImages = true)
|
||||
{
|
||||
var outputPath = Path.Combine(Path.GetDirectoryName(filename), Path.GetFileNameWithoutExtension(filename));
|
||||
Directory.CreateDirectory(outputPath);
|
||||
|
||||
using (BinaryReader reader = new BinaryReader(File.Open(filename, FileMode.Open)))
|
||||
{
|
||||
var texpMagic = Encoding.ASCII.GetString(reader.ReadBytes(4));
|
||||
|
||||
if (texpMagic != "PXET")
|
||||
{
|
||||
Console.WriteLine("Not a valid texbin file");
|
||||
Environment.Exit(1);
|
||||
}
|
||||
|
||||
var unk1 = reader.ReadInt32();
|
||||
var unk2 = reader.ReadInt32();
|
||||
var archiveSize = reader.ReadInt32();
|
||||
var unk3 = reader.ReadInt32();
|
||||
var fileCount = reader.ReadInt64();
|
||||
var dataOffset = reader.ReadInt32();
|
||||
var rectOffset = reader.ReadInt32();
|
||||
var unk4 = reader.ReadBytes(0x10);
|
||||
var nameOffset = reader.ReadInt32();
|
||||
var unk5 = reader.ReadInt32();
|
||||
var dataEntryOffset = reader.ReadInt32();
|
||||
|
||||
if (fileCount == 0)
|
||||
{
|
||||
Console.WriteLine("This file doesn't contain any image data.");
|
||||
return;
|
||||
}
|
||||
|
||||
var entries = ReadNameSection(reader, nameOffset);
|
||||
ReadDataEntrySection(reader, dataEntryOffset, fileCount, entries);
|
||||
|
||||
var texInfo = new TexInfo();
|
||||
if (rectOffset != 0)
|
||||
{
|
||||
var rectInfo = ReadRectEntrySection(reader, rectOffset);
|
||||
foreach (var rect in rectInfo)
|
||||
{
|
||||
var e = new RectInfo
|
||||
{
|
||||
ExternalFilename = entries[rect.ImageId].Filename,
|
||||
Filename = rect.Entry.Filename,
|
||||
X = rect.X,
|
||||
Y = rect.Y,
|
||||
W = rect.W,
|
||||
H = rect.H
|
||||
};
|
||||
texInfo.RectInfo.Add(e);
|
||||
}
|
||||
|
||||
// Add code to optionally not split texture files and save a metadata file instead
|
||||
if (!splitImages)
|
||||
{
|
||||
Serialize<TexInfo>(texInfo, Path.Combine(outputPath, "_metadata.xml"));
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var entry in entries)
|
||||
{
|
||||
reader.BaseStream.Seek(entry.DataOffset, SeekOrigin.Begin);
|
||||
|
||||
var data = Decompress(reader);
|
||||
|
||||
if (Encoding.ASCII.GetString(data, 0, 4) == "TXDT"
|
||||
|| Encoding.ASCII.GetString(data, 0, 4) == "TDXT")
|
||||
{
|
||||
var rectInfoList = texInfo.RectInfo.Where(x =>
|
||||
String.CompareOrdinal(Path.GetFileNameWithoutExtension(entry.Filename),
|
||||
x.ExternalFilename) == 0).ToList();
|
||||
|
||||
if (!splitImages)
|
||||
{
|
||||
rectInfoList.Clear();
|
||||
}
|
||||
|
||||
if (rectInfoList.Count == 0)
|
||||
{
|
||||
var rectInfo = new RectInfo
|
||||
{
|
||||
ExternalFilename = entry.Filename,
|
||||
Filename = entry.Filename,
|
||||
X = 0,
|
||||
Y = 0,
|
||||
W = 0,
|
||||
H = 0
|
||||
};
|
||||
rectInfoList.Add(rectInfo);
|
||||
}
|
||||
|
||||
foreach (var rectInfo in rectInfoList)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var stream = new MemoryStream(data))
|
||||
{
|
||||
using (var dataReader = new BinaryReader(stream))
|
||||
{
|
||||
byte[] extractedData;
|
||||
|
||||
|
||||
if (!splitImages || rectInfoList.Count == 0 || rectInfo.W == 0 || rectInfo.H == 0)
|
||||
{
|
||||
extractedData = gitadora_textool.Program.ExtractImageCore(dataReader, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
extractedData = gitadora_textool.Program.ExtractImageCore(dataReader, rectInfo);
|
||||
}
|
||||
|
||||
var ext = ".png";
|
||||
if (extractedData[0] == 'D' && extractedData[1] == 'D' && extractedData[2] == 'S' && extractedData[3] == ' ')
|
||||
{
|
||||
ext = ".dds";
|
||||
}
|
||||
|
||||
var outputFilename = Path.Combine(outputPath, rectInfo.Filename);
|
||||
outputFilename += ext;
|
||||
|
||||
Console.WriteLine("Saving {0}...", outputFilename);
|
||||
|
||||
File.WriteAllBytes(outputFilename, extractedData);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine("Couldn't convert image: {0}", e.Message);
|
||||
File.WriteAllBytes(Path.Combine(outputPath, entry.Filename), data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static List<byte> CreateNameSection(List<string> filelist_unique)
|
||||
{
|
||||
var nameSection = new List<byte>();
|
||||
var filenameSectionSize = 0x1c + (filelist_unique.Count * 0x0c) + filelist_unique.Select(x => x.Length + 1).Sum();
|
||||
if ((filenameSectionSize % 4) != 0)
|
||||
filenameSectionSize += 4 - (filenameSectionSize % 4);
|
||||
|
||||
nameSection.AddRange(new byte[] { 0x50, 0x4D, 0x41, 0x4E });
|
||||
nameSection.AddRange(BitConverter.GetBytes(filenameSectionSize));
|
||||
nameSection.AddRange(new byte[] { 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00 });
|
||||
nameSection.AddRange(BitConverter.GetBytes(filelist_unique.Count));
|
||||
|
||||
ushort a = (ushort)(1 << Convert.ToString(filelist_unique.Count >> 1, 2).Length - 1);
|
||||
ushort b = (ushort)((1 << Convert.ToString(filelist_unique.Count >> 1, 2).Length) - 1);
|
||||
|
||||
nameSection.AddRange(BitConverter.GetBytes(a));
|
||||
nameSection.AddRange(BitConverter.GetBytes(b));
|
||||
nameSection.AddRange(BitConverter.GetBytes(nameSection.Count + 4));
|
||||
|
||||
List<uint> hashes = filelist_unique.Select(x => (uint)CalculateHash(x)).OrderBy(x => x).ToList();
|
||||
string[] filelist_sorted = new string[filelist_unique.Count];
|
||||
|
||||
foreach (var filename in filelist_unique)
|
||||
{
|
||||
filelist_sorted[hashes.IndexOf((uint)CalculateHash(filename))] = filename;
|
||||
}
|
||||
|
||||
int nameBaseOffsetBase = nameSection.Count + (filelist_unique.Count * 0x0c);
|
||||
for (int i = 0; i < filelist_sorted.Length; i++)
|
||||
{
|
||||
var filelist_idx = filelist_unique.IndexOf(filelist_sorted[i]);
|
||||
|
||||
nameSection.AddRange(BitConverter.GetBytes(CalculateHash(filelist_sorted[i])));
|
||||
nameSection.AddRange(BitConverter.GetBytes(filelist_idx));
|
||||
|
||||
var nameBaseOffset = nameBaseOffsetBase;
|
||||
for (int j = 0; j < filelist_idx; j++)
|
||||
{
|
||||
nameBaseOffset += filelist_unique[j].Length + 1;
|
||||
}
|
||||
|
||||
nameSection.AddRange(BitConverter.GetBytes(nameBaseOffset));
|
||||
}
|
||||
|
||||
for (int i = 0; i < filelist_unique.Count; i++)
|
||||
{
|
||||
nameSection.AddRange(Encoding.ASCII.GetBytes(filelist_unique[i]));
|
||||
nameSection.Add(0);
|
||||
}
|
||||
|
||||
while (nameSection.Count < filenameSectionSize)
|
||||
{
|
||||
nameSection.Add(0);
|
||||
}
|
||||
|
||||
return nameSection;
|
||||
}
|
||||
|
||||
static void CreateTexbinFile(string pathname, bool generateRectSection = true)
|
||||
{
|
||||
var filelist = Directory.GetFiles(pathname).Where(x => !x.ToLower().EndsWith("_metadata.xml")).ToArray();
|
||||
var filelist_unique = filelist.Select(Path.GetFileNameWithoutExtension).Distinct().Where(x => !x.ToLower().EndsWith("_metadata.xml")).ToList();
|
||||
filelist_unique = filelist_unique.Select(x => x.ToUpper()).ToList();
|
||||
|
||||
if (filelist_unique.Count != filelist.Length)
|
||||
{
|
||||
Console.WriteLine("Folder has more files than expected. Are there multiple files with the same name (not including extension)?");
|
||||
Environment.Exit(1);
|
||||
}
|
||||
|
||||
var nameSection = CreateNameSection(filelist_unique);
|
||||
|
||||
var dataSection = new List<byte>();
|
||||
var fileinfoSection = new List<byte>();
|
||||
var imageRectInfo = new Dictionary<string, Tuple<ushort, ushort>>();
|
||||
for (int i = 0; i < filelist_unique.Count; i++)
|
||||
{
|
||||
var data = File.ReadAllBytes(filelist[i]);
|
||||
|
||||
Console.WriteLine("Adding {0}...", filelist[i]);
|
||||
|
||||
if (!data.Take(4).SequenceEqual(new byte[] { 0x54, 0x58, 0x44, 0x54 })
|
||||
&& !data.Take(4).SequenceEqual(new byte[] { 0x54, 0x44, 0x58, 0x54 }))
|
||||
{
|
||||
data = gitadora_textool.Program.CreateImageCore(data, true);
|
||||
}
|
||||
|
||||
fileinfoSection.AddRange(BitConverter.GetBytes(0));
|
||||
fileinfoSection.AddRange(BitConverter.GetBytes(data.Length + 0x08));
|
||||
fileinfoSection.AddRange(BitConverter.GetBytes(0x40 + nameSection.Count + (filelist_unique.Count * 0x0c) + dataSection.Count));
|
||||
|
||||
dataSection.AddRange(BitConverter.GetBytes(data.Length).Reverse());
|
||||
dataSection.AddRange(BitConverter.GetBytes(0));
|
||||
dataSection.AddRange(data);
|
||||
|
||||
imageRectInfo[filelist_unique[i]] = new Tuple<ushort, ushort>((ushort)((data[0x11] << 8) | data[0x10]), (ushort)((data[0x13] << 8) | data[0x12]));
|
||||
}
|
||||
|
||||
if ((dataSection.Count % 4) != 0)
|
||||
{
|
||||
var padding = 4 - (dataSection.Count % 4);
|
||||
while (padding > 0)
|
||||
{
|
||||
dataSection.Add(0);
|
||||
padding--;
|
||||
}
|
||||
}
|
||||
|
||||
var rectSection = new List<byte>();
|
||||
if (generateRectSection)
|
||||
{
|
||||
var rectInfo = new TexInfo();
|
||||
|
||||
if (File.Exists(Path.Combine(pathname, "_metadata.xml")))
|
||||
{
|
||||
rectInfo = Deserialize(Path.Combine(pathname, "_metadata.xml"));
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var filename in filelist_unique)
|
||||
{
|
||||
var data = new RectInfo
|
||||
{
|
||||
ExternalFilename = filename,
|
||||
Filename = filename,
|
||||
X = 0,
|
||||
Y = 0,
|
||||
W = imageRectInfo[filename].Item1,
|
||||
H = imageRectInfo[filename].Item2
|
||||
};
|
||||
rectInfo.RectInfo.Add(data);
|
||||
}
|
||||
}
|
||||
|
||||
var rectNameFilelist = rectInfo.RectInfo.Select(x => x.Filename)
|
||||
.Select(Path.GetFileNameWithoutExtension).Distinct()
|
||||
.Where(x => !x.ToLower().EndsWith("_metadata.xml")).ToList();
|
||||
|
||||
var rectinfoSection = new List<byte>();
|
||||
var rectNameSection = CreateNameSection(rectNameFilelist);
|
||||
foreach (var data in rectInfo.RectInfo)
|
||||
{
|
||||
rectinfoSection.AddRange(BitConverter.GetBytes(filelist_unique.IndexOf(Path.GetFileNameWithoutExtension(data.ExternalFilename))));
|
||||
rectinfoSection.AddRange(BitConverter.GetBytes(data.X));
|
||||
rectinfoSection.AddRange(BitConverter.GetBytes(data.W));
|
||||
rectinfoSection.AddRange(BitConverter.GetBytes(data.Y));
|
||||
rectinfoSection.AddRange(BitConverter.GetBytes(data.H));
|
||||
}
|
||||
|
||||
rectSection.AddRange(
|
||||
new byte[] { 0x54, 0x43, 0x45, 0x52, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00 });
|
||||
rectSection.AddRange(BitConverter.GetBytes(0x1c + rectNameSection.Count + rectinfoSection.Count));
|
||||
rectSection.AddRange(BitConverter.GetBytes(rectNameFilelist.Count));
|
||||
rectSection.AddRange(BitConverter.GetBytes(0x1c));
|
||||
rectSection.AddRange(BitConverter.GetBytes(0x1c + rectNameSection.Count));
|
||||
rectSection.AddRange(rectNameSection);
|
||||
rectSection.AddRange(rectinfoSection);
|
||||
}
|
||||
|
||||
var outputData = new List<byte>();
|
||||
outputData.AddRange(new byte[] { 0x50, 0x58, 0x45, 0x54, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00 });
|
||||
outputData.AddRange(BitConverter.GetBytes(0x40 + nameSection.Count + fileinfoSection.Count + dataSection.Count + rectSection.Count)); // Archive size
|
||||
outputData.AddRange(BitConverter.GetBytes(1));
|
||||
outputData.AddRange(BitConverter.GetBytes(filelist_unique.Count));
|
||||
outputData.AddRange(BitConverter.GetBytes(0));
|
||||
outputData.AddRange(BitConverter.GetBytes(0x40 + nameSection.Count + fileinfoSection.Count));
|
||||
outputData.AddRange(BitConverter.GetBytes(rectSection.Count > 0 ? 0x40 + nameSection.Count + fileinfoSection.Count + dataSection.Count : 0));
|
||||
outputData.AddRange(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 });
|
||||
outputData.AddRange(BitConverter.GetBytes(0x40)); // PMAN section offset
|
||||
outputData.AddRange(BitConverter.GetBytes(0));
|
||||
outputData.AddRange(BitConverter.GetBytes(0x40 + nameSection.Count));
|
||||
outputData.AddRange(nameSection);
|
||||
outputData.AddRange(fileinfoSection);
|
||||
outputData.AddRange(dataSection);
|
||||
outputData.AddRange(rectSection);
|
||||
|
||||
var basePath = Path.GetFileName(pathname);
|
||||
if (String.IsNullOrWhiteSpace(basePath))
|
||||
basePath = pathname.Replace(".\\", "").Replace("\\", "");
|
||||
|
||||
var outputFilename = Path.Combine(Path.GetDirectoryName(pathname), String.Format("{0}.bin", basePath));
|
||||
File.WriteAllBytes(outputFilename, outputData.ToArray());
|
||||
}
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
if (args.Length <= 0)
|
||||
{
|
||||
Console.WriteLine("usage: {0} [--no-rect/--nr] [--no-split/--ns] input_filename", AppDomain.CurrentDomain.FriendlyName);
|
||||
Console.WriteLine("--no-rect/--nr: Don't create a rect table (Some games like Jubeat don't use the rect table)");
|
||||
Console.WriteLine("--no-split/--ns: Don't split images into separate images if they use the rect table");
|
||||
Environment.Exit(1);
|
||||
}
|
||||
|
||||
var splitImage = true;
|
||||
var generateRectSection = true;
|
||||
|
||||
var filenames = new List<string>();
|
||||
for (var index = 0; index < args.Length; index++)
|
||||
{
|
||||
if (String.CompareOrdinal(args[index].ToLower(), "--no-rect") == 0
|
||||
|| String.CompareOrdinal(args[index].ToLower(), "--nr") == 0)
|
||||
{
|
||||
generateRectSection = false;
|
||||
}
|
||||
else if (String.CompareOrdinal(args[index].ToLower(), "--no-split") == 0
|
||||
|| String.CompareOrdinal(args[index].ToLower(), "--ns") == 0)
|
||||
{
|
||||
splitImage = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
filenames.Add(args[index]);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var filename in filenames)
|
||||
{
|
||||
if (Directory.Exists(filename))
|
||||
{
|
||||
CreateTexbinFile(filename, generateRectSection);
|
||||
}
|
||||
else if (File.Exists(filename))
|
||||
{
|
||||
ParseTexbinFile(filename, splitImage);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
36
gitadora-texbintool/Properties/AssemblyInfo.cs
Normal file
36
gitadora-texbintool/Properties/AssemblyInfo.cs
Normal file
@ -0,0 +1,36 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("gitadora-texbintool")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("gitadora-texbintool")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2018")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("14f21197-8ff1-4a4f-b976-aaa55378fade")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
58
gitadora-texbintool/gitadora-texbintool.csproj
Normal file
58
gitadora-texbintool/gitadora-texbintool.csproj
Normal file
@ -0,0 +1,58 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{14F21197-8FF1-4A4F-B976-AAA55378FADE}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RootNamespace>gitadora_texbintool</RootNamespace>
|
||||
<AssemblyName>gitadora-texbintool</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>none</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\gitadora-textool\gitadora-textool.csproj">
|
||||
<Project>{8c5cc09a-436c-4caa-9213-31a4f351dbdc}</Project>
|
||||
<Name>gitadora-textool</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
31
gitadora-textool.sln
Normal file
31
gitadora-textool.sln
Normal file
@ -0,0 +1,31 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.27130.2010
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "gitadora-textool", "gitadora-textool\gitadora-textool.csproj", "{8C5CC09A-436C-4CAA-9213-31A4F351DBDC}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "gitadora-texbintool", "gitadora-texbintool\gitadora-texbintool.csproj", "{14F21197-8FF1-4A4F-B976-AAA55378FADE}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{8C5CC09A-436C-4CAA-9213-31A4F351DBDC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8C5CC09A-436C-4CAA-9213-31A4F351DBDC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8C5CC09A-436C-4CAA-9213-31A4F351DBDC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8C5CC09A-436C-4CAA-9213-31A4F351DBDC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{14F21197-8FF1-4A4F-B976-AAA55378FADE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{14F21197-8FF1-4A4F-B976-AAA55378FADE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{14F21197-8FF1-4A4F-B976-AAA55378FADE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{14F21197-8FF1-4A4F-B976-AAA55378FADE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {5EDE6B8F-78F2-46C0-A47E-D3A53277210A}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
6
gitadora-textool/App.config
Normal file
6
gitadora-textool/App.config
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
|
||||
</startup>
|
||||
</configuration>
|
460
gitadora-textool/DxtUtil.cs
Normal file
460
gitadora-textool/DxtUtil.cs
Normal file
@ -0,0 +1,460 @@
|
||||
// #region License
|
||||
// /*
|
||||
// Microsoft Public License (Ms-PL)
|
||||
// MonoGame - Copyright © 2009 The MonoGame Team
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// This license governs use of the accompanying software. If you use the software, you accept this license. If you do not
|
||||
// accept the license, do not use the software.
|
||||
//
|
||||
// 1. Definitions
|
||||
// The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here as under
|
||||
// U.S. copyright law.
|
||||
//
|
||||
// A "contribution" is the original software, or any additions or changes to the software.
|
||||
// A "contributor" is any person that distributes its contribution under this license.
|
||||
// "Licensed patents" are a contributor's patent claims that read directly on its contribution.
|
||||
//
|
||||
// 2. Grant of Rights
|
||||
// (A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3,
|
||||
// each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create.
|
||||
// (B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3,
|
||||
// each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software.
|
||||
//
|
||||
// 3. Conditions and Limitations
|
||||
// (A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks.
|
||||
// (B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software,
|
||||
// your patent license from such contributor to the software ends automatically.
|
||||
// (C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution
|
||||
// notices that are present in the software.
|
||||
// (D) If you distribute any portion of the software in source code form, you may do so only under this license by including
|
||||
// a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object
|
||||
// code form, you may only do so under a license that complies with this license.
|
||||
// (E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees
|
||||
// or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent
|
||||
// permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular
|
||||
// purpose and non-infringement.
|
||||
// */
|
||||
// #endregion License
|
||||
//
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Microsoft.Xna.Framework.Graphics
|
||||
{
|
||||
internal static class DxtUtil
|
||||
{
|
||||
internal static byte[] DecompressDxt1(byte[] imageData, int width, int height)
|
||||
{
|
||||
using (MemoryStream imageStream = new MemoryStream(imageData))
|
||||
return DecompressDxt1(imageStream, width, height);
|
||||
}
|
||||
|
||||
internal static byte[] DecompressDxt1(Stream imageStream, int width, int height)
|
||||
{
|
||||
byte[] imageData = new byte[width * height * 4];
|
||||
|
||||
using (BinaryReader imageReader = new BinaryReader(imageStream))
|
||||
{
|
||||
int blockCountX = (width + 3) / 4;
|
||||
int blockCountY = (height + 3) / 4;
|
||||
|
||||
for (int y = 0; y < blockCountY; y++)
|
||||
{
|
||||
for (int x = 0; x < blockCountX; x++)
|
||||
{
|
||||
DecompressDxt1Block(imageReader, x, y, blockCountX, width, height, imageData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return imageData;
|
||||
}
|
||||
|
||||
private static void DecompressDxt1Block(BinaryReader imageReader, int x, int y, int blockCountX, int width, int height, byte[] imageData)
|
||||
{
|
||||
ushort c0 = imageReader.ReadUInt16();
|
||||
ushort c1 = imageReader.ReadUInt16();
|
||||
|
||||
byte r0, g0, b0;
|
||||
byte r1, g1, b1;
|
||||
ConvertRgb565ToRgb888(c0, out r0, out g0, out b0);
|
||||
ConvertRgb565ToRgb888(c1, out r1, out g1, out b1);
|
||||
|
||||
uint lookupTable = imageReader.ReadUInt32();
|
||||
|
||||
for (int blockY = 0; blockY < 4; blockY++)
|
||||
{
|
||||
for (int blockX = 0; blockX < 4; blockX++)
|
||||
{
|
||||
byte r = 0, g = 0, b = 0, a = 255;
|
||||
uint index = (lookupTable >> 2 * (4 * blockY + blockX)) & 0x03;
|
||||
|
||||
if (c0 > c1)
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0:
|
||||
r = r0;
|
||||
g = g0;
|
||||
b = b0;
|
||||
break;
|
||||
case 1:
|
||||
r = r1;
|
||||
g = g1;
|
||||
b = b1;
|
||||
break;
|
||||
case 2:
|
||||
r = (byte)((2 * r0 + r1) / 3);
|
||||
g = (byte)((2 * g0 + g1) / 3);
|
||||
b = (byte)((2 * b0 + b1) / 3);
|
||||
break;
|
||||
case 3:
|
||||
r = (byte)((r0 + 2 * r1) / 3);
|
||||
g = (byte)((g0 + 2 * g1) / 3);
|
||||
b = (byte)((b0 + 2 * b1) / 3);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0:
|
||||
r = r0;
|
||||
g = g0;
|
||||
b = b0;
|
||||
break;
|
||||
case 1:
|
||||
r = r1;
|
||||
g = g1;
|
||||
b = b1;
|
||||
break;
|
||||
case 2:
|
||||
r = (byte)((r0 + r1) / 2);
|
||||
g = (byte)((g0 + g1) / 2);
|
||||
b = (byte)((b0 + b1) / 2);
|
||||
break;
|
||||
case 3:
|
||||
r = 0;
|
||||
g = 0;
|
||||
b = 0;
|
||||
a = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int px = (x << 2) + blockX;
|
||||
int py = (y << 2) + blockY;
|
||||
if ((px < width) && (py < height))
|
||||
{
|
||||
int offset = ((py * width) + px) << 2;
|
||||
imageData[offset] = r;
|
||||
imageData[offset + 1] = g;
|
||||
imageData[offset + 2] = b;
|
||||
imageData[offset + 3] = a;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static byte[] DecompressDxt3(byte[] imageData, int width, int height)
|
||||
{
|
||||
using (MemoryStream imageStream = new MemoryStream(imageData))
|
||||
return DecompressDxt3(imageStream, width, height);
|
||||
}
|
||||
|
||||
internal static byte[] DecompressDxt3(Stream imageStream, int width, int height)
|
||||
{
|
||||
byte[] imageData = new byte[width * height * 4];
|
||||
|
||||
using (BinaryReader imageReader = new BinaryReader(imageStream))
|
||||
{
|
||||
int blockCountX = (width + 3) / 4;
|
||||
int blockCountY = (height + 3) / 4;
|
||||
|
||||
for (int y = 0; y < blockCountY; y++)
|
||||
{
|
||||
for (int x = 0; x < blockCountX; x++)
|
||||
{
|
||||
DecompressDxt3Block(imageReader, x, y, blockCountX, width, height, imageData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return imageData;
|
||||
}
|
||||
|
||||
private static void DecompressDxt3Block(BinaryReader imageReader, int x, int y, int blockCountX, int width, int height, byte[] imageData)
|
||||
{
|
||||
byte a0 = imageReader.ReadByte();
|
||||
byte a1 = imageReader.ReadByte();
|
||||
byte a2 = imageReader.ReadByte();
|
||||
byte a3 = imageReader.ReadByte();
|
||||
byte a4 = imageReader.ReadByte();
|
||||
byte a5 = imageReader.ReadByte();
|
||||
byte a6 = imageReader.ReadByte();
|
||||
byte a7 = imageReader.ReadByte();
|
||||
|
||||
ushort c0 = imageReader.ReadUInt16();
|
||||
ushort c1 = imageReader.ReadUInt16();
|
||||
|
||||
byte r0, g0, b0;
|
||||
byte r1, g1, b1;
|
||||
ConvertRgb565ToRgb888(c0, out r0, out g0, out b0);
|
||||
ConvertRgb565ToRgb888(c1, out r1, out g1, out b1);
|
||||
|
||||
uint lookupTable = imageReader.ReadUInt32();
|
||||
|
||||
int alphaIndex = 0;
|
||||
for (int blockY = 0; blockY < 4; blockY++)
|
||||
{
|
||||
for (int blockX = 0; blockX < 4; blockX++)
|
||||
{
|
||||
byte r = 0, g = 0, b = 0, a = 0;
|
||||
|
||||
uint index = (lookupTable >> 2 * (4 * blockY + blockX)) & 0x03;
|
||||
|
||||
switch (alphaIndex)
|
||||
{
|
||||
case 0:
|
||||
a = (byte)((a0 & 0x0F) | ((a0 & 0x0F) << 4));
|
||||
break;
|
||||
case 1:
|
||||
a = (byte)((a0 & 0xF0) | ((a0 & 0xF0) >> 4));
|
||||
break;
|
||||
case 2:
|
||||
a = (byte)((a1 & 0x0F) | ((a1 & 0x0F) << 4));
|
||||
break;
|
||||
case 3:
|
||||
a = (byte)((a1 & 0xF0) | ((a1 & 0xF0) >> 4));
|
||||
break;
|
||||
case 4:
|
||||
a = (byte)((a2 & 0x0F) | ((a2 & 0x0F) << 4));
|
||||
break;
|
||||
case 5:
|
||||
a = (byte)((a2 & 0xF0) | ((a2 & 0xF0) >> 4));
|
||||
break;
|
||||
case 6:
|
||||
a = (byte)((a3 & 0x0F) | ((a3 & 0x0F) << 4));
|
||||
break;
|
||||
case 7:
|
||||
a = (byte)((a3 & 0xF0) | ((a3 & 0xF0) >> 4));
|
||||
break;
|
||||
case 8:
|
||||
a = (byte)((a4 & 0x0F) | ((a4 & 0x0F) << 4));
|
||||
break;
|
||||
case 9:
|
||||
a = (byte)((a4 & 0xF0) | ((a4 & 0xF0) >> 4));
|
||||
break;
|
||||
case 10:
|
||||
a = (byte)((a5 & 0x0F) | ((a5 & 0x0F) << 4));
|
||||
break;
|
||||
case 11:
|
||||
a = (byte)((a5 & 0xF0) | ((a5 & 0xF0) >> 4));
|
||||
break;
|
||||
case 12:
|
||||
a = (byte)((a6 & 0x0F) | ((a6 & 0x0F) << 4));
|
||||
break;
|
||||
case 13:
|
||||
a = (byte)((a6 & 0xF0) | ((a6 & 0xF0) >> 4));
|
||||
break;
|
||||
case 14:
|
||||
a = (byte)((a7 & 0x0F) | ((a7 & 0x0F) << 4));
|
||||
break;
|
||||
case 15:
|
||||
a = (byte)((a7 & 0xF0) | ((a7 & 0xF0) >> 4));
|
||||
break;
|
||||
}
|
||||
++alphaIndex;
|
||||
|
||||
switch (index)
|
||||
{
|
||||
case 0:
|
||||
r = r0;
|
||||
g = g0;
|
||||
b = b0;
|
||||
break;
|
||||
case 1:
|
||||
r = r1;
|
||||
g = g1;
|
||||
b = b1;
|
||||
break;
|
||||
case 2:
|
||||
r = (byte)((2 * r0 + r1) / 3);
|
||||
g = (byte)((2 * g0 + g1) / 3);
|
||||
b = (byte)((2 * b0 + b1) / 3);
|
||||
break;
|
||||
case 3:
|
||||
r = (byte)((r0 + 2 * r1) / 3);
|
||||
g = (byte)((g0 + 2 * g1) / 3);
|
||||
b = (byte)((b0 + 2 * b1) / 3);
|
||||
break;
|
||||
}
|
||||
|
||||
int px = (x << 2) + blockX;
|
||||
int py = (y << 2) + blockY;
|
||||
if ((px < width) && (py < height))
|
||||
{
|
||||
int offset = ((py * width) + px) << 2;
|
||||
imageData[offset] = r;
|
||||
imageData[offset + 1] = g;
|
||||
imageData[offset + 2] = b;
|
||||
imageData[offset + 3] = a;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static byte[] DecompressDxt5(byte[] imageData, int width, int height)
|
||||
{
|
||||
using (MemoryStream imageStream = new MemoryStream(imageData))
|
||||
return DecompressDxt5(imageStream, width, height);
|
||||
}
|
||||
|
||||
internal static byte[] DecompressDxt5(Stream imageStream, int width, int height)
|
||||
{
|
||||
byte[] imageData = new byte[width * height * 4];
|
||||
|
||||
using (BinaryReader imageReader = new BinaryReader(imageStream))
|
||||
{
|
||||
int blockCountX = (width + 3) / 4;
|
||||
int blockCountY = (height + 3) / 4;
|
||||
|
||||
for (int y = 0; y < blockCountY; y++)
|
||||
{
|
||||
for (int x = 0; x < blockCountX; x++)
|
||||
{
|
||||
DecompressDxt5Block(imageReader, x, y, blockCountX, width, height, imageData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return imageData;
|
||||
}
|
||||
|
||||
private static void DecompressDxt5Block(BinaryReader imageReader, int x, int y, int blockCountX, int width, int height, byte[] imageData)
|
||||
{
|
||||
byte alpha0 = imageReader.ReadByte();
|
||||
byte alpha1 = imageReader.ReadByte();
|
||||
|
||||
ulong alphaMask = (ulong)imageReader.ReadByte();
|
||||
alphaMask += (ulong)imageReader.ReadByte() << 8;
|
||||
alphaMask += (ulong)imageReader.ReadByte() << 16;
|
||||
alphaMask += (ulong)imageReader.ReadByte() << 24;
|
||||
alphaMask += (ulong)imageReader.ReadByte() << 32;
|
||||
alphaMask += (ulong)imageReader.ReadByte() << 40;
|
||||
|
||||
ushort c0 = imageReader.ReadUInt16();
|
||||
ushort c1 = imageReader.ReadUInt16();
|
||||
|
||||
byte r0, g0, b0;
|
||||
byte r1, g1, b1;
|
||||
ConvertRgb565ToRgb888(c0, out r0, out g0, out b0);
|
||||
ConvertRgb565ToRgb888(c1, out r1, out g1, out b1);
|
||||
|
||||
uint lookupTable = imageReader.ReadUInt32();
|
||||
|
||||
for (int blockY = 0; blockY < 4; blockY++)
|
||||
{
|
||||
for (int blockX = 0; blockX < 4; blockX++)
|
||||
{
|
||||
byte r = 0, g = 0, b = 0, a = 255;
|
||||
uint index = (lookupTable >> 2 * (4 * blockY + blockX)) & 0x03;
|
||||
|
||||
uint alphaIndex = (uint)((alphaMask >> 3 * (4 * blockY + blockX)) & 0x07);
|
||||
if (alphaIndex == 0)
|
||||
{
|
||||
a = alpha0;
|
||||
}
|
||||
else if (alphaIndex == 1)
|
||||
{
|
||||
a = alpha1;
|
||||
}
|
||||
else if (alpha0 > alpha1)
|
||||
{
|
||||
a = (byte)(((8 - alphaIndex) * alpha0 + (alphaIndex - 1) * alpha1) / 7);
|
||||
}
|
||||
else if (alphaIndex == 6)
|
||||
{
|
||||
a = 0;
|
||||
}
|
||||
else if (alphaIndex == 7)
|
||||
{
|
||||
a = 0xff;
|
||||
}
|
||||
else
|
||||
{
|
||||
a = (byte)(((6 - alphaIndex) * alpha0 + (alphaIndex - 1) * alpha1) / 5);
|
||||
}
|
||||
|
||||
switch (index)
|
||||
{
|
||||
case 0:
|
||||
r = r0;
|
||||
g = g0;
|
||||
b = b0;
|
||||
break;
|
||||
case 1:
|
||||
r = r1;
|
||||
g = g1;
|
||||
b = b1;
|
||||
break;
|
||||
case 2:
|
||||
r = (byte)((2 * r0 + r1) / 3);
|
||||
g = (byte)((2 * g0 + g1) / 3);
|
||||
b = (byte)((2 * b0 + b1) / 3);
|
||||
break;
|
||||
case 3:
|
||||
r = (byte)((r0 + 2 * r1) / 3);
|
||||
g = (byte)((g0 + 2 * g1) / 3);
|
||||
b = (byte)((b0 + 2 * b1) / 3);
|
||||
break;
|
||||
}
|
||||
|
||||
int px = (x << 2) + blockX;
|
||||
int py = (y << 2) + blockY;
|
||||
if ((px < width) && (py < height))
|
||||
{
|
||||
int offset = ((py * width) + px) << 2;
|
||||
imageData[offset] = r;
|
||||
imageData[offset + 1] = g;
|
||||
imageData[offset + 2] = b;
|
||||
imageData[offset + 3] = a;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void ConvertRgb565ToRgb888(ushort color, out byte r, out byte g, out byte b)
|
||||
{
|
||||
int temp;
|
||||
|
||||
temp = (color >> 11) * 255 + 16;
|
||||
r = (byte)((temp / 32 + temp) / 32);
|
||||
temp = ((color & 0x07E0) >> 5) * 255 + 32;
|
||||
g = (byte)((temp / 64 + temp) / 64);
|
||||
temp = (color & 0x001F) * 255 + 16;
|
||||
b = (byte)((temp / 32 + temp) / 32);
|
||||
}
|
||||
|
||||
public static void ConvertArgb4444ToArgb8888(ushort color, out byte a, out byte r, out byte g, out byte b)
|
||||
{
|
||||
int temp;
|
||||
|
||||
temp = (color & 0xf000) >> 12;
|
||||
a = (byte)(temp * 16 + temp);
|
||||
|
||||
temp = (color & 0x0f00) >> 8;
|
||||
r = (byte)(temp * 16 + temp);
|
||||
|
||||
temp = (color & 0x00f0) >> 4;
|
||||
g = (byte)(temp * 16 + temp);
|
||||
|
||||
temp = color & 0x000f;
|
||||
b = (byte)(temp * 16 + temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
530
gitadora-textool/Program.cs
Normal file
530
gitadora-textool/Program.cs
Normal file
@ -0,0 +1,530 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.IO;
|
||||
using System.Linq.Expressions;
|
||||
using System.Runtime.InteropServices;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace gitadora_textool
|
||||
{
|
||||
public struct RectInfo
|
||||
{
|
||||
public string ExternalFilename;
|
||||
public string Filename;
|
||||
public ushort X;
|
||||
public ushort Y;
|
||||
public ushort W;
|
||||
public ushort H;
|
||||
}
|
||||
|
||||
public class Program
|
||||
{
|
||||
static int ReadInt32(BinaryReader reader, bool endianness = false)
|
||||
{
|
||||
var data = reader.ReadBytes(4);
|
||||
if (!endianness)
|
||||
Array.Reverse(data);
|
||||
return BitConverter.ToInt32(data, 0);
|
||||
}
|
||||
|
||||
static int ReadInt16(BinaryReader reader, bool endianness = false)
|
||||
{
|
||||
var data = reader.ReadBytes(2);
|
||||
if (!endianness)
|
||||
Array.Reverse(data);
|
||||
return BitConverter.ToInt16(data, 0);
|
||||
}
|
||||
|
||||
static void WriteInt32(BinaryWriter writer, uint input, bool endianness = false)
|
||||
{
|
||||
var data = BitConverter.GetBytes(input);
|
||||
if (!endianness)
|
||||
Array.Reverse(data);
|
||||
writer.Write(data);
|
||||
}
|
||||
|
||||
static void WriteInt16(BinaryWriter writer, ushort input, bool endianness = false)
|
||||
{
|
||||
var data = BitConverter.GetBytes(input);
|
||||
if (!endianness)
|
||||
Array.Reverse(data);
|
||||
writer.Write(data);
|
||||
}
|
||||
|
||||
|
||||
public static byte[] ExtractImageCore(BinaryReader reader, RectInfo? rectInfoList = null)
|
||||
{
|
||||
|
||||
var magic = Encoding.ASCII.GetString(reader.ReadBytes(4));
|
||||
var endianCheck1 = reader.ReadInt32();
|
||||
var endianCheck2 = reader.ReadInt32();
|
||||
var requiresEndianFix = endianCheck2 == 0x00010100;
|
||||
|
||||
reader.BaseStream.Seek(0x0c, SeekOrigin.Begin);
|
||||
|
||||
var dataSize = ReadInt32(reader, requiresEndianFix) - 0x40;
|
||||
var width = ReadInt16(reader, requiresEndianFix);
|
||||
var height = ReadInt16(reader, requiresEndianFix);
|
||||
|
||||
if (!requiresEndianFix)
|
||||
reader.BaseStream.Seek(0x03, SeekOrigin.Current);
|
||||
|
||||
|
||||
/*
|
||||
GRAYSCALE_FORMAT 0x01
|
||||
GRAYSCALE_FORMAT_2 0x06
|
||||
BGR_16BIT_FORMAT 0x0C
|
||||
BGRA_16BIT_FORMAT 0x0D
|
||||
BGR_FORMAT 0x0E
|
||||
BGRA_FORMAT 0x10
|
||||
BGR_8BIT_FORMAT 0x12
|
||||
DXT1_FORMAT 0x16
|
||||
DXT3_FORMAT 0x18
|
||||
DXT5_FORMAT 0x1A
|
||||
*/
|
||||
|
||||
var dataFormat = reader.ReadByte();
|
||||
|
||||
reader.BaseStream.Seek(0x40, SeekOrigin.Begin);
|
||||
var bitmapData = reader.ReadBytes(dataSize);
|
||||
|
||||
var pixelFormat = PixelFormat.Undefined;
|
||||
if (dataFormat == 0x01)
|
||||
{
|
||||
// GRAYSCALE_FORMAT8
|
||||
pixelFormat = PixelFormat.Format8bppIndexed;
|
||||
}
|
||||
else if (dataFormat == 0x06)
|
||||
{
|
||||
// GRAYSCALE_FORMAT_2
|
||||
pixelFormat = PixelFormat.Format8bppIndexed;
|
||||
}
|
||||
else if (dataFormat == 0x0c)
|
||||
{
|
||||
// BGR_16BIT_FORMAT
|
||||
pixelFormat = PixelFormat.Format16bppRgb565;
|
||||
}
|
||||
else if (dataFormat == 0x0d)
|
||||
{
|
||||
// BGRA_16BIT_FORMAT
|
||||
byte[] newBitmapData = new byte[width * height * 4];
|
||||
for (int didx = 0, i = 0; i < height; i++)
|
||||
{
|
||||
for (var j = 0; j < width; j++, didx += 2)
|
||||
{
|
||||
ushort c = (ushort)((bitmapData[didx + 1] << 8) | bitmapData[didx]);
|
||||
|
||||
DxtUtil.ConvertArgb4444ToArgb8888(c, out var a, out var r, out var g, out var b);
|
||||
|
||||
newBitmapData[(j * 4) + (i * width * 4)] = a;
|
||||
newBitmapData[(j * 4) + 1 + (i * width * 4)] = r;
|
||||
newBitmapData[(j * 4) + 2 + (i * width * 4)] = g;
|
||||
newBitmapData[(j * 4) + 3 + (i * width * 4)] = b;
|
||||
}
|
||||
}
|
||||
|
||||
bitmapData = newBitmapData;
|
||||
|
||||
pixelFormat = PixelFormat.Format32bppArgb;
|
||||
}
|
||||
else if (dataFormat == 0x0e)
|
||||
{
|
||||
// BGR_FORMAT
|
||||
pixelFormat = PixelFormat.Format24bppRgb;
|
||||
}
|
||||
else if (dataFormat == 0x10)
|
||||
{
|
||||
// BGRA_FORMAT
|
||||
pixelFormat = PixelFormat.Format32bppArgb;
|
||||
}
|
||||
else if (dataFormat == 0x12)
|
||||
{
|
||||
// BGR_8BIT_FORMAT
|
||||
throw new Exception("Found BGR_8BIT_FORMAT");
|
||||
}
|
||||
else if (dataFormat == 0x16)
|
||||
{
|
||||
// DXT1_FORMAT
|
||||
pixelFormat = PixelFormat.Format32bppArgb;
|
||||
bitmapData = DxtUtil.DecompressDxt1(bitmapData, width, height);
|
||||
}
|
||||
else if (dataFormat == 0x18)
|
||||
{
|
||||
// DXT3_FORMAT
|
||||
pixelFormat = PixelFormat.Format32bppArgb;
|
||||
bitmapData = DxtUtil.DecompressDxt3(bitmapData, width, height);
|
||||
}
|
||||
else if (dataFormat == 0x1a)
|
||||
{
|
||||
// DXT5_FORMAT
|
||||
pixelFormat = PixelFormat.Format32bppArgb;
|
||||
bitmapData = DxtUtil.DecompressDxt5(bitmapData, width, height);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Found unknown pixel format");
|
||||
}
|
||||
|
||||
for (int i = 0; i < bitmapData.Length;)
|
||||
{
|
||||
if (pixelFormat == PixelFormat.Format16bppArgb1555)
|
||||
{
|
||||
var a = bitmapData[i] & 0x0f;
|
||||
var r = (bitmapData[i] >> 4) & 0x0f;
|
||||
var g = bitmapData[i + 1] & 0x0f;
|
||||
var b = (bitmapData[i + 1] >> 4) & 0x0f;
|
||||
|
||||
bitmapData[i + 1] = (byte)((a << 4) | b);
|
||||
bitmapData[i + 0] = (byte)((g << 4) | r);
|
||||
|
||||
i += 2;
|
||||
}
|
||||
else if (pixelFormat == PixelFormat.Format16bppRgb565)
|
||||
{
|
||||
bitmapData[i] = (byte)((bitmapData[i] & 0xc0) | (bitmapData[i] & 0x3f) >> 1);
|
||||
i += 2;
|
||||
}
|
||||
else if (pixelFormat == PixelFormat.Format24bppRgb)
|
||||
{
|
||||
var t = bitmapData[i + 2];
|
||||
bitmapData[i + 2] = bitmapData[i];
|
||||
bitmapData[i] = t;
|
||||
i += 3;
|
||||
}
|
||||
else if (pixelFormat == PixelFormat.Format32bppArgb)
|
||||
{
|
||||
var t = bitmapData[i + 2];
|
||||
bitmapData[i + 2] = bitmapData[i];
|
||||
bitmapData[i] = t;
|
||||
i += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pixelFormat == PixelFormat.Undefined
|
||||
|| pixelFormat == PixelFormat.Format16bppArgb1555)
|
||||
{
|
||||
// Create DDS file
|
||||
var output = new List<byte>();
|
||||
|
||||
output.AddRange(new byte[]
|
||||
{
|
||||
0x44, 0x44, 0x53, 0x20, 0x7C, 0x00, 0x00, 0x00, 0x07, 0x10, 0x08, 0x00
|
||||
});
|
||||
|
||||
output.AddRange(BitConverter.GetBytes(height));
|
||||
output.AddRange(BitConverter.GetBytes(width));
|
||||
output.AddRange(BitConverter.GetBytes(dataSize));
|
||||
|
||||
output.AddRange(new byte[]
|
||||
{
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00
|
||||
});
|
||||
|
||||
if (pixelFormat == PixelFormat.Format16bppArgb1555)
|
||||
{
|
||||
output.AddRange(new byte[]
|
||||
{
|
||||
0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00,
|
||||
0xF0, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
});
|
||||
}
|
||||
else if (pixelFormat == PixelFormat.Format16bppRgb555)
|
||||
{
|
||||
output.AddRange(new byte[]
|
||||
{
|
||||
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00,
|
||||
0xE0, 0x07, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
output.AddRange(new byte[]
|
||||
{
|
||||
0x04, 0x00, 0x00, 0x00
|
||||
});
|
||||
|
||||
if (dataFormat == 0x16)
|
||||
{
|
||||
output.AddRange(Encoding.ASCII.GetBytes("DXT1"));
|
||||
}
|
||||
else if (dataFormat == 0x18)
|
||||
{
|
||||
output.AddRange(Encoding.ASCII.GetBytes("DXT3"));
|
||||
}
|
||||
else if (dataFormat == 0x1a)
|
||||
{
|
||||
output.AddRange(Encoding.ASCII.GetBytes("DXT5"));
|
||||
}
|
||||
|
||||
output.AddRange(new byte[]
|
||||
{
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
});
|
||||
}
|
||||
|
||||
output.AddRange(bitmapData);
|
||||
|
||||
return output.ToArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
var b = new Bitmap(width, height, pixelFormat);
|
||||
|
||||
if (pixelFormat == PixelFormat.Format8bppIndexed)
|
||||
{
|
||||
ColorPalette palette = b.Palette;
|
||||
Color[] entries = palette.Entries;
|
||||
for (int i = 0; i < 256; i++)
|
||||
{
|
||||
Color c = Color.FromArgb((byte)i, (byte)i, (byte)i);
|
||||
entries[i] = c;
|
||||
}
|
||||
b.Palette = palette;
|
||||
}
|
||||
|
||||
var boundsRect = new Rectangle(0, 0, width, height);
|
||||
BitmapData bmpData = b.LockBits(boundsRect,
|
||||
ImageLockMode.WriteOnly,
|
||||
b.PixelFormat);
|
||||
|
||||
IntPtr ptr = bmpData.Scan0;
|
||||
|
||||
if (pixelFormat != PixelFormat.Format24bppRgb)
|
||||
{
|
||||
int bytes = bmpData.Stride * b.Height;
|
||||
Marshal.Copy(bitmapData, 0, ptr, bytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Because things are stupid, we have to pad the lines for 24bit images ourself...
|
||||
for (int i = 0; i < height; i++)
|
||||
{
|
||||
Marshal.Copy(bitmapData, i * width * 3, ptr + (bmpData.Stride * i), width * 3);
|
||||
}
|
||||
}
|
||||
|
||||
b.UnlockBits(bmpData);
|
||||
|
||||
// Split into separate smaller bitmap
|
||||
if (rectInfoList != null)
|
||||
{
|
||||
var rect = new Rectangle(rectInfoList.Value.X, rectInfoList.Value.Y, rectInfoList.Value.W, rectInfoList.Value.H);
|
||||
Bitmap subimage = new Bitmap(rect.Width, rect.Height);
|
||||
|
||||
Console.WriteLine(rect);
|
||||
|
||||
using (Graphics g = Graphics.FromImage(subimage))
|
||||
{
|
||||
g.DrawImage(b, new Rectangle(0, 0, subimage.Width, subimage.Height), rect, GraphicsUnit.Pixel);
|
||||
}
|
||||
|
||||
b = subimage;
|
||||
}
|
||||
|
||||
ImageConverter converter = new ImageConverter();
|
||||
return (byte[])converter.ConvertTo(b, typeof(byte[]));
|
||||
}
|
||||
}
|
||||
|
||||
static void ExtractImage(string filename)
|
||||
{
|
||||
using (BinaryReader reader = new BinaryReader(File.Open(filename, FileMode.Open)))
|
||||
{
|
||||
var data = ExtractImageCore(reader);
|
||||
|
||||
var ext = "png";
|
||||
if (data[0] == 'D' && data[1] == 'D' && data[2] == 'S' && data[3] == ' ')
|
||||
{
|
||||
ext = "dds";
|
||||
}
|
||||
|
||||
string outputFilename = String.Format("{0}.{1}", Path.Combine(Path.GetDirectoryName(filename), Path.GetFileNameWithoutExtension(filename)), ext);
|
||||
Console.WriteLine(outputFilename);
|
||||
File.WriteAllBytes(outputFilename, data);
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] CreateImageCore(byte[] data, bool requiresEndianFix = false)
|
||||
{
|
||||
var image = Bitmap.FromStream(new MemoryStream(data));
|
||||
var bmpOrig = new Bitmap(image);
|
||||
|
||||
var pixelFormat = image.PixelFormat;
|
||||
|
||||
if (pixelFormat == PixelFormat.Format8bppIndexed)
|
||||
{
|
||||
pixelFormat = PixelFormat.Format32bppArgb;
|
||||
}
|
||||
|
||||
var bmp = new Bitmap(bmpOrig.Width, bmpOrig.Height, pixelFormat);
|
||||
using (Graphics gr = Graphics.FromImage(bmp))
|
||||
{
|
||||
gr.DrawImage(bmpOrig, new Rectangle(0, 0, bmp.Width, bmp.Height));
|
||||
}
|
||||
|
||||
var bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly,
|
||||
pixelFormat);
|
||||
|
||||
IntPtr ptr = bmpData.Scan0;
|
||||
int bytes = Math.Abs(bmpData.Stride) * bmp.Height;
|
||||
byte[] rawData = new byte[bytes];
|
||||
|
||||
Marshal.Copy(ptr, rawData, 0, bytes);
|
||||
|
||||
bmp.UnlockBits(bmpData);
|
||||
|
||||
var stream = new MemoryStream();
|
||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
||||
{
|
||||
Func<byte[], bool> writeBytes = delegate (byte[] inputData)
|
||||
{
|
||||
writer.Write(requiresEndianFix ? inputData.Reverse().ToArray() : inputData);
|
||||
return true;
|
||||
};
|
||||
|
||||
writeBytes(new byte[] { 0x54, 0x58, 0x44, 0x54 });
|
||||
if (requiresEndianFix)
|
||||
{
|
||||
writeBytes(new byte[] { 0x00, 0x01, 0x00, 0x00 });
|
||||
writeBytes(new byte[] { 0x00, 0x01, 0x01, 0x00 });
|
||||
}
|
||||
else
|
||||
{
|
||||
writeBytes(new byte[] { 0x00, 0x01, 0x02, 0x00 });
|
||||
writeBytes(new byte[] { 0x00, 0x01, 0x02, 0x00 });
|
||||
}
|
||||
|
||||
WriteInt32(writer, (uint)(rawData.Length + 0x40), requiresEndianFix);
|
||||
WriteInt16(writer, (ushort)(bmp.Width), requiresEndianFix);
|
||||
WriteInt16(writer, (ushort)(bmp.Height), requiresEndianFix);
|
||||
|
||||
if (bmp.PixelFormat == PixelFormat.Format24bppRgb)
|
||||
{
|
||||
if (requiresEndianFix)
|
||||
{
|
||||
writeBytes(new byte[] { 0x11, 0x22, 0x10, 0x0E });
|
||||
}
|
||||
else
|
||||
{
|
||||
writeBytes(new byte[] { 0x11, 0x11, 0x10, 0x0E });
|
||||
}
|
||||
}
|
||||
else if (bmp.PixelFormat == PixelFormat.Format32bppArgb)
|
||||
{
|
||||
if (requiresEndianFix)
|
||||
{
|
||||
writeBytes(new byte[] { 0x11, 0x22, 0x10, 0x10 });
|
||||
}
|
||||
else
|
||||
{
|
||||
writeBytes(new byte[] { 0x11, 0x11, 0x10, 0x10 });
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Expected 24bit or 32bit image. Don't know how to handle pixel format {0}", bmp.PixelFormat);
|
||||
Environment.Exit(1);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 0x14; i++)
|
||||
{
|
||||
writer.Write((byte)0x00);
|
||||
}
|
||||
|
||||
if (bmp.PixelFormat == PixelFormat.Format24bppRgb)
|
||||
{
|
||||
WriteInt32(writer, 0x01, requiresEndianFix);
|
||||
}
|
||||
else if (bmp.PixelFormat == PixelFormat.Format32bppArgb)
|
||||
{
|
||||
WriteInt32(writer, 0x03, requiresEndianFix);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 0x10; i++)
|
||||
{
|
||||
writer.Write((byte)0x00);
|
||||
}
|
||||
|
||||
var bpp = bmp.PixelFormat == PixelFormat.Format32bppArgb ? 4 : 3;
|
||||
for (int i = 0; i < rawData.Length; i += bpp)
|
||||
{
|
||||
var t = rawData[i];
|
||||
rawData[i] = rawData[i + 2];
|
||||
rawData[i + 2] = t;
|
||||
}
|
||||
|
||||
writer.Write(rawData);
|
||||
}
|
||||
|
||||
var outputData = stream.GetBuffer();
|
||||
Array.Resize(ref outputData, bytes + 0x40);
|
||||
return outputData;
|
||||
}
|
||||
|
||||
static void CreateImage(string filename)
|
||||
{
|
||||
string outputFilename = String.Format("{0}.tex", Path.Combine(Path.GetDirectoryName(filename), Path.GetFileNameWithoutExtension(filename)));
|
||||
Console.WriteLine(outputFilename);
|
||||
|
||||
var rawData = File.ReadAllBytes(filename);
|
||||
var data = CreateImageCore(rawData, false);
|
||||
File.WriteAllBytes(outputFilename, data);
|
||||
}
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
if (args.Length < 1)
|
||||
{
|
||||
Console.WriteLine("usage: {0} input_filename", AppDomain.CurrentDomain.FriendlyName);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var filename in args)
|
||||
{
|
||||
var isExtract = false;
|
||||
using (BinaryReader reader = new BinaryReader(File.Open(filename, FileMode.Open)))
|
||||
{
|
||||
var magic = reader.ReadBytes(4);
|
||||
if (magic.SequenceEqual(new byte[] { 0x54, 0x58, 0x44, 0x54 })
|
||||
|| magic.SequenceEqual(new byte[] { 0x54, 0x44, 0x58, 0x54 }))
|
||||
{
|
||||
isExtract = true;
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (isExtract)
|
||||
{
|
||||
ExtractImage(filename);
|
||||
}
|
||||
else
|
||||
{
|
||||
CreateImage(filename);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine("Error occurred: {0}", e.Message);
|
||||
Environment.Exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
36
gitadora-textool/Properties/AssemblyInfo.cs
Normal file
36
gitadora-textool/Properties/AssemblyInfo.cs
Normal file
@ -0,0 +1,36 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("gitadora-textool")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("gitadora-textool")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2018")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("8c5cc09a-436c-4caa-9213-31a4f351dbdc")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
55
gitadora-textool/gitadora-textool.csproj
Normal file
55
gitadora-textool/gitadora-textool.csproj
Normal file
@ -0,0 +1,55 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{8C5CC09A-436C-4CAA-9213-31A4F351DBDC}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RootNamespace>gitadora_textool</RootNamespace>
|
||||
<AssemblyName>gitadora-textool</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>none</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="DxtUtil.cs" />
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
Loading…
Reference in New Issue
Block a user