diff --git a/Source/Builder.csproj b/Source/Builder.csproj
index 525c58da..4b733c10 100644
--- a/Source/Builder.csproj
+++ b/Source/Builder.csproj
@@ -650,6 +650,8 @@
+
+
diff --git a/Source/Data/DataManager.cs b/Source/Data/DataManager.cs
index fe554b13..4f9ca0cc 100644
--- a/Source/Data/DataManager.cs
+++ b/Source/Data/DataManager.cs
@@ -243,9 +243,11 @@ namespace CodeImp.DoomBuilder.Data
break;
}
}
- catch(Exception)
+ catch(Exception e)
{
// Unable to load resource
+ General.WriteLogLine("ERROR while creating data reader. " + e.GetType().Name + ": " + e.Message);
+ General.WriteLogLine(e.StackTrace);
General.ShowErrorMessage("Unable to load resources from location \"" + dl.location + "\". Please make sure the location is accessible and not in use by another program.", MessageBoxButtons.OK);
continue;
}
@@ -361,9 +363,11 @@ namespace CodeImp.DoomBuilder.Data
General.WriteLogLine("Resumed data resource '" + d.Location.location + "'");
d.Resume();
}
- catch(Exception)
+ catch(Exception e)
{
// Unable to load resource
+ General.WriteLogLine("ERROR while resuming data reader. " + e.GetType().Name + ": " + e.Message);
+ General.WriteLogLine(e.StackTrace);
General.ShowErrorMessage("Unable to load resources from location \"" + d.Location.location + "\". Please make sure the location is accessible and not in use by another program.", MessageBoxButtons.OK);
}
}
@@ -891,7 +895,7 @@ namespace CodeImp.DoomBuilder.Data
string[] files = Directory.GetFiles(General.SpritesPath, "*.png", SearchOption.TopDirectoryOnly);
foreach(string spritefile in files)
{
- ImageData img = new FileImage(Path.GetFileNameWithoutExtension(spritefile).ToLowerInvariant(), spritefile);
+ ImageData img = new FileImage(Path.GetFileNameWithoutExtension(spritefile).ToLowerInvariant(), spritefile, false);
img.LoadImage();
internalsprites.Add(img.Name, img);
}
diff --git a/Source/Data/DirectoryReader.cs b/Source/Data/DirectoryReader.cs
index 10401b0b..1383ca17 100644
--- a/Source/Data/DirectoryReader.cs
+++ b/Source/Data/DirectoryReader.cs
@@ -30,66 +30,17 @@ using CodeImp.DoomBuilder.IO;
namespace CodeImp.DoomBuilder.Data
{
- internal sealed class DirectoryReader : DataReader
+ internal sealed class DirectoryReader : PK3StructuredReader
{
- #region ================== Constants
-
- private const string PATCHES_DIR = "patches";
- private const string TEXTURES_DIR = "textures";
- private const string FLATS_DIR = "flats";
- private const string HIRES_DIR = "hires";
- private const string SPRITES_DIR = "sprites";
-
- #endregion
-
- #region ================== Variables
-
- // Source
- private bool roottextures;
- private bool rootflats;
-
- // Paths
- private string rootpath;
- private string patchespath;
- private string texturespath;
- private string flatspath;
- private string hirespath;
- private string spritespath;
-
- // WAD files that must be loaded as well
- private List wads;
-
- #endregion
-
- #region ================== Properties
-
- #endregion
-
#region ================== Constructor / Disposer
// Constructor
public DirectoryReader(DataLocation dl) : base(dl)
{
- // Initialize
- this.roottextures = dl.textures;
- this.rootflats = dl.flats;
- this.rootpath = dl.location;
- this.patchespath = Path.Combine(rootpath, PATCHES_DIR);
- this.texturespath = Path.Combine(rootpath, TEXTURES_DIR);
- this.flatspath = Path.Combine(rootpath, FLATS_DIR);
- this.hirespath = Path.Combine(rootpath, HIRES_DIR);
- this.spritespath = Path.Combine(rootpath, SPRITES_DIR);
-
General.WriteLogLine("Opening directory resource '" + location.location + "'");
- // Load all WAD files in the root as WAD resources
- string[] wadfiles = Directory.GetFiles(rootpath, "*.wad", SearchOption.TopDirectoryOnly);
- wads = new List(wadfiles.Length);
- foreach(string w in wadfiles)
- {
- DataLocation wdl = new DataLocation(DataLocation.RESOURCE_WAD, w, false, false);
- wads.Add(new WADReader(wdl));
- }
+ // Initialize
+ Initialize(dl.location);
// We have no destructor
GC.SuppressFinalize(this);
@@ -101,9 +52,6 @@ namespace CodeImp.DoomBuilder.Data
// Not already disposed?
if(!isdisposed)
{
- // Clean up
- foreach(WADReader wr in wads) wr.Dispose();
-
General.WriteLogLine("Closing directory resource '" + location.location + "'");
// Done
@@ -113,275 +61,62 @@ namespace CodeImp.DoomBuilder.Data
#endregion
- #region ================== Management
-
- // This suspends use of this resource
- public override void Suspend()
- {
- foreach(WADReader wr in wads) wr.Suspend();
- base.Suspend();
- }
-
- // This resumes use of this resource
- public override void Resume()
- {
- foreach(WADReader wr in wads) wr.Resume();
- base.Resume();
- }
-
- #endregion
-
- #region ================== Palette
-
- // This loads the PLAYPAL palette
- public override Playpal LoadPalette()
- {
- // Error when suspended
- if(issuspended) throw new Exception("Data reader is suspended");
-
- // Palette from wad(s)
- Playpal palette = null;
- foreach(WADReader wr in wads)
- {
- Playpal wadpalette = wr.LoadPalette();
- if(wadpalette != null) palette = wadpalette;
- }
-
- // Done
- return palette;
- }
-
- #endregion
-
- #region ================== Textures
-
- // This loads the textures
- public override ICollection LoadTextures(PatchNames pnames)
- {
- List images = new List();
- ICollection collection;
-
- // Error when suspended
- if(issuspended) throw new Exception("Data reader is suspended");
-
- // Load from wad files (NOTE: backward order, because the last wad's images have priority)
- for(int i = wads.Count - 1; i >= 0; i--)
- {
- collection = wads[i].LoadTextures(pnames);
- AddImagesToList(images, collection);
- }
-
- // Should we load the images in this directory as textures?
- if(roottextures)
- {
- collection = LoadDirectoryImages(rootpath);
- AddImagesToList(images, collection);
- }
-
- // TODO: Add support for hires texture here
-
- // Add images from texture directory
- collection = LoadDirectoryImages(texturespath);
- AddImagesToList(images, collection);
-
- return images;
- }
-
- // This returns the patch names from the PNAMES lump
- // A directory resource does not support this lump, but the wads in the directory may contain this lump
- public override PatchNames LoadPatchNames()
- {
- // Error when suspended
- if(issuspended) throw new Exception("Data reader is suspended");
-
- // Load from wad files (NOTE: backward order, because the last wad's images have priority)
- for(int i = wads.Count - 1; i >= 0; i--)
- {
- PatchNames pnames = wads[i].LoadPatchNames();
- if(pnames != null) return pnames;
- }
-
- return null;
- }
-
- // This finds and returns a patch stream
- public override Stream GetPatchData(string pname)
- {
- string filename;
-
- // Error when suspended
- if(issuspended) throw new Exception("Data reader is suspended");
-
- // Find in any of the wad files
- for(int i = wads.Count - 1; i >= 0; i--)
- {
- Stream data = wads[i].GetPatchData(pname);
- if(data != null) return data;
- }
-
- // Find in patches directory
- string datafile = null;
- filename = Path.Combine(patchespath, pname + ".bmp");
- if(File.Exists(filename)) datafile = filename;
- filename = Path.Combine(patchespath, pname + ".gif");
- if(File.Exists(filename)) datafile = filename;
- filename = Path.Combine(patchespath, pname + ".png");
- if(File.Exists(filename)) datafile = filename;
- filename = Path.Combine(patchespath, pname);
- if(File.Exists(filename)) datafile = filename;
-
- // Found anything?
- if(datafile != null)
- {
- byte[] filedata = File.ReadAllBytes(datafile);
- MemoryStream mem = new MemoryStream(filedata);
- return mem;
- }
-
- // Nothing found
- return null;
- }
-
- #endregion
-
- #region ================== Flats
-
- // This loads the textures
- public override ICollection LoadFlats()
- {
- List images = new List();
- ICollection collection;
-
- // Error when suspended
- if(issuspended) throw new Exception("Data reader is suspended");
-
- // Load from wad files (NOTE: backward order, because the last wad's images have priority)
- for(int i = wads.Count - 1; i >= 0; i--)
- {
- collection = wads[i].LoadFlats();
- AddImagesToList(images, collection);
- }
-
- // Should we load the images in this directory as flats?
- if(rootflats)
- {
- collection = LoadDirectoryImages(rootpath);
- AddImagesToList(images, collection);
- }
-
- // Add images from flats directory
- collection = LoadDirectoryImages(flatspath);
- AddImagesToList(images, collection);
-
- return images;
- }
-
- #endregion
-
- #region ================== Sprites
-
- // This finds and returns a sprite stream
- public override Stream GetSpriteData(string pname)
- {
- string pfilename = pname.Replace('\\', '^');
- string filename;
-
- // Error when suspended
- if(issuspended) throw new Exception("Data reader is suspended");
-
- // Find in any of the wad files
- for(int i = wads.Count - 1; i >= 0; i--)
- {
- Stream sprite = wads[i].GetSpriteData(pname);
- if(sprite != null) return sprite;
- }
-
- // Find in sprites directory
- string spritefoundfile = null;
- filename = Path.Combine(spritespath, pfilename + ".bmp");
- if(File.Exists(filename)) spritefoundfile = filename;
- filename = Path.Combine(spritespath, pfilename + ".gif");
- if(File.Exists(filename)) spritefoundfile = filename;
- filename = Path.Combine(spritespath, pfilename + ".png");
- if(File.Exists(filename)) spritefoundfile = filename;
-
- // Found anything?
- if(spritefoundfile != null)
- {
- byte[] filedata = File.ReadAllBytes(spritefoundfile);
- MemoryStream mem = new MemoryStream(filedata);
- return mem;
- }
-
- // Nothing found
- return null;
- }
-
- #endregion
-
#region ================== Methods
- // This loads the images in this directory
- private ICollection LoadDirectoryImages(string path)
+ // This creates an image
+ protected override ImageData CreateImage(string name, string filename, bool flat)
{
- List images = new List();
- string[] files;
- string name;
+ return new FileImage(name, filename, flat);
+ }
- // Find all BMP files
- files = Directory.GetFiles(path, "*.bmp", SearchOption.TopDirectoryOnly);
+ // This returns true if the specified file exists
+ protected override bool FileExists(string filename)
+ {
+ return File.Exists(filename);
+ }
+
+ // This returns all files in a given directory
+ protected override string[] GetAllFiles(string path)
+ {
+ return Directory.GetFiles(path, "*", SearchOption.TopDirectoryOnly);
+ }
- // Find all GIF files and append to files array
- AddToArray(ref files, Directory.GetFiles(path, "*.gif", SearchOption.TopDirectoryOnly));
+ // This returns all files in a given directory that match the given extension
+ protected override string[] GetFilesWithExt(string path, string extension)
+ {
+ return Directory.GetFiles(path, "*." + extension, SearchOption.TopDirectoryOnly);
+ }
- // Find all PNG files and append to files array
- AddToArray(ref files, Directory.GetFiles(path, "*.png", SearchOption.TopDirectoryOnly));
-
- // Go for all files
+ // This finds the first file that has the specific name, regardless of file extension
+ protected override string FindFirstFile(string path, string beginswith)
+ {
+ string[] files = GetAllFiles(path);
foreach(string f in files)
{
- // Make the texture name from filename without extension
- name = Path.GetFileNameWithoutExtension(f).ToUpperInvariant();
- if(name.Length > 8) name = name.Substring(0, 8);
-
- // Add image to list
- images.Add(new FileImage(name, f));
+ if(string.Compare(Path.GetFileNameWithoutExtension(f), beginswith, true) == 0)
+ return f;
}
- // Return result
- return images;
+ return null;
}
- // This resizes a string array and adds to it
- private void AddToArray(ref string[] array, string[] add)
+ // This loads an entire file in memory and returns the stream
+ // NOTE: Callers are responsible for disposing the stream!
+ protected override MemoryStream LoadFile(string filename)
{
- int insertindex = array.Length;
- Array.Resize(ref array, array.Length + add.Length);
- add.CopyTo(array, insertindex);
+ return new MemoryStream(File.ReadAllBytes(filename));
}
-
- // This copies images from a collection unless they already exist in the list
- private void AddImagesToList(List targetlist, ICollection sourcelist)
+
+ // This creates a temp file for the speciied file and return the absolute path to the temp file
+ // NOTE: Callers are responsible for removing the temp file when done!
+ protected override string CreateTempFile(string filename)
{
- // Go for all source images
- foreach(ImageData src in sourcelist)
- {
- // Check if exists in target list
- bool alreadyexists = false;
- foreach(ImageData tgt in targetlist)
- {
- if(tgt.LongName == src.LongName)
- {
- alreadyexists = true;
- break;
- }
- }
-
- // Add source image to target list
- if(!alreadyexists) targetlist.Add(src);
- }
+ // Just copy the file
+ string tempfile = General.MakeTempFilename(General.Map.TempPath, "wad");
+ File.Copy(filename, tempfile);
+ return tempfile;
}
-
+
#endregion
}
}
diff --git a/Source/Data/FileImage.cs b/Source/Data/FileImage.cs
index 007ab89a..79d8bd06 100644
--- a/Source/Data/FileImage.cs
+++ b/Source/Data/FileImage.cs
@@ -24,6 +24,7 @@ using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
+using CodeImp.DoomBuilder.IO;
#endregion
@@ -34,34 +35,56 @@ namespace CodeImp.DoomBuilder.Data
#region ================== Variables
private string filepathname;
+ private int probableformat;
+ private float scalex;
+ private float scaley;
#endregion
#region ================== Constructor / Disposer
// Constructor
- public FileImage(string name, string filepathname)
+ public FileImage(string name, string filepathname, bool asflat)
{
// Initialize
this.filepathname = filepathname;
SetName(name);
- // Temporarily load file
- Bitmap bmp = (Bitmap)Bitmap.FromFile(filepathname);
-
- // Get width and height from image
- width = bmp.Size.Width;
- height = bmp.Size.Height;
- scaledwidth = (float)bmp.Size.Width * General.Map.Config.DefaultTextureScale;
- scaledheight = (float)bmp.Size.Height * General.Map.Config.DefaultTextureScale;
-
- // Unload file
- bmp.Dispose();
+ if(asflat)
+ {
+ probableformat = ImageDataFormat.DOOMFLAT;
+ scalex = General.Map.Config.DefaultFlatScale;
+ scaley = General.Map.Config.DefaultFlatScale;
+ }
+ else
+ {
+ probableformat = ImageDataFormat.DOOMPICTURE;
+ scalex = General.Map.Config.DefaultTextureScale;
+ scaley = General.Map.Config.DefaultTextureScale;
+ }
// We have no destructor
GC.SuppressFinalize(this);
}
+ // Constructor
+ public FileImage(string name, string filepathname, bool asflat, float scalex, float scaley)
+ {
+ // Initialize
+ this.filepathname = filepathname;
+ this.scalex = scalex;
+ this.scaley = scaley;
+ SetName(name);
+
+ if(asflat)
+ probableformat = ImageDataFormat.DOOMFLAT;
+ else
+ probableformat = ImageDataFormat.DOOMPICTURE;
+
+ // We have no destructor
+ GC.SuppressFinalize(this);
+ }
+
#endregion
#region ================== Methods
@@ -74,17 +97,41 @@ namespace CodeImp.DoomBuilder.Data
lock(this)
{
- // Load file
- if(bitmap != null) bitmap.Dispose();
- bitmap = (Bitmap)Bitmap.FromFile(filepathname);
+ // Load file data
+ if(bitmap != null) bitmap.Dispose(); bitmap = null;
+ MemoryStream filedata = new MemoryStream(File.ReadAllBytes(filepathname));
+
+ // Get a reader for the data
+ IImageReader reader = ImageDataFormat.GetImageReader(filedata, probableformat, General.Map.Data.Palette);
+ if(!(reader is UnknownImageReader))
+ {
+ // Load the image
+ filedata.Seek(0, SeekOrigin.Begin);
+ try { bitmap = reader.ReadAsBitmap(filedata); }
+ catch(InvalidDataException)
+ {
+ // Data cannot be read!
+ bitmap = null;
+ }
+ }
+
+ // Not loaded?
+ if(bitmap == null)
+ {
+ General.WriteLogLine("WARNING: Image file '" + filepathname + "' data format could not be read, while loading texture '" + this.Name + "'!");
+ loadfailed = true;
+ filedata.Dispose();
+ return;
+ }
// Get width and height from image
width = bitmap.Size.Width;
height = bitmap.Size.Height;
- scaledwidth = (float)bitmap.Size.Width * General.Map.Config.DefaultTextureScale;
- scaledheight = (float)bitmap.Size.Height * General.Map.Config.DefaultTextureScale;
+ scaledwidth = (float)bitmap.Size.Width * scalex;
+ scaledheight = (float)bitmap.Size.Height * scaley;
// Pass on to base
+ filedata.Dispose();
base.LocalLoadImage();
}
}
diff --git a/Source/Data/ImageData.cs b/Source/Data/ImageData.cs
index f3fe7918..dba20108 100644
--- a/Source/Data/ImageData.cs
+++ b/Source/Data/ImageData.cs
@@ -192,7 +192,7 @@ namespace CodeImp.DoomBuilder.Data
int oldheight = height;
float oldscaledwidth = scaledwidth;
float oldscaledheight = scaledheight;
-
+
// Do the loading
LocalLoadImage();
diff --git a/Source/Data/PK3FileImage.cs b/Source/Data/PK3FileImage.cs
new file mode 100644
index 00000000..2aa366d8
--- /dev/null
+++ b/Source/Data/PK3FileImage.cs
@@ -0,0 +1,125 @@
+
+#region ================== Copyright (c) 2007 Pascal vd Heiden
+
+/*
+ * Copyright (c) 2007 Pascal vd Heiden, www.codeimp.com
+ * This program is released under GNU General Public License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#endregion
+
+#region ================== Namespaces
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Text;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.IO;
+using CodeImp.DoomBuilder.IO;
+
+#endregion
+
+namespace CodeImp.DoomBuilder.Data
+{
+ public sealed class PK3FileImage : ImageData
+ {
+ #region ================== Variables
+
+ private PK3Reader datareader;
+ private string filepathname;
+ private int probableformat;
+ private float scalex;
+ private float scaley;
+
+ #endregion
+
+ #region ================== Constructor / Disposer
+
+ // Constructor
+ internal PK3FileImage(PK3Reader datareader, string name, string filepathname, bool asflat)
+ {
+ // Initialize
+ this.datareader = datareader;
+ this.filepathname = filepathname;
+ SetName(name);
+
+ if(asflat)
+ {
+ probableformat = ImageDataFormat.DOOMFLAT;
+ scalex = General.Map.Config.DefaultFlatScale;
+ scaley = General.Map.Config.DefaultFlatScale;
+ }
+ else
+ {
+ probableformat = ImageDataFormat.DOOMPICTURE;
+ scalex = General.Map.Config.DefaultTextureScale;
+ scaley = General.Map.Config.DefaultTextureScale;
+ }
+
+ // We have no destructor
+ GC.SuppressFinalize(this);
+ }
+
+ #endregion
+
+ #region ================== Methods
+
+ // This loads the image
+ protected override void LocalLoadImage()
+ {
+ // Leave when already loaded
+ if(this.IsImageLoaded) return;
+
+ lock(this)
+ {
+ // Load file data
+ if(bitmap != null) bitmap.Dispose(); bitmap = null;
+ MemoryStream filedata = datareader.ExtractFile(filepathname);
+
+ // Get a reader for the data
+ IImageReader reader = ImageDataFormat.GetImageReader(filedata, probableformat, General.Map.Data.Palette);
+ if(!(reader is UnknownImageReader))
+ {
+ // Load the image
+ filedata.Seek(0, SeekOrigin.Begin);
+ try { bitmap = reader.ReadAsBitmap(filedata); }
+ catch(InvalidDataException)
+ {
+ // Data cannot be read!
+ bitmap = null;
+ }
+ }
+
+ // Not loaded?
+ if(bitmap == null)
+ {
+ General.WriteLogLine("WARNING: Image file '" + filepathname + "' data format could not be read, while loading texture '" + this.Name + "'!");
+ loadfailed = true;
+ filedata.Dispose();
+ return;
+ }
+
+ // Get width and height from image
+ width = bitmap.Size.Width;
+ height = bitmap.Size.Height;
+ scaledwidth = (float)bitmap.Size.Width * scalex;
+ scaledheight = (float)bitmap.Size.Height * scaley;
+
+ // Pass on to base
+ filedata.Dispose();
+ base.LocalLoadImage();
+ }
+ }
+
+ #endregion
+ }
+}
diff --git a/Source/Data/PK3Reader.cs b/Source/Data/PK3Reader.cs
index 0e0dc517..a9e2b953 100644
--- a/Source/Data/PK3Reader.cs
+++ b/Source/Data/PK3Reader.cs
@@ -31,17 +31,11 @@ using ICSharpCode.SharpZipLib.Zip;
namespace CodeImp.DoomBuilder.Data
{
- internal sealed class PK3Reader : DataReader
+ internal sealed class PK3Reader : PK3StructuredReader
{
- #region ================== Constants
-
- #endregion
-
#region ================== Variables
- #endregion
-
- #region ================== Properties
+ private List fileslist;
#endregion
@@ -50,21 +44,29 @@ namespace CodeImp.DoomBuilder.Data
// Constructor
public PK3Reader(DataLocation dl) : base(dl)
{
- // Initialize
General.WriteLogLine("Opening PK3 resource '" + location.location + "'");
-
- //TEST
- /*
- ZipInputStream z = new ZipInputStream(File.Open(dl.location, FileMode.Open, FileAccess.Read, FileShare.ReadWrite));
- ZipEntry ze;
- while((ze = z.GetNextEntry()) != null)
- {
- General.WriteLogLine(ze.Name);
-
- }
- z.Dispose();
- */
+ // Open the zip file
+ ZipInputStream zipstream = OpenPK3File();
+
+ // Make list of all files
+ fileslist = new List();
+ ZipEntry entry = zipstream.GetNextEntry();
+ while(entry != null)
+ {
+ if(entry.IsFile) fileslist.Add(entry.Name.ToLowerInvariant());
+
+ // Next
+ entry = zipstream.GetNextEntry();
+ }
+
+ // Done with the zip file
+ zipstream.Close();
+ zipstream.Dispose();
+
+ // Initialize without path (because we use paths relative to the PK3 file)
+ Initialize("");
+
// We have no destructor
GC.SuppressFinalize(this);
}
@@ -76,9 +78,7 @@ namespace CodeImp.DoomBuilder.Data
if(!isdisposed)
{
General.WriteLogLine("Closing PK3 resource '" + location.location + "'");
-
- // Clean up
-
+
// Done
base.Dispose();
}
@@ -86,22 +86,148 @@ namespace CodeImp.DoomBuilder.Data
#endregion
- #region ================== Palette
+ #region ================== Management
- // This loads the PLAYPAL palette
- public override Playpal LoadPalette()
+ // This opens the zip file for reading
+ private ZipInputStream OpenPK3File()
{
- // Error when suspended
- if(issuspended) throw new Exception("Data reader is suspended");
-
- // Not yet implemented
- return null;
+ FileStream filestream = File.Open(location.location, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
+ filestream.Seek(0, SeekOrigin.Begin);
+ return new ZipInputStream(filestream);
}
#endregion
+
+ #region ================== Methods
+
+ // This creates an image
+ protected override ImageData CreateImage(string name, string filename, bool flat)
+ {
+ return new PK3FileImage(this, name, filename, flat);
+ }
- #region ================== Textures
+ // This returns true if the specified file exists
+ protected override bool FileExists(string filename)
+ {
+ string lowfile = filename.ToLowerInvariant();
+ foreach(string f in fileslist)
+ {
+ if((string.Compare(f, lowfile) == 0)) return true;
+ }
+ return false;
+ }
+
+ // This returns all files in a given directory
+ protected override string[] GetAllFiles(string path)
+ {
+ List matches = new List();
+ string lowpath = path.ToLowerInvariant();
+ foreach(string f in fileslist)
+ {
+ if((string.Compare(Path.GetDirectoryName(f), lowpath) == 0) &&
+ (Path.GetFileName(f).Length > 0))
+ matches.Add(f);
+ }
+
+ return matches.ToArray();
+ }
+
+ // This returns all files in a given directory that match the given extension
+ protected override string[] GetFilesWithExt(string path, string extension)
+ {
+ List matches = new List();
+ string lowpath = path.ToLowerInvariant();
+ string lowext = "." + extension.ToLowerInvariant();
+ foreach(string f in fileslist)
+ {
+ if((string.Compare(Path.GetDirectoryName(f), lowpath) == 0) && f.EndsWith(lowext))
+ matches.Add(f);
+ }
+
+ return matches.ToArray();
+ }
+
+ // This finds the first file that has the specific name, regardless of file extension
+ protected override string FindFirstFile(string path, string beginswith)
+ {
+ string lowpath = path.ToLowerInvariant();
+ string lowbegin = beginswith.ToLowerInvariant();
+ foreach(string f in fileslist)
+ {
+ if((string.Compare(Path.GetDirectoryName(f), lowpath) == 0) &&
+ (string.Compare(Path.GetFileNameWithoutExtension(f), lowbegin) == 0))
+ return f;
+ }
+
+ return null;
+ }
+
+ // This loads an entire file in memory and returns the stream
+ // NOTE: Callers are responsible for disposing the stream!
+ protected override MemoryStream LoadFile(string filename)
+ {
+ MemoryStream filedata = null;
+ byte[] copybuffer = new byte[4096];
+
+ // Open the zip file
+ ZipInputStream zipstream = OpenPK3File();
+
+ ZipEntry entry = zipstream.GetNextEntry();
+ while(entry != null)
+ {
+ // Is this the entry we are looking for?
+ if(string.Compare(entry.Name, filename, true) == 0)
+ {
+ int expectedsize = (int)entry.Size;
+ if(expectedsize < 1) expectedsize = 1024;
+ filedata = new MemoryStream(expectedsize);
+ int readsize = zipstream.Read(copybuffer, 0, copybuffer.Length);
+ while(readsize > 0)
+ {
+ filedata.Write(copybuffer, 0, readsize);
+ readsize = zipstream.Read(copybuffer, 0, copybuffer.Length);
+ }
+ break;
+ }
+
+ // Next
+ entry = zipstream.GetNextEntry();
+ }
+
+ // Done with the zip file
+ zipstream.Close();
+ zipstream.Dispose();
+
+ // Nothing found?
+ if(filedata == null)
+ {
+ throw new FileNotFoundException("Cannot find the file " + filename + " in PK3 file " + location.location + ".");
+ }
+ else
+ {
+ return filedata;
+ }
+ }
+
+ // This creates a temp file for the speciied file and return the absolute path to the temp file
+ // NOTE: Callers are responsible for removing the temp file when done!
+ protected override string CreateTempFile(string filename)
+ {
+ // Just copy the file
+ string tempfile = General.MakeTempFilename(General.Map.TempPath, "wad");
+ MemoryStream filedata = LoadFile(filename);
+ File.WriteAllBytes(tempfile, filedata.ToArray());
+ filedata.Dispose();
+ return tempfile;
+ }
+
+ // Public version to load a file
+ internal MemoryStream ExtractFile(string filename)
+ {
+ return LoadFile(filename);
+ }
+
#endregion
}
}
diff --git a/Source/Data/PK3StructuredReader.cs b/Source/Data/PK3StructuredReader.cs
new file mode 100644
index 00000000..721f3b56
--- /dev/null
+++ b/Source/Data/PK3StructuredReader.cs
@@ -0,0 +1,413 @@
+
+#region ================== Copyright (c) 2007 Pascal vd Heiden
+
+/*
+ * Copyright (c) 2007 Pascal vd Heiden, www.codeimp.com
+ * This program is released under GNU General Public License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#endregion
+
+#region ================== Namespaces
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Text;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.IO;
+using CodeImp.DoomBuilder.IO;
+
+#endregion
+
+namespace CodeImp.DoomBuilder.Data
+{
+ internal abstract class PK3StructuredReader : DataReader
+ {
+ #region ================== Constants
+
+ private const string PATCHES_DIR = "patches";
+ private const string TEXTURES_DIR = "textures";
+ private const string FLATS_DIR = "flats";
+ private const string HIRES_DIR = "hires";
+ private const string SPRITES_DIR = "sprites";
+
+ #endregion
+
+ #region ================== Variables
+
+ // Source
+ private bool roottextures;
+ private bool rootflats;
+
+ // Paths
+ protected string rootpath;
+ protected string patchespath;
+ protected string texturespath;
+ protected string flatspath;
+ protected string hirespath;
+ protected string spritespath;
+
+ // WAD files that must be loaded as well
+ private List wads;
+
+ #endregion
+
+ #region ================== Properties
+
+ #endregion
+
+ #region ================== Constructor / Disposer
+
+ // Constructor
+ public PK3StructuredReader(DataLocation dl) : base(dl)
+ {
+ // Initialize
+ this.roottextures = dl.textures;
+ this.rootflats = dl.flats;
+ }
+
+ // Call this to initialize this class
+ protected virtual void Initialize(string rootpath)
+ {
+ // Initialize
+ this.rootpath = rootpath;
+ this.patchespath = Path.Combine(rootpath, PATCHES_DIR);
+ this.texturespath = Path.Combine(rootpath, TEXTURES_DIR);
+ this.flatspath = Path.Combine(rootpath, FLATS_DIR);
+ this.hirespath = Path.Combine(rootpath, HIRES_DIR);
+ this.spritespath = Path.Combine(rootpath, SPRITES_DIR);
+
+ // Load all WAD files in the root as WAD resources
+ string[] wadfiles = GetFilesWithExt(rootpath, "wad");
+ wads = new List(wadfiles.Length);
+ foreach(string w in wadfiles)
+ {
+ string tempfile = CreateTempFile(w);
+ DataLocation wdl = new DataLocation(DataLocation.RESOURCE_WAD, tempfile, false, false);
+ wads.Add(new WADReader(wdl));
+ }
+ }
+
+ // Disposer
+ public override void Dispose()
+ {
+ // Not already disposed?
+ if(!isdisposed)
+ {
+ // Clean up
+ foreach(WADReader wr in wads) wr.Dispose();
+
+ // Remove temp files
+ foreach(WADReader wr in wads)
+ {
+ try { File.Delete(wr.Location.location); }
+ catch(Exception) { }
+ }
+
+ // Done
+ base.Dispose();
+ }
+ }
+
+ #endregion
+
+ #region ================== Management
+
+ // This suspends use of this resource
+ public override void Suspend()
+ {
+ foreach(WADReader wr in wads) wr.Suspend();
+ base.Suspend();
+ }
+
+ // This resumes use of this resource
+ public override void Resume()
+ {
+ foreach(WADReader wr in wads) wr.Resume();
+ base.Resume();
+ }
+
+ #endregion
+
+ #region ================== Palette
+
+ // This loads the PLAYPAL palette
+ public override Playpal LoadPalette()
+ {
+ // Error when suspended
+ if(issuspended) throw new Exception("Data reader is suspended");
+
+ // Palette from wad(s)
+ Playpal palette = null;
+ foreach(WADReader wr in wads)
+ {
+ Playpal wadpalette = wr.LoadPalette();
+ if(wadpalette != null) palette = wadpalette;
+ }
+
+ // Done
+ return palette;
+ }
+
+ #endregion
+
+ #region ================== Textures
+
+ // This loads the textures
+ public override ICollection LoadTextures(PatchNames pnames)
+ {
+ List images = new List();
+ ICollection collection;
+
+ // Error when suspended
+ if(issuspended) throw new Exception("Data reader is suspended");
+
+ // Load from wad files (NOTE: backward order, because the last wad's images have priority)
+ for(int i = wads.Count - 1; i >= 0; i--)
+ {
+ collection = wads[i].LoadTextures(pnames);
+ AddImagesToList(images, collection);
+ }
+
+ // Should we load the images in this directory as textures?
+ if(roottextures)
+ {
+ collection = LoadDirectoryImages(rootpath, false);
+ AddImagesToList(images, collection);
+ }
+
+ // TODO: Add support for hires texture here
+
+ // Add images from texture directory
+ collection = LoadDirectoryImages(texturespath, false);
+ AddImagesToList(images, collection);
+
+ // Load TEXTURE1 lump file
+ List imgset = new List();
+ string texture1file = FindFirstFile(rootpath, "TEXTURE1");
+ if((texture1file != null) && FileExists(texture1file))
+ {
+ MemoryStream filedata = LoadFile(texture1file);
+ WADReader.LoadTextureSet(filedata, ref imgset, pnames);
+ filedata.Dispose();
+ }
+
+ // Load TEXTURE2 lump file
+ string texture2file = FindFirstFile(rootpath, "TEXTURE2");
+ if((texture2file != null) && FileExists(texture2file))
+ {
+ MemoryStream filedata = LoadFile(texture2file);
+ WADReader.LoadTextureSet(filedata, ref imgset, pnames);
+ filedata.Dispose();
+ }
+
+ // Add images from TEXTURE1 and TEXTURE2 lump files
+ AddImagesToList(images, imgset);
+
+ return images;
+ }
+
+ // This returns the patch names from the PNAMES lump
+ // A directory resource does not support this lump, but the wads in the directory may contain this lump
+ public override PatchNames LoadPatchNames()
+ {
+ PatchNames pnames;
+
+ // Error when suspended
+ if(issuspended) throw new Exception("Data reader is suspended");
+
+ // Load from wad files
+ // Note the backward order, because the last wad's images have priority
+ for(int i = wads.Count - 1; i >= 0; i--)
+ {
+ pnames = wads[i].LoadPatchNames();
+ if(pnames != null) return pnames;
+ }
+
+ // If none of the wads provides patch names, let's see if we can
+ string pnamesfile = FindFirstFile(rootpath, "PNAMES");
+ if((pnamesfile != null) && FileExists(pnamesfile))
+ {
+ MemoryStream pnamesdata = LoadFile(pnamesfile);
+ pnames = new PatchNames(pnamesdata);
+ pnamesdata.Dispose();
+ return pnames;
+ }
+
+ return null;
+ }
+
+ // This finds and returns a patch stream
+ public override Stream GetPatchData(string pname)
+ {
+ // Error when suspended
+ if(issuspended) throw new Exception("Data reader is suspended");
+
+ // Find in any of the wad files
+ // Note the backward order, because the last wad's images have priority
+ for(int i = wads.Count - 1; i >= 0; i--)
+ {
+ Stream data = wads[i].GetPatchData(pname);
+ if(data != null) return data;
+ }
+
+ // Find in patches directory
+ string filename = FindFirstFile(patchespath, pname);
+ if((filename != null) && FileExists(filename))
+ {
+ return LoadFile(filename);
+ }
+
+ // Nothing found
+ return null;
+ }
+
+ #endregion
+
+ #region ================== Flats
+
+ // This loads the textures
+ public override ICollection LoadFlats()
+ {
+ List images = new List();
+ ICollection collection;
+
+ // Error when suspended
+ if(issuspended) throw new Exception("Data reader is suspended");
+
+ // Load from wad files
+ // Note the backward order, because the last wad's images have priority
+ for(int i = wads.Count - 1; i >= 0; i--)
+ {
+ collection = wads[i].LoadFlats();
+ AddImagesToList(images, collection);
+ }
+
+ // Should we load the images in this directory as flats?
+ if(rootflats)
+ {
+ collection = LoadDirectoryImages(rootpath, true);
+ AddImagesToList(images, collection);
+ }
+
+ // Add images from flats directory
+ collection = LoadDirectoryImages(flatspath, true);
+ AddImagesToList(images, collection);
+
+ return images;
+ }
+
+ #endregion
+
+ #region ================== Sprites
+
+ // This finds and returns a sprite stream
+ public override Stream GetSpriteData(string pname)
+ {
+ string pfilename = pname.Replace('\\', '^');
+
+ // Error when suspended
+ if(issuspended) throw new Exception("Data reader is suspended");
+
+ // Find in any of the wad files
+ for(int i = wads.Count - 1; i >= 0; i--)
+ {
+ Stream sprite = wads[i].GetSpriteData(pname);
+ if(sprite != null) return sprite;
+ }
+
+ // Find in sprites directory
+ string filename = FindFirstFile(spritespath, pfilename);
+ if((filename != null) && FileExists(filename))
+ {
+ return LoadFile(filename);
+ }
+
+ // Nothing found
+ return null;
+ }
+
+ #endregion
+
+ #region ================== Methods
+
+ // This loads the images in this directory
+ private ICollection LoadDirectoryImages(string path, bool flats)
+ {
+ List images = new List();
+ string[] files;
+ string name;
+
+ // Go for all files
+ files = GetAllFiles(path);
+ foreach(string f in files)
+ {
+ // Make the texture name from filename without extension
+ name = Path.GetFileNameWithoutExtension(f).ToUpperInvariant();
+ if(name.Length > 8) name = name.Substring(0, 8);
+
+ // Add image to list
+ images.Add(CreateImage(name, f, flats));
+ }
+
+ // Return result
+ return images;
+ }
+
+ // This copies images from a collection unless they already exist in the list
+ private void AddImagesToList(List targetlist, ICollection sourcelist)
+ {
+ // Go for all source images
+ foreach(ImageData src in sourcelist)
+ {
+ // Check if exists in target list
+ bool alreadyexists = false;
+ foreach(ImageData tgt in targetlist)
+ {
+ if(tgt.LongName == src.LongName)
+ {
+ alreadyexists = true;
+ break;
+ }
+ }
+
+ // Add source image to target list
+ if(!alreadyexists) targetlist.Add(src);
+ }
+ }
+
+ // This must create an image
+ protected abstract ImageData CreateImage(string name, string filename, bool flat);
+
+ // This must return true if the specified file exists
+ protected abstract bool FileExists(string filename);
+
+ // This must return all files in a given directory
+ protected abstract string[] GetAllFiles(string path);
+
+ // This must return all files in a given directory that match the given extension
+ protected abstract string[] GetFilesWithExt(string path, string extension);
+
+ // This must find the first file that has the specific name, regardless of file extension
+ protected abstract string FindFirstFile(string path, string beginswith);
+
+ // This must load an entire file in memory and returns the stream
+ // NOTE: Callers are responsible for disposing the stream!
+ protected abstract MemoryStream LoadFile(string filename);
+
+ // This must create a temp file for the speciied file and return the absolute path to the temp file
+ // NOTE: Callers are responsible for removing the temp file when done!
+ protected abstract string CreateTempFile(string filename);
+
+ #endregion
+ }
+}
diff --git a/Source/Data/SimpleTextureImage.cs b/Source/Data/SimpleTextureImage.cs
index 02676b1f..5678a31b 100644
--- a/Source/Data/SimpleTextureImage.cs
+++ b/Source/Data/SimpleTextureImage.cs
@@ -80,6 +80,7 @@ namespace CodeImp.DoomBuilder.Data
lock(this)
{
// Get the patch data stream
+ if(bitmap != null) bitmap.Dispose(); bitmap = null;
patchdata = General.Map.Data.GetPatchData(lumpname);
if(patchdata != null)
{
@@ -92,16 +93,31 @@ namespace CodeImp.DoomBuilder.Data
// Get a reader for the data
reader = ImageDataFormat.GetImageReader(mem, ImageDataFormat.DOOMPICTURE, General.Map.Data.Palette);
- if(reader is UnknownImageReader)
+ if(!(reader is UnknownImageReader))
{
- // Data is in an unknown format!
- General.WriteLogLine("WARNING: Image lump '" + lumpname + "' data format could not be read, while loading texture '" + this.Name + "'!");
+ // Load the image
+ mem.Seek(0, SeekOrigin.Begin);
+ try { bitmap = reader.ReadAsBitmap(mem); }
+ catch(InvalidDataException)
+ {
+ // Data cannot be read!
+ bitmap = null;
+ }
}
- // Load the image
- mem.Seek(0, SeekOrigin.Begin);
- bitmap = reader.ReadAsBitmap(mem);
- if(bitmap == null) return;
+ // Not loaded?
+ if(bitmap == null)
+ {
+ General.WriteLogLine("WARNING: Image lump '" + lumpname + "' data format could not be read, while loading texture '" + this.Name + "'!");
+ loadfailed = true;
+ return;
+ }
+
+ // Get width and height from image
+ width = bitmap.Size.Width;
+ height = bitmap.Size.Height;
+ scaledwidth = (float)width * scalex;
+ scaledheight = (float)height * scaley;
// Done
mem.Dispose();
diff --git a/Source/Data/WADReader.cs b/Source/Data/WADReader.cs
index 0a5aeea6..8e8967cc 100644
--- a/Source/Data/WADReader.cs
+++ b/Source/Data/WADReader.cs
@@ -201,7 +201,7 @@ namespace CodeImp.DoomBuilder.Data
}
// This loads a set of textures
- private void LoadTextureSet(Stream texturedata, ref List images, PatchNames pnames)
+ public static void LoadTextureSet(Stream texturedata, ref List images, PatchNames pnames)
{
BinaryReader reader = new BinaryReader(texturedata);
int flags, width, height, patches, px, py, pi;
diff --git a/Source/Editing/GridSetup.cs b/Source/Editing/GridSetup.cs
index 3d1b8f23..0c6be244 100644
--- a/Source/Editing/GridSetup.cs
+++ b/Source/Editing/GridSetup.cs
@@ -176,7 +176,7 @@ namespace CodeImp.DoomBuilder.Editing
break;
case SOURCE_FILE:
- backimage = new FileImage(background, background);
+ backimage = new FileImage(background, background, false, 1.0f, 1.0f);
break;
}
diff --git a/Source/General/General.cs b/Source/General/General.cs
index 0ebe3baf..d5a2ad56 100644
--- a/Source/General/General.cs
+++ b/Source/General/General.cs
@@ -56,7 +56,7 @@ namespace CodeImp.DoomBuilder
internal static extern void ZeroMemory(IntPtr dest, int size);
[DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory", SetLastError = false)]
- internal static extern unsafe void CopyMemory(void* dst, void* src, UIntPtr length);
+ internal static extern unsafe void CopyMemory(void* dst, void* src, uint length);
[DllImport("user32.dll", EntryPoint = "SendMessage", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
internal static extern int SendMessage(IntPtr hwnd, uint Msg, int wParam, int lParam);
diff --git a/Source/IO/DoomFlatReader.cs b/Source/IO/DoomFlatReader.cs
index cd42e7ff..bbc0456b 100644
--- a/Source/IO/DoomFlatReader.cs
+++ b/Source/IO/DoomFlatReader.cs
@@ -103,7 +103,7 @@ namespace CodeImp.DoomBuilder.IO
targetdata = (PixelColor*)bitmapdata.Scan0.ToPointer();
// Copy the pixels
- General.CopyMemory((void*)targetdata, (void*)pixeldata.Pointer, new UIntPtr((uint)(width * height * sizeof(PixelColor))));
+ General.CopyMemory(targetdata, pixeldata.Pointer, (uint)(width * height * sizeof(PixelColor)));
// Done
bmp.UnlockBits(bitmapdata);
diff --git a/Source/IO/DoomPictureReader.cs b/Source/IO/DoomPictureReader.cs
index cc27a6ab..f8eae896 100644
--- a/Source/IO/DoomPictureReader.cs
+++ b/Source/IO/DoomPictureReader.cs
@@ -119,7 +119,7 @@ namespace CodeImp.DoomBuilder.IO
targetdata = (PixelColor*)bitmapdata.Scan0.ToPointer();
// Copy the pixels
- General.CopyMemory((void*)targetdata, (void*)pixeldata.Pointer, new UIntPtr((uint)(width * height * sizeof(PixelColor))));
+ General.CopyMemory(targetdata, pixeldata.Pointer, (uint)(width * height * sizeof(PixelColor)));
// Done
bmp.UnlockBits(bitmapdata);
diff --git a/Source/IO/Lump.cs b/Source/IO/Lump.cs
index 53aef521..3e0b2b6f 100644
--- a/Source/IO/Lump.cs
+++ b/Source/IO/Lump.cs
@@ -119,7 +119,7 @@ namespace CodeImp.DoomBuilder.IO
fixed(void* bp = namebytes)
{
- General.CopyMemory(&value, bp, new UIntPtr(bytes));
+ General.CopyMemory(&value, bp, bytes);
}
return value;
diff --git a/Source/Windows/GridSetupForm.cs b/Source/Windows/GridSetupForm.cs
index 0e712e3e..4e04181e 100644
--- a/Source/Windows/GridSetupForm.cs
+++ b/Source/Windows/GridSetupForm.cs
@@ -132,7 +132,7 @@ namespace CodeImp.DoomBuilder.Windows
// Set this file as background
backgroundname = browsefile.FileName;
backgroundsource = GridSetup.SOURCE_FILE;
- ImageData img = new FileImage(backgroundname, backgroundname);
+ ImageData img = new FileImage(backgroundname, backgroundname, false, 1.0f, 1.0f);
img.LoadImage();
General.DisplayZoomedImage(backgroundimage, new Bitmap(img.Bitmap));
img.Dispose();