giants-map-texture-changer/GiantsMapTextureChanger/ChangeTextureForm.cs

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;
}
}
}