386 lines
14 KiB
C#
386 lines
14 KiB
C#
using System;
|
|
using System.Windows.Forms;
|
|
using System.IO.Compression;
|
|
using System.IO;
|
|
using System.Drawing;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using TGASharpLib;
|
|
using System.Text;
|
|
|
|
namespace GiantsMapTextureChanger
|
|
{
|
|
public partial class ChangeTextureForm : Form
|
|
{
|
|
public ChangeTextureForm()
|
|
{
|
|
InitializeComponent();
|
|
}
|
|
|
|
public string map_filename { get; private set; }
|
|
public string giantsPath { get; private set; }
|
|
public Dictionary<string, Image> all_textures { get; private set; }
|
|
public Dictionary<string, Image> map_textures { get; private set; }
|
|
|
|
private void ChangeTextureForm_Load(object sender, EventArgs e)
|
|
{
|
|
}
|
|
private Dictionary<string, Image> ReadAllTextures()
|
|
{
|
|
Dictionary<string, Image> all = new Dictionary<string, Image>();
|
|
|
|
string bin_path = Path.GetDirectoryName(this.giantsPath) + "\\Bin";
|
|
var all_files_in_bin = Directory.EnumerateFiles(bin_path);
|
|
// MessageBox.Show(all_files_in_bin.Count() + " files in Bin");
|
|
foreach (string currentFile in all_files_in_bin)
|
|
{
|
|
if (currentFile.EndsWith(".gzp"))
|
|
{
|
|
// it's a .gzp
|
|
toolStripStatusLabel1.Text = "Reading file " + currentFile;
|
|
Application.DoEvents();
|
|
Dictionary<string, Image> textures_in_gzp = ReadTexturesInGzp(currentFile);
|
|
textures_in_gzp.ToList().ForEach(x => {
|
|
if (!all.ContainsKey(x.Key))
|
|
{
|
|
all.Add(x.Key, x.Value);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
return all;
|
|
}
|
|
private Dictionary<string, Image> ReadTexturesInGzp(string gzp_file)
|
|
{
|
|
Dictionary<string, Image> all = new Dictionary<string, Image>();
|
|
|
|
using (BinaryReader reader = new BinaryReader(File.Open(gzp_file, FileMode.Open)))
|
|
{
|
|
int checksum = BitConverter.ToInt32(reader.ReadBytes(4), 0);
|
|
if (checksum != 0x6608F101)
|
|
{
|
|
throw new Exception("GZP checksum invalid: " + checksum);
|
|
}
|
|
|
|
int meta_info_offset = BitConverter.ToInt32(reader.ReadBytes(4), 0);
|
|
reader.BaseStream.Seek(meta_info_offset, SeekOrigin.Begin);
|
|
|
|
int unk = BitConverter.ToInt32(reader.ReadBytes(4), 0);
|
|
int entries_count = BitConverter.ToInt32(reader.ReadBytes(4), 0);
|
|
|
|
// MessageBox.Show(entries_count + " files in " + gzp_file);
|
|
|
|
for (int i=0; i<entries_count; i++)
|
|
{
|
|
int compressed_size = BitConverter.ToInt32(reader.ReadBytes(4), 0);
|
|
int original_size = BitConverter.ToInt32(reader.ReadBytes(4), 0);
|
|
int file_time = BitConverter.ToInt32(reader.ReadBytes(4), 0);
|
|
int content_offset = BitConverter.ToInt32(reader.ReadBytes(4), 0) + 16;
|
|
byte compression = reader.ReadBytes(1)[0];
|
|
byte name_length = reader.ReadBytes(1)[0];
|
|
string name = Encoding.UTF8.GetString(reader.ReadBytes(name_length)).Trim().Replace("\0", "");
|
|
// MessageBox.Show(name);
|
|
|
|
if (name.EndsWith(".tga"))
|
|
{
|
|
// MessageBox.Show("TGA file found: " + name);
|
|
long current_offset = reader.BaseStream.Position;
|
|
reader.BaseStream.Seek(content_offset, SeekOrigin.Begin);
|
|
byte[] tgaData = reader.ReadBytes(compressed_size);
|
|
reader.BaseStream.Seek(current_offset, SeekOrigin.Begin);
|
|
|
|
if (compression == 1)
|
|
{
|
|
tgaData = DecompressBytes(tgaData, original_size);
|
|
}
|
|
|
|
Image img = TGAToImage(tgaData);
|
|
all.Add(name, img);
|
|
}
|
|
|
|
}
|
|
}
|
|
return all;
|
|
}
|
|
|
|
private Dictionary<string, Image> ReadMapTextures(string map_file)
|
|
{
|
|
Dictionary<string, Image> res = new Dictionary<string, Image>();
|
|
|
|
// read all files in gck file
|
|
ZipArchive zip = ZipFile.OpenRead(map_file);
|
|
foreach (ZipArchiveEntry file in zip.Entries)
|
|
{
|
|
if(file.Name.EndsWith(".tga"))
|
|
{
|
|
Stream rs = file.Open();
|
|
byte[] tgaData = new byte[file.Length];
|
|
rs.Read(tgaData, 0, (int)file.Length);
|
|
TGA t = TGA.FromBytes(tgaData);
|
|
|
|
Image img = (Image)t;
|
|
res.Add(file.Name, img);
|
|
rs.Close();
|
|
}
|
|
}
|
|
|
|
zip.Dispose();
|
|
|
|
return res;
|
|
}
|
|
|
|
private byte[] DecompressBytes(byte[] compressed_bytes, int original_size)
|
|
{
|
|
int i = 0;
|
|
int j = 0;
|
|
int dec_byte = 0;
|
|
int dec_bits = 8;
|
|
int buff_start = 0xFEE;
|
|
|
|
byte[] res = new byte[original_size];
|
|
|
|
if (original_size == 0)
|
|
{
|
|
return res;
|
|
}
|
|
|
|
while (j < original_size)
|
|
{
|
|
if (dec_bits == 8)
|
|
{
|
|
dec_byte = compressed_bytes[i];
|
|
i++;
|
|
dec_bits = 0;
|
|
}
|
|
if ((dec_byte >> dec_bits & 1) == 0)
|
|
{
|
|
int dec_pos = ((compressed_bytes[i] + ((compressed_bytes[i + 1] & 0xF0) << 4) - buff_start - j) & 0xFFF) - 0x1000 + j;
|
|
int dec_len = (compressed_bytes[i + 1] & 0xF) + 3;
|
|
i += 2;
|
|
while (dec_len > 0)
|
|
{
|
|
if (dec_pos >= 0)
|
|
{
|
|
res[j] = res[dec_pos];
|
|
} else
|
|
{
|
|
res[j] = 32;
|
|
}
|
|
j++;
|
|
dec_pos++;
|
|
dec_len--;
|
|
}
|
|
} else
|
|
{
|
|
res[j] = compressed_bytes[i];
|
|
i++;
|
|
j++;
|
|
}
|
|
dec_bits++;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
private Image TGAToImage(byte[] data)
|
|
{
|
|
TGA tga = TGA.FromBytes(data);
|
|
return (Image)tga;
|
|
}
|
|
|
|
private void textureList_SelectedIndexChanged(object sender, EventArgs e)
|
|
{
|
|
// texturesinmapList.SelectedIndex = -1;
|
|
string selected = textureList.Text;
|
|
if (this.all_textures.ContainsKey(selected)) {
|
|
ThumbImage.Image = this.all_textures[selected];
|
|
ThumbImage.Tag = selected;
|
|
toolStripStatusLabel1.Text = selected + ": " + this.all_textures[selected].Width + "x" + this.all_textures[selected].Height;
|
|
}
|
|
}
|
|
|
|
private void exportButton_Click(object sender, EventArgs e)
|
|
{
|
|
saveTextureDialog.FileName = (string)ThumbImage.Tag;
|
|
saveTextureDialog.ShowDialog();
|
|
// If the file name is not an empty string open it for saving.
|
|
if (saveTextureDialog.FileName != "")
|
|
{
|
|
// Saves the Image via a FileStream created by the OpenFile method.
|
|
System.IO.FileStream fs = (System.IO.FileStream)saveTextureDialog.OpenFile();
|
|
|
|
TGA t = (TGA)ThumbImage.Image;
|
|
t.Save(fs);
|
|
fs.Close();
|
|
toolStripStatusLabel1.Text = "Saved texture to "+ saveTextureDialog.FileName;
|
|
}
|
|
else
|
|
{
|
|
toolStripStatusLabel1.Text = "Error: you did not choose a file to save texture";
|
|
}
|
|
}
|
|
|
|
private void texturesinmapList_SelectedIndexChanged(object sender, EventArgs e)
|
|
{
|
|
// textureList.SelectedIndex = -1;
|
|
string selected = texturesinmapList.Text;
|
|
if (this.map_textures.ContainsKey(selected))
|
|
{
|
|
ThumbImage.Image = this.map_textures[selected];
|
|
ThumbImage.Tag = selected;
|
|
toolStripStatusLabel1.Text = selected + ": " + this.map_textures[selected].Width + "x" + this.map_textures[selected].Height;
|
|
}
|
|
}
|
|
|
|
private void button2_Click(object sender, EventArgs e)
|
|
{
|
|
string selected = texturesinmapList.Text;
|
|
texturesinmapList.Items.Remove(selected);
|
|
map_textures.Remove(selected);
|
|
}
|
|
|
|
private void button1_Click(object sender, EventArgs e)
|
|
{
|
|
textureAddDialog.ShowDialog();
|
|
if (textureAddDialog.FileName != "")
|
|
{
|
|
Image img = (Image)new TGA(textureAddDialog.FileName);
|
|
string name = Path.GetFileName(textureAddDialog.FileName);
|
|
map_textures.Add(name, img);
|
|
texturesinmapList.Items.Add(name);
|
|
}
|
|
}
|
|
|
|
private void button3_Click(object sender, EventArgs e)
|
|
{
|
|
saveMapDialog.ShowDialog();
|
|
toolStripStatusLabel1.Text = "Saving map to: " + saveMapDialog.FileName;
|
|
if (saveMapDialog.FileName != "")
|
|
{
|
|
if (this.map_filename != saveMapDialog.FileName) {
|
|
File.Copy(this.map_filename, saveMapDialog.FileName, true);
|
|
}
|
|
ZipArchive map = ZipFile.Open(saveMapDialog.FileName, ZipArchiveMode.Update);
|
|
for(int i = map.Entries.Count-1;i>=0;i--)
|
|
{
|
|
ZipArchiveEntry entry = map.Entries[i];
|
|
if (entry.Name.EndsWith(".tga"))
|
|
{
|
|
entry.Delete();
|
|
}
|
|
}
|
|
|
|
foreach(string texture_name in this.map_textures.Keys)
|
|
{
|
|
TGA texture = (TGA)map_textures[texture_name];
|
|
|
|
ZipArchiveEntry newentry = map.CreateEntry(texture_name);
|
|
using (StreamWriter writer = new StreamWriter(newentry.Open()))
|
|
{
|
|
texture.Save(writer.BaseStream);
|
|
}
|
|
}
|
|
toolStripStatusLabel1.Text = "Saved map to: " + Path.GetFileName(saveMapDialog.FileName);
|
|
map.Dispose();
|
|
}
|
|
}
|
|
|
|
private void ChangeTextureForm_Shown(object sender, EventArgs e)
|
|
{
|
|
// Get Giants.exe location
|
|
object install_dir = Microsoft.Win32.Registry.GetValue(@"HKEY_CURRENT_USER\Software\PlanetMoon\Giants", "DestDir", "");
|
|
if (install_dir != null) {
|
|
this.giantsPath = install_dir.ToString();
|
|
this.giantsPath += "\\Giants.exe";
|
|
}
|
|
if (this.giantsPath == null || !File.Exists(this.giantsPath))
|
|
{
|
|
if (gameFileDialog.ShowDialog() != DialogResult.OK)
|
|
{
|
|
Application.Exit();
|
|
return;
|
|
}
|
|
this.giantsPath = gameFileDialog.FileName;
|
|
}
|
|
|
|
// Get map location
|
|
if (mapFileDialog.ShowDialog() != DialogResult.OK)
|
|
{
|
|
Application.Exit();
|
|
return;
|
|
}
|
|
|
|
this.map_filename = mapFileDialog.FileName;
|
|
|
|
toolStripStatusLabel1.Text = "Reading files...";
|
|
Application.DoEvents();
|
|
|
|
this.all_textures = ReadAllTextures();
|
|
foreach (string i in all_textures.Keys)
|
|
{
|
|
textureList.Items.Add(i);
|
|
}
|
|
|
|
toolStripStatusLabel1.Text = "Reading map file " + this.map_filename;
|
|
Application.DoEvents();
|
|
this.map_textures = ReadMapTextures(this.map_filename); ;
|
|
foreach (string i in map_textures.Keys)
|
|
{
|
|
texturesinmapList.Items.Add(i);
|
|
}
|
|
|
|
this.Activate();
|
|
toolStripStatusLabel1.Text = "Done";
|
|
|
|
button1.Enabled = true;
|
|
button3.Enabled = true;
|
|
textureList.Enabled = true;
|
|
exportButton.Enabled = true;
|
|
button2.Enabled = true;
|
|
openmapButton.Enabled = true;
|
|
}
|
|
|
|
private void openmapButton_Click(object sender, EventArgs e)
|
|
{
|
|
button1.Enabled = false;
|
|
button3.Enabled = false;
|
|
textureList.Enabled = false;
|
|
exportButton.Enabled = false;
|
|
button2.Enabled = false;
|
|
openmapButton.Enabled = false;
|
|
|
|
Application.DoEvents();
|
|
|
|
|
|
// Get map location
|
|
if (mapFileDialog.ShowDialog() != DialogResult.OK)
|
|
{
|
|
Application.Exit();
|
|
return;
|
|
}
|
|
|
|
this.map_filename = mapFileDialog.FileName;
|
|
|
|
toolStripStatusLabel1.Text = "Reading map file " + this.map_filename;
|
|
Application.DoEvents();
|
|
this.map_textures = ReadMapTextures(this.map_filename);
|
|
|
|
texturesinmapList.Items.Clear();
|
|
foreach (string i in map_textures.Keys)
|
|
{
|
|
texturesinmapList.Items.Add(i);
|
|
}
|
|
|
|
this.Activate();
|
|
toolStripStatusLabel1.Text = "Done";
|
|
|
|
button1.Enabled = true;
|
|
button3.Enabled = true;
|
|
textureList.Enabled = true;
|
|
exportButton.Enabled = true;
|
|
button2.Enabled = true;
|
|
openmapButton.Enabled = true;
|
|
}
|
|
}
|
|
}
|