mirror of
https://github.com/spiffcode/hostile-takeover.git
synced 2025-12-16 12:08:36 +00:00
1187 lines
42 KiB
C#
1187 lines
42 KiB
C#
using System;
|
|
using System.Drawing;
|
|
using System.Drawing.Imaging;
|
|
using System.Collections;
|
|
using System.IO;
|
|
using SpiffLib;
|
|
using System.Diagnostics;
|
|
using System.Text;
|
|
using m;
|
|
|
|
namespace m
|
|
{
|
|
public class OutputTools
|
|
{
|
|
public static void ImportExportPdbs(string[] astr) {
|
|
// Expand filespecs
|
|
ArrayList alsFiles = new ArrayList();
|
|
for (int n = 1; n < astr.Length; n++) {
|
|
string strFileT = Path.GetFileName(astr[n]);
|
|
string strDirT = Path.GetDirectoryName(astr[n]);
|
|
if (strDirT == "")
|
|
strDirT = ".";
|
|
string[] astrFiles = Directory.GetFiles(strDirT, strFileT);
|
|
foreach (string filename in astrFiles) {
|
|
if (filename.EndsWith(".pdb")) {
|
|
alsFiles.Add(filename);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Import, then save each pdb
|
|
foreach (string filename in alsFiles) {
|
|
try {
|
|
if (File.Exists(filename + "_new")) {
|
|
Console.WriteLine("Exists: " + filename + "_new");
|
|
continue;
|
|
}
|
|
ImportExpansionPdb(filename);
|
|
LevelDocTemplate doctLevel = (LevelDocTemplate)DocManager.FindDocTemplate(typeof(LevelDoc));
|
|
Document[] adoc = doctLevel.GetDocuments();
|
|
SaveExpansionPdb(filename + "_new", adoc, "1.1");
|
|
foreach (Document doc in adoc) {
|
|
doc.SetModified(false);
|
|
}
|
|
doctLevel.CloseAllDocuments();
|
|
} catch {
|
|
Console.WriteLine("Error loading " + filename + ", skipping");
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void ImportExpansionPdb(string strFile) {
|
|
PdbPacker pdbp = new PdbPacker(strFile);
|
|
|
|
ArrayList alsTileSets = new ArrayList();
|
|
for (int i = 0; i < pdbp.Count; i++) {
|
|
PdbPacker.File file = pdbp[i];
|
|
if (!file.str.EndsWith(".lvl")) {
|
|
continue;
|
|
}
|
|
|
|
// Load up the pieces
|
|
|
|
Ini ini = Ini.LoadBinary(new MemoryStream(file.ab));
|
|
string strTileMapFilename = ini["General"]["TileMap"].Value;
|
|
TileMap tmap = TileMap.Load(new MemoryStream(pdbp[strTileMapFilename].ab));
|
|
|
|
|
|
// First, tell the active LevelDoc not to switch its templates based on the following
|
|
// template load
|
|
|
|
LevelDoc lvldActive = (LevelDoc)DocManager.GetActiveDocument(typeof(LevelDoc));
|
|
if (lvldActive != null) {
|
|
lvldActive.SwitchTemplatesEnabled = false;
|
|
}
|
|
|
|
// If the TileSet for this level is not yet available, load it now
|
|
|
|
TemplateDoc tmpd = (TemplateDoc)DocManager.OpenDocument(tmap.Filename.Replace(".tset", ".tc"));
|
|
TileSet tset = null;
|
|
foreach (TileSet tsetT in alsTileSets) {
|
|
if (tsetT.FileName == tmap.Filename) {
|
|
tset = tsetT;
|
|
break;
|
|
}
|
|
}
|
|
if (tset == null) {
|
|
tset = new TileSet(tmpd, tmap.Filename);
|
|
alsTileSets.Add(tset);
|
|
}
|
|
|
|
// Re-enable template switching
|
|
|
|
if (lvldActive != null) {
|
|
lvldActive.SwitchTemplatesEnabled = true;
|
|
}
|
|
|
|
// Create a new level description, and deduce which templates are in it, with what visibility
|
|
|
|
LevelDoc lvld = (LevelDoc)DocManager.NewDocument(typeof(LevelDoc), null);
|
|
lvld.OutputFilename = file.str;
|
|
ImportTileMap(tmap, tset, tmpd, lvld);
|
|
|
|
// Walls are stored in the terrain map. Load them.
|
|
string strTrmapFilename = ini["General"]["TerrainMap"].Value;
|
|
TerrainMap trmap = TerrainMap.Load(new MemoryStream(pdbp[strTrmapFilename].ab));
|
|
ImportWalls(trmap, lvld);
|
|
|
|
// Load everything else
|
|
lvld.LoadIni(ini);
|
|
}
|
|
}
|
|
|
|
static void ImportWalls(TerrainMap trmap, LevelDoc lvld) {
|
|
ArrayList alsmi = new ArrayList();
|
|
for (int ty = 0; ty < trmap.Map.GetLength(0); ty++) {
|
|
for (int tx = 0; tx < trmap.Map.GetLength(1); tx++) {
|
|
if (trmap.Map[ty, tx] == TerrainTypes.Wall) {
|
|
IMapItem mi = new Wall(100, lvld.Bounds.Left + tx, lvld.Bounds.Top + ty);
|
|
alsmi.Add(mi);
|
|
}
|
|
}
|
|
}
|
|
lvld.AddMapItems((IMapItem[])alsmi.ToArray(typeof(IMapItem)));
|
|
}
|
|
|
|
class TemplatePos {
|
|
public Template tmpl;
|
|
public int txOrigin;
|
|
public int tyOrigin;
|
|
public bool[,] afMapped;
|
|
|
|
public TemplatePos(Template tmpl, int txOrigin, int tyOrigin, bool[,] afMapped) {
|
|
this.tmpl = tmpl;
|
|
this.txOrigin = txOrigin;
|
|
this.tyOrigin = tyOrigin;
|
|
this.afMapped = afMapped;
|
|
}
|
|
}
|
|
|
|
static void ImportTileMap(TileMap tmap, TileSet tset, TemplateDoc tmpd, LevelDoc lvld) {
|
|
// The TileMap is a list of indexes into a tile set. A Tileset is a list of tiles compiled
|
|
// from Templates. Reverse the tilemap into Templates, and set into lvld.
|
|
|
|
bool[,] afCellTaken = new bool[64, 64];
|
|
ArrayList alsTemplPos = new ArrayList();
|
|
Template[] atmpl = tmpd.GetTemplates();
|
|
for (int ty = 0; ty < tmap.Height; ty++) {
|
|
for (int tx = 0; tx < tmap.Width; tx++) {
|
|
// Cell mapped already?
|
|
if (afCellTaken[ty, tx]) {
|
|
continue;
|
|
}
|
|
|
|
// Cell not mapped. Create TemplatePos.
|
|
int iTile = tmap.GetTileIndex(tx, ty);
|
|
TileData tdata = tset.GetTileData(iTile);
|
|
Template tmpl = atmpl[tdata.iTemplate];
|
|
|
|
// Don't bother with background tiles
|
|
if (tmpl == tmpd.GetBackgroundTemplate()) {
|
|
continue;
|
|
}
|
|
|
|
int txOrigin = tx - tdata.txTemplate;
|
|
int tyOrigin = ty - tdata.tyTemplate;
|
|
bool[,] afMapped = new bool[tmpl.Cty, tmpl.Ctx];
|
|
|
|
for (int tyTmpl = 0; tyTmpl < tmpl.Cty; tyTmpl++) {
|
|
for (int txTmpl = 0; txTmpl < tmpl.Ctx; txTmpl++) {
|
|
int txT = txOrigin + txTmpl;
|
|
int tyT = tyOrigin + tyTmpl;
|
|
if (txT < 0 || txT >= 64 || tyT < 0 || tyT >= 64) {
|
|
continue;
|
|
}
|
|
if (afCellTaken[tyT, txT]) {
|
|
continue;
|
|
}
|
|
int iTileT = tmap.GetTileIndex(txT, tyT);
|
|
if (iTileT != -1) {
|
|
TileData tdataT = tset.GetTileData(iTileT);
|
|
if (tdataT.iTemplate != tdata.iTemplate) {
|
|
continue;
|
|
}
|
|
if (tdataT.txTemplate != txTmpl || tdataT.tyTemplate != tyTmpl) {
|
|
continue;
|
|
}
|
|
}
|
|
afMapped[tyTmpl, txTmpl] = true;
|
|
afCellTaken[tyT, txT] = true;
|
|
}
|
|
}
|
|
alsTemplPos.Add(new TemplatePos(tmpl, txOrigin, tyOrigin, afMapped));
|
|
}
|
|
}
|
|
|
|
// Figure out the bounds.
|
|
|
|
Rectangle rcBounds = new Rectangle((64 - tmap.Width) / 2, (64 - tmap.Height) / 2,
|
|
tmap.Width, tmap.Height);
|
|
lvld.Bounds = rcBounds;
|
|
|
|
// The list of TemplatePos's has been created. Add to LevelDoc.
|
|
|
|
ArrayList alsTiles = new ArrayList();
|
|
foreach (TemplatePos tpos in alsTemplPos) {
|
|
Tile tile = new Tile(tpos.tmpl.Name,
|
|
tpos.txOrigin + rcBounds.Left,
|
|
tpos.tyOrigin + rcBounds.Top,
|
|
tpos.afMapped, tpos.tmpl.OccupancyMap);
|
|
alsTiles.Add(tile);
|
|
}
|
|
lvld.AddMapItems((IMapItem[])alsTiles.ToArray(typeof(IMapItem)));
|
|
}
|
|
|
|
public static void SaveExpansionPdb(string strFile, Document[] adoc, string strVersion) {
|
|
// First save all level docs
|
|
|
|
//annoying
|
|
//DocManager.SaveAllModified(typeof(LevelDoc));
|
|
|
|
// Remember active document
|
|
|
|
LevelDoc lvldActive = (LevelDoc)DocManager.GetActiveDocument(typeof(LevelDoc));
|
|
|
|
// Save documents adoc in an expansion .pdb. Expansion .pdbs need:
|
|
// - .lvl, .tmap, .trmap, but not .tsets since these come from game .pdbs
|
|
// - need a version.txt
|
|
// - need an if demo trigger check "inserted" at save time
|
|
// - .pdb needs WARI creator, ADD1 type
|
|
// - data should be compressed for obfuscation purposes
|
|
|
|
PdbPacker pdbp = new PdbPacker();
|
|
|
|
// Add version.txt
|
|
|
|
byte[] abT = new byte[strVersion.Length + 1];
|
|
for (int n = 0; n < strVersion.Length; n++)
|
|
abT[n] = (byte)strVersion[n];
|
|
abT[abT.Length - 1] = 0;
|
|
pdbp.Add(new PdbPacker.File("version.txt", abT));
|
|
|
|
// Load res.h from embedded resource in prep for pre-process
|
|
|
|
System.Reflection.Assembly ass = typeof(GobImage).Module.Assembly;
|
|
Stream stmResDotH = ass.GetManifestResourceStream("m.EmbeddedResources." + "res.h");
|
|
if (stmResDotH == null)
|
|
throw new Exception("Cannot load res.h");
|
|
|
|
// Compile levels
|
|
|
|
Random rand = new Random();
|
|
ArrayList alsTileSets = new ArrayList();
|
|
foreach (LevelDoc lvld in adoc) {
|
|
// Need to do this unfortunately; some of the "saving" code relies on what the "active" document
|
|
// is!!
|
|
|
|
DocManager.SetActiveDocument(typeof(LevelDoc), lvld);
|
|
|
|
TemplateDoc tmpd = lvld.GetTemplateDoc();
|
|
|
|
// Get appropriate TileSet, or make one if this map
|
|
// uses a new tile collection
|
|
|
|
TileSet tset = null;
|
|
foreach (TileSet tsetT in alsTileSets) {
|
|
if (tsetT.TemplateDoc == tmpd) {
|
|
tset = tsetT;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Create new tile set if none found
|
|
|
|
if (tset == null) {
|
|
tset = new TileSet(tmpd, tmpd.GetName() + ".tset");
|
|
alsTileSets.Add(tset);
|
|
}
|
|
|
|
#if false
|
|
// Generate base file name for this level (this is never user-visible, but it should be
|
|
// as unique as possible
|
|
|
|
char[] achBase = new char[16];
|
|
for (int n = 0; n < achBase.Length; n++) {
|
|
int nT = rand.Next() % (26 + 10);
|
|
if (nT < 26) {
|
|
achBase[n] = (char)(nT + 97);
|
|
} else {
|
|
achBase[n] = (char)(nT + 48 - 26);
|
|
}
|
|
}
|
|
if (lvld.MaxPlayers > 1) {
|
|
achBase[0] = 'm';
|
|
achBase[1] = '_';
|
|
}
|
|
string strBase = new String(achBase);
|
|
#else
|
|
// This isn't unique which can cause problems due to how packfiles work.
|
|
// Could change packfile api to accept .pdb parameter.
|
|
// Note1: set next mission action requires predictable filename
|
|
// Note2: mission sorting is based on filename, not title
|
|
// Could put lots of "support" in to fix these problems, or just ship
|
|
// it like this.
|
|
//
|
|
// Hack: filename length 29
|
|
// Maximum extension on filename: 7
|
|
|
|
string strBase = lvld.Title;
|
|
if (strBase.Length > 29 - 7)
|
|
strBase = strBase.Substring(0, 29 - 7);
|
|
|
|
// If multiplayer, add "m_" to the name by losing the last two characters
|
|
// so sort order is preserved
|
|
|
|
if (lvld.MaxPlayers > 1)
|
|
strBase = "m_" + strBase.Substring(0, strBase.Length - 2);
|
|
#endif
|
|
|
|
// Get tile map file for this level
|
|
|
|
MemoryStream stmTmap = new MemoryStream();
|
|
TileMap tmap = TileMap.CreateFromImage(tset, lvld.GetMapBitmap(tmpd.TileSize, tmpd, true), tmpd.TileSize);
|
|
tmap.Save(stmTmap);
|
|
string strTmap = strBase + ".tmap";
|
|
pdbp.Add(new PdbPacker.File(strTmap, stmTmap.ToArray()));
|
|
stmTmap.Close();
|
|
|
|
// Get the terrain map file for this level
|
|
|
|
MemoryStream stmTRmap = new MemoryStream();
|
|
TerrainMap trmap = new TerrainMap(lvld.GetTerrainMap(tmpd.TileSize, tmpd, false));
|
|
trmap.Save(stmTRmap);
|
|
string strTRmap = strBase + ".trmap";
|
|
pdbp.Add(new PdbPacker.File(strTRmap, stmTRmap.ToArray()));
|
|
stmTRmap.Close();
|
|
|
|
// Save .ini file for this level doc
|
|
|
|
MemoryStream stmLvld = new MemoryStream();
|
|
lvld.SaveIni(stmLvld, -1, strTmap, strTRmap, tmpd.GetName() + ".palbin", true);
|
|
|
|
// Pre-process
|
|
|
|
stmLvld.Seek(0, SeekOrigin.Begin);
|
|
MemoryStream stmPreprocessed = Misc.PreprocessStream(stmLvld, stmResDotH);
|
|
stmPreprocessed.Seek(0, SeekOrigin.Begin);
|
|
Ini iniPreProcessed = new Ini(stmPreprocessed);
|
|
|
|
MemoryStream stmLvldPreProcessedBinary = new MemoryStream();
|
|
iniPreProcessed.SaveBinary(stmLvldPreProcessedBinary);
|
|
stmLvldPreProcessedBinary.Close();
|
|
|
|
string strLvlName = lvld.OutputFilename;
|
|
if (strLvlName == null) {
|
|
strLvlName = strBase + ".lvl";
|
|
}
|
|
pdbp.Add(new PdbPacker.File(strLvlName, stmLvldPreProcessedBinary.ToArray()));
|
|
stmLvldPreProcessedBinary.Close();
|
|
}
|
|
stmResDotH.Close();
|
|
|
|
// Restore active document
|
|
|
|
if (lvldActive != null)
|
|
DocManager.SetActiveDocument(typeof(LevelDoc), lvldActive);
|
|
|
|
// Now save out pdb
|
|
|
|
pdbp.Save(strFile, "WARI", "ADD2");
|
|
}
|
|
|
|
public static void MixMapImportSpecial(Theater theater, TemplateDoc tmpdCopyTerrain, string strFileSave) {
|
|
TemplateDoc tmpd24 = (TemplateDoc)DocManager.NewDocument(typeof(TemplateDoc), new Object[] { new Size(24, 24) });
|
|
MixTemplate[] amixt = MixSuck.LoadTemplates(theater);
|
|
MixSuck.ImportTemplates(amixt, tmpd24);
|
|
|
|
Template[] atmpl24 = tmpd24.GetTemplates();
|
|
Template[] atmpl16 = tmpdCopyTerrain.GetTemplates();
|
|
|
|
for (int n = 0; n < atmpl24.Length; n++) {
|
|
Template tmpl24 = atmpl24[n];
|
|
Template tmpl16 = atmpl16[n];
|
|
tmpl24.TerrainMap = tmpl16.TerrainMap;
|
|
}
|
|
|
|
tmpd24.SetBackgroundTemplate(atmpl24[0]);
|
|
tmpd24.SaveAs(strFileSave);
|
|
}
|
|
|
|
public static void MakePalette(string[] astr) {
|
|
// -makepal 16 templates.tc palsize fixpalsize backgroundpalsize fixed.pal out.pal
|
|
|
|
// tile size
|
|
|
|
Size sizTile = new Size(0, 0);
|
|
sizTile.Width = int.Parse(astr[1]);
|
|
sizTile.Height = sizTile.Width;
|
|
|
|
// Load template collection
|
|
|
|
TemplateDoc tmpd = (TemplateDoc)DocManager.OpenDocument(astr[2]);
|
|
|
|
// palette size
|
|
|
|
int cPalEntries = int.Parse(astr[3]);
|
|
|
|
// entries fixed
|
|
|
|
int cPalEntriesFixed = int.Parse(astr[4]);
|
|
|
|
// entries for background
|
|
|
|
int cPalEntriesBackground = int.Parse(astr[5]);
|
|
|
|
// fixed palette
|
|
|
|
Palette palFixed = new Palette(astr[6]);
|
|
|
|
// output palette
|
|
|
|
string strFilePalOut = astr[7];
|
|
|
|
// If this template collection already has a palette it has already been quantized; we don't
|
|
// want that.
|
|
|
|
if (tmpd.GetPalette() != null)
|
|
new Exception("Template collection has already been quantized!");
|
|
|
|
// Scale templates if needed
|
|
|
|
if (sizTile.Width != tmpd.TileSize.Width || sizTile.Height != tmpd.TileSize.Height)
|
|
TemplateTools.ScaleTemplates(tmpd, sizTile);
|
|
|
|
// Quantize
|
|
|
|
TemplateTools.QuantizeTemplates(tmpd, palFixed, cPalEntries, cPalEntriesFixed, cPalEntriesBackground);
|
|
|
|
// Save the new palette out
|
|
|
|
Palette palNew = tmpd.GetPalette();
|
|
palNew.SaveJasc(strFilePalOut);
|
|
}
|
|
|
|
public static void ExportMixMaps(string[] astr) {
|
|
// Expand filespecs
|
|
ArrayList alsFiles = new ArrayList();
|
|
for (int n = 1; n < astr.Length; n++) {
|
|
string strFileT = Path.GetFileName(astr[n]);
|
|
string strDirT = Path.GetDirectoryName(astr[n]);
|
|
if (strDirT == "")
|
|
strDirT = ".";
|
|
string[] astrFiles = Directory.GetFiles(strDirT, strFileT);
|
|
alsFiles.AddRange(astrFiles);
|
|
}
|
|
|
|
foreach (string strFile in alsFiles) {
|
|
LevelDoc lvld = (LevelDoc)DocManager.NewDocument(typeof(LevelDoc), null);
|
|
Console.Write("Exporting " + strFile + " as ");
|
|
string strFileExport = MixSuck.ImportExportMixMap(strFile, lvld);
|
|
if (strFileExport == null) {
|
|
Console.Write("Error exporting!\n");
|
|
} else {
|
|
Console.Write(strFileExport + "\n");
|
|
}
|
|
lvld.Dispose();
|
|
}
|
|
}
|
|
|
|
public static void ExportImages(string[] astr) {
|
|
// Get directory
|
|
//string strDir = Path.GetFullPath(astr[1]);
|
|
string strDir = ".";
|
|
string strPrefix = astr[1];
|
|
|
|
// Expand filespecs
|
|
ArrayList alsFiles = new ArrayList();
|
|
for (int n = 2; n < astr.Length; n++) {
|
|
string strFileT = Path.GetFileName(astr[n]);
|
|
string strDirT = Path.GetDirectoryName(astr[n]);
|
|
if (strDirT == "")
|
|
strDirT = ".";
|
|
string[] astrFiles = Directory.GetFiles(strDirT, strFileT);
|
|
alsFiles.AddRange(astrFiles);
|
|
}
|
|
|
|
// Attempt to process these level docs
|
|
foreach (string strFile in alsFiles) {
|
|
Console.Write("Map of " + strFile + " -> ");
|
|
LevelDoc lvld = (LevelDoc)DocManager.OpenDocument(strFile);
|
|
if (lvld == null)
|
|
throw new Exception("Could not load level doc " + strFile);
|
|
string strPng = strDir + Path.DirectorySeparatorChar + strPrefix + Path.GetFileName(strFile).Replace(".ld", ".png");
|
|
Console.Write(strPng + "...");
|
|
TemplateDoc tmpd = lvld.GetTemplateDoc();
|
|
Bitmap bm = lvld.GetMapBitmap(tmpd.TileSize, tmpd, true);
|
|
bm.Save(strPng, ImageFormat.Png);
|
|
bm.Dispose();
|
|
lvld.Dispose();
|
|
Console.Write(" Done.\n");
|
|
}
|
|
}
|
|
|
|
public static void ExportLevels(string[] astr, int nVersion) {
|
|
// Get tile size
|
|
|
|
Size sizTile = new Size(0, 0);
|
|
sizTile.Width = int.Parse(astr[1]);
|
|
sizTile.Height = sizTile.Width;
|
|
|
|
// Get depth
|
|
|
|
int nDepth = Int32.Parse(astr[2]);
|
|
|
|
// Get background threshold
|
|
|
|
double nAreaBackgroundThreshold = double.Parse(astr[3]);
|
|
|
|
// Background luminance multiplier
|
|
|
|
double nLuminanceMultBackground = double.Parse(astr[4]);
|
|
|
|
// Background saturation multiplier
|
|
|
|
double nSaturationMultBackground = double.Parse(astr[5]);
|
|
|
|
// Foreground luminance multiplier
|
|
|
|
double nLuminanceMultForeground = double.Parse(astr[6]);
|
|
|
|
// Foreground saturation multiplier
|
|
|
|
double nSaturationMultForeground = double.Parse(astr[7]);
|
|
|
|
// Palette directory
|
|
|
|
string strPalDir = astr[8];
|
|
|
|
// Get output directory
|
|
|
|
string strDir = Path.GetFullPath(astr[9]);
|
|
|
|
// Expand filespecs
|
|
ArrayList alsFiles = new ArrayList();
|
|
for (int n = 9; n < astr.Length; n++) {
|
|
string strFileT = Path.GetFileName(astr[n]);
|
|
string strDirT = Path.GetDirectoryName(astr[n]);
|
|
if (strDirT == "")
|
|
strDirT = ".";
|
|
string[] astrFiles = Directory.GetFiles(strDirT, strFileT);
|
|
alsFiles.AddRange(astrFiles);
|
|
}
|
|
|
|
// Attempt to process these level doc
|
|
ArrayList alsTileSets = new ArrayList();
|
|
foreach (string strFile in alsFiles) {
|
|
Console.Write("Loading " + strFile + "...");
|
|
LevelDoc lvld = (LevelDoc)DocManager.OpenDocument(strFile);
|
|
if (lvld == null)
|
|
throw new Exception("Could not load level doc " + strFile);
|
|
Console.Write(" Done.\n");
|
|
|
|
// Size this template collection if necessary
|
|
|
|
TemplateDoc tmpd = lvld.GetTemplateDoc();
|
|
if (sizTile.Width != tmpd.TileSize.Width || sizTile.Height != tmpd.TileSize.Height)
|
|
TemplateTools.ScaleTemplates(tmpd, sizTile);
|
|
|
|
// Get appropriate TileSet, or make one if this map
|
|
// uses a new tile collection
|
|
TileSet tset = null;
|
|
foreach (TileSet tsetT in alsTileSets) {
|
|
if (tsetT.TileCollectionFileName == Path.GetFileName(lvld.GetTemplateDoc().GetPath())) {
|
|
tset = tsetT;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Create new tile set if none found
|
|
if (tset == null) {
|
|
string strTcPath = lvld.GetTemplateDoc().GetPath();
|
|
string strTcName = Path.GetFileNameWithoutExtension(strTcPath);
|
|
string strTcDir = Path.GetDirectoryName(strTcPath);
|
|
string strT3 = strTcDir + Path.DirectorySeparatorChar + strPalDir + Path.DirectorySeparatorChar + strTcName;
|
|
tset = new TileSet(lvld.GetTemplateDoc(), Path.GetFileName(strTcPath), strT3, nDepth, sizTile);
|
|
alsTileSets.Add(tset);
|
|
}
|
|
|
|
// Get and save a tile map for this level
|
|
string strTmap = Path.GetFileName(lvld.GetPath().Replace(".ld", ".tmap"));
|
|
string strFileTmap = strDir + Path.DirectorySeparatorChar + strTmap;
|
|
Console.Write("Creating & writing " + strFileTmap + "...");
|
|
TileMap tmap = TileMap.CreateFromImage(tset, lvld.GetMapBitmap(tmpd.TileSize, tmpd, true), tmpd.TileSize);
|
|
tmap.Save(strFileTmap);
|
|
Console.Write(" Done.\n");
|
|
|
|
// Get and save terrain map for this level
|
|
string strTrmap = Path.GetFileName(lvld.GetPath().Replace(".ld", ".trmap"));
|
|
string strFileTrmap = strDir + Path.DirectorySeparatorChar + strTrmap;
|
|
Console.Write("Creating & writing " + strFileTrmap + "...");
|
|
TerrainMap trmap = new TerrainMap(lvld.GetTerrainMap(tmpd.TileSize, tmpd, false));
|
|
trmap.Save(strFileTrmap);
|
|
Console.Write(" Done.\n");
|
|
|
|
// Save .ini for this level doc
|
|
string strFileIni = strDir + Path.DirectorySeparatorChar + Path.GetFileName(strFile).Replace(".ld", ".lvl");
|
|
Console.Write("Writing " + strFileIni + "...");
|
|
lvld.SaveIni(strFileIni, nVersion, strTmap, strTrmap, tset.PalBinFileName);
|
|
Console.Write(" Done.\n");
|
|
lvld.Dispose();
|
|
}
|
|
|
|
// Now write out tilesets
|
|
foreach (TileSet tset in alsTileSets) {
|
|
// Save tile set
|
|
string strFileTset = strDir + Path.DirectorySeparatorChar + tset.FileName;
|
|
Console.Write("Creating & writing " + strFileTset + ", " + tset.Count.ToString() + " tiles...");
|
|
tset.Save(strFileTset);
|
|
tset.SaveMini(strFileTset, nAreaBackgroundThreshold, nLuminanceMultBackground, nSaturationMultBackground, nLuminanceMultForeground, nSaturationMultForeground);
|
|
Console.Write(" Done.\n");
|
|
}
|
|
}
|
|
|
|
public static void ExportText(string[] astr) {
|
|
// Expand filespecs
|
|
ArrayList alsFiles = new ArrayList();
|
|
for (int n = 1; n < astr.Length; n++) {
|
|
string strFileT = Path.GetFileName(astr[n]);
|
|
string strDirT = Path.GetDirectoryName(astr[n]);
|
|
if (strDirT == "")
|
|
strDirT = ".";
|
|
string[] astrFiles = Directory.GetFiles(strDirT, strFileT);
|
|
alsFiles.AddRange(astrFiles);
|
|
}
|
|
|
|
Console.WriteLine("Exporting text from {0} files", alsFiles.Count);
|
|
|
|
// Attempt to process these level docs
|
|
|
|
foreach (string strFile in alsFiles) {
|
|
Console.Write("Writing text of " + strFile + "...");
|
|
LevelDoc lvld = (LevelDoc)DocManager.OpenDocument(strFile);
|
|
if (lvld == null)
|
|
throw new Exception("Could not load level doc " + strFile);
|
|
string strTextFile = "." + Path.DirectorySeparatorChar + Path.GetFileName(strFile).Replace(".ld", ".txt");
|
|
string str = lvld.GetLevelText();
|
|
str = str.Replace("\n", "\r\n");
|
|
StreamWriter stmw = new StreamWriter(strTextFile);
|
|
stmw.Write(str);
|
|
stmw.Close();
|
|
lvld.Dispose();
|
|
Console.WriteLine(" done");
|
|
}
|
|
}
|
|
|
|
public static void ImportText(string[] astr) {
|
|
// Expand filespecs
|
|
ArrayList alsFiles = new ArrayList();
|
|
for (int n = 1; n < astr.Length; n++) {
|
|
string strFileT = Path.GetFileName(astr[n]);
|
|
string strDirT = Path.GetDirectoryName(astr[n]);
|
|
if (strDirT == "")
|
|
strDirT = ".";
|
|
string[] astrFiles = Directory.GetFiles(strDirT, strFileT);
|
|
alsFiles.AddRange(astrFiles);
|
|
}
|
|
|
|
Console.WriteLine("Importing text from {0} files", alsFiles.Count);
|
|
|
|
// Attempt to process these text files/level docs
|
|
|
|
foreach (string strTextFile in alsFiles) {
|
|
string strFile = "." + Path.DirectorySeparatorChar + Path.GetFileName(strTextFile).Replace(".txt", ".ld");
|
|
Console.Write("Writing " + strTextFile + " to " + strFile + "...");
|
|
LevelDoc lvld = (LevelDoc)DocManager.OpenDocument(strFile);
|
|
if (lvld == null)
|
|
throw new Exception("Could not load level doc " + strFile);
|
|
|
|
StreamReader stmr = new StreamReader(strTextFile);
|
|
string str = stmr.ReadToEnd();
|
|
stmr.Close();
|
|
str = str.Replace("\r\n", "\n");
|
|
|
|
int ichErrorPos;
|
|
if (!lvld.SetLevelText(str, out ichErrorPos)) {
|
|
Console.WriteLine(" error at char " + ichErrorPos);
|
|
} else {
|
|
lvld.Save();
|
|
Console.WriteLine(" saved");
|
|
}
|
|
lvld.Dispose();
|
|
}
|
|
}
|
|
}
|
|
|
|
class TerrainMap {
|
|
private TerrainTypes[,] m_aterMap;
|
|
|
|
public TerrainMap(TerrainTypes[,] aterMap) {
|
|
m_aterMap = aterMap;
|
|
}
|
|
|
|
public void Save(string strFileTrmap) {
|
|
Stream stm = new FileStream(strFileTrmap, FileMode.Create, FileAccess.Write, FileShare.None);
|
|
Save(stm);
|
|
}
|
|
|
|
public void Save(Stream stm) {
|
|
BinaryWriter bwtr = new BinaryWriter(stm);
|
|
|
|
//struct TerrainMapHeader { // trmhdr
|
|
// word ctx;
|
|
// word cty;
|
|
//};
|
|
|
|
bwtr.Write(Misc.SwapUShort((ushort)m_aterMap.GetLength(1)));
|
|
bwtr.Write(Misc.SwapUShort((ushort)m_aterMap.GetLength(0)));
|
|
for (int ty = 0; ty < m_aterMap.GetLength(0); ty++) {
|
|
for (int tx = 0; tx < m_aterMap.GetLength(1); tx++) {
|
|
byte b = 0;
|
|
switch (m_aterMap[ty, tx]) {
|
|
default:
|
|
case TerrainTypes.Open:
|
|
b = 1;
|
|
break;
|
|
|
|
case TerrainTypes.Area:
|
|
b = 0;
|
|
break;
|
|
|
|
case TerrainTypes.Wall:
|
|
b = 2;
|
|
break;
|
|
|
|
case TerrainTypes.Blocked:
|
|
b = 3;
|
|
break;
|
|
}
|
|
bwtr.Write(b);
|
|
}
|
|
}
|
|
bwtr.Close();
|
|
}
|
|
|
|
public static TerrainMap Load(MemoryStream stm) {
|
|
BinaryReader brdr = new BinaryReader(stm);
|
|
int ctx = (int)Misc.SwapUShort(brdr.ReadUInt16());
|
|
int cty = (int)Misc.SwapUShort(brdr.ReadUInt16());
|
|
TerrainTypes[,] map = new TerrainTypes[cty, ctx];
|
|
for (int ty = 0; ty < cty; ty++) {
|
|
for (int tx = 0; tx < ctx; tx++) {
|
|
byte b = brdr.ReadByte();
|
|
switch (b) {
|
|
case 0: // Area
|
|
map[ty, tx] = TerrainTypes.Area;
|
|
break;
|
|
|
|
case 1: // Open
|
|
map[ty, tx] = TerrainTypes.Open;
|
|
break;
|
|
|
|
case 2: // Wall
|
|
map[ty, tx] = TerrainTypes.Wall;
|
|
break;
|
|
|
|
case 3: // Blocked
|
|
map[ty, tx] = TerrainTypes.Blocked;
|
|
break;
|
|
|
|
default: // Default to Open
|
|
map[ty, tx] = TerrainTypes.Open;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
brdr.Close();
|
|
return new TerrainMap(map);
|
|
}
|
|
|
|
public TerrainTypes[,] Map {
|
|
get {
|
|
return m_aterMap;
|
|
}
|
|
}
|
|
}
|
|
|
|
class TileMap {
|
|
int m_ctx;
|
|
int m_cty;
|
|
Size m_sizTile;
|
|
int[,] m_aiTile;
|
|
string m_strTSetFileName;
|
|
|
|
public TileMap(string strTSetFileName, int ctx, int cty, Size sizTile) {
|
|
m_strTSetFileName = strTSetFileName;
|
|
m_ctx = ctx;
|
|
m_cty = cty;
|
|
m_sizTile = sizTile;
|
|
m_aiTile = new int[cty, ctx];
|
|
}
|
|
|
|
public TileMap(string strTSetFileName, int ctx, int cty, int[,] aiTile, Size sizTile) {
|
|
m_strTSetFileName = strTSetFileName;
|
|
m_ctx = ctx;
|
|
m_cty = cty;
|
|
m_aiTile = aiTile;
|
|
m_sizTile = sizTile;
|
|
}
|
|
|
|
public string Filename {
|
|
get {
|
|
return m_strTSetFileName;
|
|
}
|
|
}
|
|
|
|
public int Width {
|
|
get {
|
|
return m_ctx;
|
|
}
|
|
}
|
|
|
|
public int Height {
|
|
get {
|
|
return m_cty;
|
|
}
|
|
}
|
|
|
|
public static TileMap CreateFromImage(TileSet tset, Bitmap bm, Size sizTile) {
|
|
int ctx = bm.Width / sizTile.Width;
|
|
int cty = bm.Height / sizTile.Height;
|
|
TileMap tmap = new TileMap(tset.FileName, ctx, cty, sizTile);
|
|
tmap.InitFromImage(tset, bm);
|
|
return tmap;
|
|
}
|
|
|
|
public void InitFromImage(TileSet tset, Bitmap bm) {
|
|
Color[] aclrTile = new Color[m_sizTile.Width * m_sizTile.Height];
|
|
for (int ty = 0; ty < m_cty; ty++) {
|
|
for (int tx = 0; tx < m_ctx; tx++) {
|
|
TileSet.ExtractTilePixels(bm, tx, ty, m_sizTile, ref aclrTile);
|
|
int index = tset.FindTileIndex(aclrTile);
|
|
if (index == -1)
|
|
throw new Exception("Couldn't find tile index!");
|
|
m_aiTile[ty, tx] = index;
|
|
}
|
|
}
|
|
}
|
|
|
|
public void Save(string strFileTmap) {
|
|
Stream stm = new FileStream(strFileTmap, FileMode.Create, FileAccess.Write, FileShare.None);
|
|
Save(stm);
|
|
}
|
|
|
|
public void Save(Stream stm) {
|
|
BinaryWriter bwtr = new BinaryWriter(stm);
|
|
|
|
// #define kcbFilename 28
|
|
// struct TileMapHeader { // thdr
|
|
// char szFnTset[kcbFilename];
|
|
// word ctx;
|
|
// word cty;
|
|
// };
|
|
|
|
char[] szFnTset = new char[28];
|
|
m_strTSetFileName.CopyTo(0, szFnTset, 0, m_strTSetFileName.Length);
|
|
bwtr.Write(szFnTset);
|
|
bwtr.Write(Misc.SwapUShort((ushort)m_ctx));
|
|
bwtr.Write(Misc.SwapUShort((ushort)m_cty));
|
|
|
|
for (int ty = 0; ty < m_cty; ty++) {
|
|
for (int tx = 0; tx < m_ctx; tx++) {
|
|
bwtr.Write(Misc.SwapUShort((ushort)(m_aiTile[ty, tx] << 2)));
|
|
}
|
|
}
|
|
bwtr.Close();
|
|
}
|
|
|
|
public static TileMap Load(MemoryStream stm) {
|
|
BinaryReader brdr = new BinaryReader(stm);
|
|
byte[] ab = brdr.ReadBytes(28);
|
|
int i = 0;
|
|
for (; i < ab.Length; i++) {
|
|
if (ab[i] == 0) {
|
|
break;
|
|
}
|
|
}
|
|
string strFilename = Encoding.ASCII.GetString(ab, 0, i);
|
|
int ctx = Misc.SwapUShort(brdr.ReadUInt16());
|
|
int cty = Misc.SwapUShort(brdr.ReadUInt16());
|
|
|
|
int [,] aiTile = new int[cty, ctx];
|
|
for (int ty = 0; ty < cty; ty++) {
|
|
for (int tx = 0; tx < ctx; tx++) {
|
|
aiTile[ty, tx] = Misc.SwapUShort(brdr.ReadUInt16()) >> 2;
|
|
}
|
|
}
|
|
brdr.Close();
|
|
|
|
Size sizTile = new Size(24, 24); // hardwired
|
|
return new TileMap(strFilename, ctx, cty, aiTile, sizTile);
|
|
}
|
|
|
|
public int GetTileIndex(int tx, int ty) {
|
|
if (tx < 0 || tx >= m_aiTile.GetLength(1)) {
|
|
return -1;
|
|
}
|
|
if (ty < 0 || ty >= m_aiTile.GetLength(0)) {
|
|
return -1;
|
|
}
|
|
return m_aiTile[ty, tx];
|
|
}
|
|
}
|
|
|
|
struct TileData {
|
|
public int hash;
|
|
public Color[] aclr;
|
|
public int iTemplate;
|
|
public int txTemplate;
|
|
public int tyTemplate;
|
|
}
|
|
|
|
class TileSet {
|
|
public string FileName;
|
|
public string TileCollectionFileName;
|
|
public string PalBinFileName;
|
|
public TemplateDoc TemplateDoc;
|
|
private ArrayList m_alsTileData = new ArrayList();
|
|
private Palette m_pal = null;
|
|
private static int s_cbFileMax = 32000;
|
|
Size m_sizTile;
|
|
|
|
public TileSet(TemplateDoc tmpd, string strFile) {
|
|
TemplateDoc = tmpd;
|
|
m_pal = tmpd.GetPalette();
|
|
m_sizTile = tmpd.TileSize;
|
|
FileName = strFile.Replace(".tc", ".tset");
|
|
SuckTemplates();
|
|
}
|
|
|
|
public TileSet(TemplateDoc tmpd, string strFile, string strFilePal, int nDepth, Size sizTile) {
|
|
TemplateDoc = tmpd;
|
|
m_pal = new Palette(strFilePal + "_" + nDepth.ToString() + "bpp.pal");
|
|
TileCollectionFileName = strFile;
|
|
FileName = strFile.Replace(".tc", ".tset");
|
|
PalBinFileName = Path.GetFileName(strFilePal) + ".palbin";
|
|
m_sizTile = sizTile;
|
|
SuckTemplates();
|
|
}
|
|
|
|
private void SuckTemplates() {
|
|
// Suck all the tiles in
|
|
|
|
Template[] atmpl = TemplateDoc.GetTemplates();
|
|
int iTemplate = 0;
|
|
foreach (Template tmpl in atmpl) {
|
|
bool[,] afOccupancy = tmpl.OccupancyMap;
|
|
for (int ty = 0; ty < afOccupancy.GetLength(0); ty++) {
|
|
for (int tx = 0; tx < afOccupancy.GetLength(1); tx++) {
|
|
if (!afOccupancy[ty, tx])
|
|
continue;
|
|
TileData tdata = new TileData();
|
|
tdata.iTemplate = iTemplate;
|
|
tdata.txTemplate = tx;
|
|
tdata.tyTemplate = ty;
|
|
tdata.aclr = new Color[m_sizTile.Width * m_sizTile.Height];
|
|
ExtractTilePixels(tmpl.Bitmap, tx, ty, m_sizTile, ref tdata.aclr);
|
|
tdata.hash = HashTile(tdata.aclr);
|
|
m_alsTileData.Add(tdata);
|
|
}
|
|
}
|
|
iTemplate++;
|
|
}
|
|
}
|
|
|
|
public static unsafe void ExtractTilePixels(Bitmap bm, int tx, int ty, Size sizTile, ref Color[] aclrTile) {
|
|
Rectangle rcSrc = new Rectangle(tx * sizTile.Width, ty * sizTile.Height, sizTile.Width, sizTile.Height);
|
|
BitmapData bmd = bm.LockBits(rcSrc, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
|
|
IntPtr p = bmd.Scan0;
|
|
byte *pbBase = (byte *)p.ToPointer();
|
|
for (int y = 0; y < sizTile.Height; y++) {
|
|
for (int x = 0; x < sizTile.Width; x++) {
|
|
byte *pb = pbBase + y * bmd.Stride + x * 3;
|
|
aclrTile[y * sizTile.Width + x] = Color.FromArgb(pb[2], pb[1], pb[0]);
|
|
}
|
|
}
|
|
bm.UnlockBits(bmd);
|
|
}
|
|
|
|
public int FindTileIndex(Color[] aclrTile) {
|
|
int hash = HashTile(aclrTile);
|
|
for (int n = 0; n < m_alsTileData.Count; n++) {
|
|
TileData td = (TileData)m_alsTileData[n];
|
|
if (hash == td.hash && CheckTileMatch(aclrTile, td.aclr))
|
|
return n;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int HashTile(Color[] aclrTile) {
|
|
int hash = 0;
|
|
for (int n = 0; n < aclrTile.Length; n++) {
|
|
Color clr = aclrTile[n];
|
|
hash += (hash << 1) | (clr.R << 16) + (clr.G << 8) + clr.B;
|
|
}
|
|
return hash;
|
|
}
|
|
|
|
bool CheckTileMatch(Color[] aclr1, Color[] aclr2) {
|
|
for (int n = 0; n < aclr1.Length; n++) {
|
|
if (aclr1[n] != aclr2[n])
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public void Save(string strFileTset) {
|
|
// struct TileSetHeader { // tshdr
|
|
// ushort cTiles;
|
|
// ushort cxTile;
|
|
// ushort cyTile;
|
|
// };
|
|
|
|
int cbTile = m_sizTile.Width * m_sizTile.Height;
|
|
int cTilesFit = (s_cbFileMax - 6) / cbTile;
|
|
int cTilesLeft = m_alsTileData.Count;
|
|
|
|
int nFile = 0;
|
|
int nTile = 0;
|
|
while (cTilesLeft != 0) {
|
|
// Get filename
|
|
string strT = strFileTset;
|
|
if (nFile > 0)
|
|
strT = strFileTset.Replace(".tset", ".tset." + nFile.ToString());
|
|
nFile++;
|
|
|
|
// Open file for writing
|
|
Stream stm = new FileStream(strT, FileMode.Create, FileAccess.Write, FileShare.None);
|
|
BinaryWriter bwtr = new BinaryWriter(stm);
|
|
|
|
// Figure out how many tiles will go in this file
|
|
int cTilesWrite = Math.Min(cTilesFit, cTilesLeft);
|
|
|
|
// Write out the header
|
|
bwtr.Write(Misc.SwapUShort((ushort)cTilesWrite));
|
|
bwtr.Write(Misc.SwapUShort((ushort)m_sizTile.Width));
|
|
bwtr.Write(Misc.SwapUShort((ushort)m_sizTile.Height));
|
|
|
|
// Write out the tiles
|
|
for (int n = 0; n < cTilesWrite; n++) {
|
|
bwtr.Write(GetTileBytes(nTile));
|
|
nTile++;
|
|
}
|
|
|
|
// Next file
|
|
bwtr.Close();
|
|
cTilesLeft -= cTilesWrite;
|
|
}
|
|
}
|
|
|
|
public void SaveMini(string strFileTset, double nAreaBackgroundThreshold, double nLuminanceMultBackground, double nSaturationMultBackground, double nLuminanceMultForeground, double nSaturationMultForeground) {
|
|
// Now write out minimap tiles, 2x2 and 1x1
|
|
|
|
Stream stmT = new FileStream(strFileTset.Replace(".tset", ".tsetmini"), FileMode.Create, FileAccess.Write, FileShare.None);
|
|
BinaryWriter bwtrMini = new BinaryWriter(stmT);
|
|
WriteMiniTiles(bwtrMini, m_pal, TemplateDoc, 2, true, nAreaBackgroundThreshold, nLuminanceMultBackground, nSaturationMultBackground, nLuminanceMultForeground, nSaturationMultForeground);
|
|
WriteMiniTiles(bwtrMini, m_pal, TemplateDoc, 1, false, nAreaBackgroundThreshold, nLuminanceMultBackground, nSaturationMultBackground, nLuminanceMultForeground, nSaturationMultForeground);
|
|
bwtrMini.Close();
|
|
}
|
|
|
|
void WriteMiniTiles(BinaryWriter bwtr, Palette pal, TemplateDoc tmpd, int cx, bool fNext, double nAreaBackgroundThreshold, double nLuminanceMultBackground, double nSaturationMultBackground, double nLuminanceMultForeground, double nSaturationMultForeground) {
|
|
// struct MiniTileSetHeader { // mtshdr
|
|
// ushort offNext;
|
|
// ushort cTiles;
|
|
// ushort cxTile;
|
|
// ushort cyTile;
|
|
// };
|
|
|
|
ushort offNext = 0;
|
|
if (fNext)
|
|
offNext = (ushort)(8 + m_alsTileData.Count * cx * cx);
|
|
bwtr.Write(Misc.SwapUShort(offNext));
|
|
bwtr.Write(Misc.SwapUShort((ushort)m_alsTileData.Count));
|
|
bwtr.Write(Misc.SwapUShort((ushort)cx));
|
|
bwtr.Write(Misc.SwapUShort((ushort)cx));
|
|
|
|
// If a background template exists, use it to distinguish foreground from background objects for better minimaps
|
|
|
|
Size sizTile = tmpd.TileSize;
|
|
ArrayList alsColors = new ArrayList();
|
|
Template tmplBackground = tmpd.GetBackgroundTemplate();
|
|
if (tmplBackground != null && nAreaBackgroundThreshold >= 0.0) {
|
|
// Get despeckled hue map of background, calc mean and
|
|
// std dev for filtering purposes
|
|
|
|
Bitmap bmHueBackground = TemplateTools.MakeHueMap(tmplBackground.Bitmap);
|
|
TemplateTools.DespeckleGrayscaleBitmap(bmHueBackground, 9, 50);
|
|
double nMean = TemplateTools.CalcGrayscaleMean(bmHueBackground);
|
|
double nStdDev = TemplateTools.CalcGrayscaleStandardDeviation(bmHueBackground, nMean);
|
|
|
|
// Go through each tile, first make a mask that'll delineate foreground from background
|
|
|
|
Bitmap bmTile = new Bitmap(sizTile.Width, sizTile.Height);
|
|
foreach (TileData td in m_alsTileData) {
|
|
// Need to turn data back into a bitmap - doh!
|
|
|
|
for (int y = 0; y < sizTile.Height; y++) {
|
|
for (int x = 0; x < sizTile.Width; x++) {
|
|
Color clr = (Color)td.aclr[y * sizTile.Width + x];
|
|
bmTile.SetPixel(x, y, clr);
|
|
}
|
|
}
|
|
|
|
// Create mask which'll replace background with transparent color (255, 0, 255)
|
|
|
|
Bitmap bmMask = TemplateTools.MakeHueMap(bmTile);
|
|
TemplateTools.DespeckleGrayscaleBitmap(bmMask, 9, 50);
|
|
TemplateTools.SubtractGrayscaleDistribution(bmMask, nMean, nStdDev);
|
|
|
|
// Now scale tile down to desired size, using mask as input
|
|
|
|
Bitmap bmScaled = TemplateTools.ScaleTemplateBitmap(bmTile, bmMask, cx, cx, nAreaBackgroundThreshold, nLuminanceMultBackground, nSaturationMultBackground, nLuminanceMultForeground, nSaturationMultForeground);
|
|
|
|
// Grab the data
|
|
|
|
for (int y = 0; y < cx; y++) {
|
|
for (int x = 0; x < cx; x++) {
|
|
alsColors.Add(bmScaled.GetPixel(x, y));
|
|
}
|
|
}
|
|
bmScaled.Dispose();
|
|
bmMask.Dispose();
|
|
}
|
|
} else {
|
|
// No background template; just scale
|
|
|
|
Bitmap bmTile = new Bitmap(sizTile.Width, sizTile.Height);
|
|
foreach (TileData td in m_alsTileData) {
|
|
// Need to turn data back into a bitmap - doh!
|
|
|
|
for (int y = 0; y < sizTile.Height; y++) {
|
|
for (int x = 0; x < sizTile.Width; x++) {
|
|
Color clr = (Color)td.aclr[y * sizTile.Width + x];
|
|
bmTile.SetPixel(x, y, clr);
|
|
}
|
|
}
|
|
|
|
// Now scale tile down to desired size, using mask as input
|
|
|
|
Bitmap bmScaled = TemplateTools.ScaleTemplateBitmap(bmTile, null, cx, cx, 1.0, 1.0, 1.0, 1.0, 1.0);
|
|
|
|
// Grab the data
|
|
|
|
for (int y = 0; y < cx; y++) {
|
|
for (int x = 0; x < cx; x++) {
|
|
alsColors.Add(bmScaled.GetPixel(x, y));
|
|
}
|
|
}
|
|
bmScaled.Dispose();
|
|
}
|
|
}
|
|
|
|
// Palette match and write results
|
|
|
|
foreach (Color clr in alsColors)
|
|
bwtr.Write((byte)pal.FindClosestEntry(clr));
|
|
}
|
|
|
|
byte[] GetTileBytes(int nTile) {
|
|
byte[] ab = new byte[m_sizTile.Width * m_sizTile.Height];
|
|
TileData tdata = (TileData)m_alsTileData[nTile];
|
|
for (int n = 0; n < tdata.aclr.Length; n++)
|
|
ab[n] = (byte)m_pal.FindClosestEntry(tdata.aclr[n]);
|
|
return ab;
|
|
}
|
|
|
|
public int Count {
|
|
get {
|
|
return m_alsTileData.Count;
|
|
}
|
|
}
|
|
|
|
public TileData GetTileData(int iTile) {
|
|
return (TileData)m_alsTileData[iTile];
|
|
}
|
|
}
|
|
}
|