From 5bb3e70344cfafa8c09561b6d7d157026ce18b4f Mon Sep 17 00:00:00 2001 From: Ian C Date: Fri, 21 Jan 2005 00:52:26 +0000 Subject: Initial checkin --- AssemblyInfo.cs | 32 +++ DOOM.resources | Bin 0 -> 1575 bytes DoomException.cs | 35 +++ Noddybox.DOOM.cmbx | 16 ++ Noddybox.DOOM.prjx | 30 +++ WAD.cs | 365 ++++++++++++++++++++++++++++ WADCollection.cs | 196 +++++++++++++++ WADEntry.cs | 143 +++++++++++ WADEntryConvert.cs | 685 +++++++++++++++++++++++++++++++++++++++++++++++++++++ palette.bmp | Bin 0 -> 1082 bytes 10 files changed, 1502 insertions(+) create mode 100644 AssemblyInfo.cs create mode 100644 DOOM.resources create mode 100644 DoomException.cs create mode 100644 Noddybox.DOOM.cmbx create mode 100644 Noddybox.DOOM.prjx create mode 100644 WAD.cs create mode 100644 WADCollection.cs create mode 100644 WADEntry.cs create mode 100644 WADEntryConvert.cs create mode 100644 palette.bmp diff --git a/AssemblyInfo.cs b/AssemblyInfo.cs new file mode 100644 index 0000000..6566edf --- /dev/null +++ b/AssemblyInfo.cs @@ -0,0 +1,32 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// Information about this assembly is defined by the following +// attributes. +// +// change them to the information which is associated with the assembly +// you compile. + +[assembly: AssemblyTitle("")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// The assembly version has following format : +// +// Major.Minor.Build.Revision +// +// You can specify all values by your own or you can build default build and revision +// numbers with the '*' character (the default): + +[assembly: AssemblyVersion("1.0.*")] + +// The following attributes specify the key for the sign of your assembly. See the +// .NET Framework documentation for more information about signing. +// This is not required, if you don't want signing let these attributes like they're. +[assembly: AssemblyDelaySign(false)] +[assembly: AssemblyKeyFile("")] diff --git a/DOOM.resources b/DOOM.resources new file mode 100644 index 0000000..8a54a4c Binary files /dev/null and b/DOOM.resources differ diff --git a/DoomException.cs b/DoomException.cs new file mode 100644 index 0000000..e2777d8 --- /dev/null +++ b/DoomException.cs @@ -0,0 +1,35 @@ +// Noddybox.DOOM - DOOM WAD Wrapper +// Copyright (C) 2004 Ian Cowburn +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// 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. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +using System; + +namespace Noddybox.DOOM +{ + /// + /// Namespace exception + /// + public class DoomException : Exception + { + /// + /// Base exception for the namespace + /// + /// Error message + public DoomException(string message) : base(message) + { + } + } +} diff --git a/Noddybox.DOOM.cmbx b/Noddybox.DOOM.cmbx new file mode 100644 index 0000000..768070a --- /dev/null +++ b/Noddybox.DOOM.cmbx @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Noddybox.DOOM.prjx b/Noddybox.DOOM.prjx new file mode 100644 index 0000000..6de2c54 --- /dev/null +++ b/Noddybox.DOOM.prjx @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/WAD.cs b/WAD.cs new file mode 100644 index 0000000..42a687d --- /dev/null +++ b/WAD.cs @@ -0,0 +1,365 @@ +// Noddybox.DOOM - DOOM WAD Wrapper +// Copyright (C) 2004 Ian Cowburn +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// 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. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +using System; +using System.IO; +using System.Collections; +using System.Text; + +namespace Noddybox.DOOM +{ + /// + /// Defines a WAD File + /// + public class WAD : IEnumerable, IEnumerator + { + // ==================================== + // PUBLIC + // ==================================== + + /// + /// Describes the type of WAD + /// + public enum EWadType + { + /// + /// An Interal WAD (eg. DOOM 2) + /// + IWAD, + + /// + /// A Patch WAD (eg. a user-defined level) + /// + PWAD + }; + + /// + /// Construct a new, empty WAD file + /// + public WAD() + { + m_type=EWadType.PWAD; + m_entry=new ArrayList(); + m_ascii=new ASCIIEncoding(); + } + + /// + /// Load a WAD file from disk + /// + /// The WAD file + /// + /// I/O errors + /// + public WAD(string path) + { + m_path=path; + m_entry=new ArrayList(); + m_ascii=new ASCIIEncoding(); + Load(); + } + + /// + /// Get/set the path of the WAD file on disk + /// + public string Path + { + get {return m_path;} + set {m_path=value;} + } + + /// + /// Get the type of WAD file + /// + public EWadType WadType + { + get {return m_type;} + } + + /// + /// Adds a new lump to the WAD + /// + /// The lump + public void AddEntry(WADEntry e) + { + m_entry.Add(e); + } + + /// + /// Removes a lump from the WAD + /// + /// The lump + public void RemoveEntry(WADEntry e) + { + m_entry.Remove(e); + } + + /// + /// Find a lump + /// + /// The name to find + /// The first lump that matches the name, or null for no match + public WADEntry FindEntry(string name) + { + foreach (WADEntry e in m_entry) + { + if (e.Name==name) + { + return e; + } + } + + return null; + } + + /// + /// Load a WAD file + /// + /// + /// I/O errors + /// + public void Load() + { + if (m_path==null) + { + throw new DoomException("Tried to load a WAD without a path"); + } + + FileStream fs=File.OpenRead(m_path); + + string id=ReadString(fs,4); + + if (id=="IWAD") + { + m_type=EWadType.IWAD; + } + else if (id=="PWAD") + { + m_type=EWadType.PWAD; + } + else + { + fs.Close(); + throw new DoomException("Not a WAD File - " + m_path); + } + + m_entry.Clear(); + + int num=ReadLong(fs); + + if (num>0) + { + fs.Position=ReadLong(fs); + + for(int f=0;f + /// Saves the WAD file + /// + /// + /// Tried to save an IWAD file + /// + /// + /// I/O errors + /// + public void Save() + { + if (m_path==null) + { + throw new DoomException("Tried to save a WAD without a path"); + } + + if (m_type==EWadType.IWAD) + { + throw new DoomException("Tried to save an IWAD"); + } + + FileStream fs=File.Create(m_path); + + int len=0; + + foreach (WADEntry e in this) + { + len+=e.Length; + } + + WriteString(fs,"PWAD",4); + WriteLong(fs,m_entry.Count); + + int offset=12; + + WriteLong(fs,len+offset); + + foreach (WADEntry e in m_entry) + { + fs.Write(e.Data,0,e.Length); + } + + foreach (WADEntry e in m_entry) + { + WriteLong(fs,offset); + WriteLong(fs,e.Length); + WriteString(fs,e.Name,8); + offset+=e.Length; + } + + fs.Close(); + } + + /// + /// Returns the number of lumps in the WAD + /// + public int Count + { + get {return m_entry.Count;} + } + + /// + /// Index into the lumps + /// + public WADEntry this[int index] + { + get {return (WADEntry)m_entry[index];} + } + + /// + /// Gets an enumerator + /// + /// The enumerator + public IEnumerator GetEnumerator() + { + Reset(); + return this; + } + + /// + /// Get the current object from the enumerator + /// + public object Current + { + get + { + if (m_iter_index==-1) + { + throw new InvalidOperationException(); + } + + return m_entry[m_iter_index]; + } + } + + /// + /// Reset the enumerator to the start of the collection. + /// + public void Reset() + { + m_iter_index=-1; + } + + /// + /// Move the enumerator to the next item. + /// + /// True if there are more objects to enumerate over + public bool MoveNext() + { + m_iter_index++; + + if (m_iter_index>=m_entry.Count) + { + m_iter_index=-1; + } + + return m_iter_index!=-1; + } + + // ==================================== + // PRIVATE + // ==================================== + private string m_path; + private EWadType m_type; + private ArrayList m_entry; + private ASCIIEncoding m_ascii; + + private int m_iter_index; + + private int ReadLong(FileStream fs) + { + int l=0; + + for(int f=0;f<4;f++) + { + int b=fs.ReadByte(); + l|=b<<(f*8); + } + + return l; + } + + private string ReadString(FileStream fs, int len) + { + byte[] data=new byte[len]; + + fs.Read(data,0,len); + + return m_ascii.GetString(data,0,len); + } + + private void WriteLong(FileStream fs, int l) + { + for(int f=0;f<4;f++) + { + fs.WriteByte((byte)(l&0xff)); + l=l>>8; + } + } + + private void WriteString(FileStream fs, string s, int len) + { + byte[] data=m_ascii.GetBytes(s); + + for(int f=0;f + /// Performs operations on a collection of WADs + /// + public class WADCollection : IEnumerable, IEnumerator + { + // ==================================== + // PUBLIC + // ==================================== + + /// + /// Delegate for WAD added event + /// + public delegate void WadAddedEvent(WADCollection collection, WAD wad); + + /// + /// Delegate for WAD removed event + /// + public delegate void WadRemovedEvent(WADCollection collection); + + /// + /// Create an empty collection of WADs + /// + public WADCollection() + { + m_wads=new ArrayList(); + m_iter_index=-1; + } + + /// + /// Add a WAD to the collection + /// + /// The WAD + public void AddWad(WAD w) + { + m_wads.Add(w); + + if (WadAdded!=null) + { + WadAdded(this,w); + } + } + + /// + /// Remove a WAD from the collection + /// + /// The WAD + public void RemoveWad(WAD w) + { + m_wads.Remove(w); + + if (WadRemoved!=null) + { + WadRemoved(this); + } + } + + + /// + /// Get the first palette (PLAYPAL) lump from the WAD files + /// + /// The lump containing the palette, or null if not found + public WADEntry GetPalette() + { + return QueryDirectory("PLAYPAL"); + } + + + /// + /// Queries the WAD directories for the named lump. Note it searches + /// back from the last loaded WAD as DOOM does. + /// + /// The lump name + /// The lump, or null if it doesn't exist + public WADEntry QueryDirectory(string name) + { + for(int f=m_wads.Count-1;f>=0;f--) + { + WAD w=(WAD)m_wads[f]; + + WADEntry e=w.FindEntry("PLAYPAL"); + + if (e!=null) + { + return e; + } + } + + return null; + } + + /// + /// Called when a WAD is added to the collection + /// + public event WadAddedEvent WadAdded; + + /// + /// Called when a WAD is removed from the collection + /// + public event WadRemovedEvent WadRemoved; + + /// + /// Returns the number of WADs in the collection + /// + public int Count + { + get {return m_wads.Count;} + } + + /// + /// Index into the WADs + /// + public WAD this[int index] + { + get {return (WAD)m_wads[index];} + } + + /// + /// Gets an enumerator + /// + /// The enumerator + public IEnumerator GetEnumerator() + { + Reset(); + return this; + } + + /// + /// Get the current object from the enumerator + /// + public object Current + { + get + { + if (m_iter_index==-1) + { + throw new InvalidOperationException(); + } + + return m_wads[m_iter_index]; + } + } + + /// + /// Reset the enumerator to the start of the collection. + /// + public void Reset() + { + m_iter_index=-1; + } + + /// + /// Move the enumerator to the next item. + /// + /// True if there are more objects to enumerate over + public bool MoveNext() + { + m_iter_index++; + + if (m_iter_index>=m_wads.Count) + { + m_iter_index=-1; + } + + return m_iter_index!=-1; + } + + + // ==================================== + // PRIVATE + // ==================================== + private ArrayList m_wads; + private int m_iter_index; + } +} diff --git a/WADEntry.cs b/WADEntry.cs new file mode 100644 index 0000000..d43da68 --- /dev/null +++ b/WADEntry.cs @@ -0,0 +1,143 @@ +// Noddybox.DOOM - DOOM WAD Wrapper +// Copyright (C) 2004 Ian Cowburn +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// 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. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +using System; +using System.IO; + +namespace Noddybox.DOOM +{ + /// + /// Describes a directory entry in a WAD file + /// + public class WADEntry + { + // ==================================== + // PUBLIC + // ==================================== + + /// + /// Create an empty lump + /// + public WADEntry() + { + Name="LUMP"; + Data=null; + } + + /// + /// Create a lump + /// + /// The name + /// The data + public WADEntry(string name, byte[] data) + { + Name=name; + Data=data; + } + + /// + /// Create a lump + /// + /// The lump to copy + public WADEntry(WADEntry we) + { + Name=we.Name; + Data=(byte[])we.Data.Clone(); + } + + /// + /// Get/set the lump's name + /// + public string Name + { + get {return m_name;} + set + { + m_name=value; + + if (m_name.Length>8) + { + m_name=m_name.Substring(0,8); + } + + m_name=m_name.Trim(new char[] {'\0'}); + } + } + + /// + /// Get the length of the lump's data + /// + public int Length + { + get {return m_length;} + } + + /// + /// Get/set the lump data + /// + public byte[] Data + { + get {return m_data;} + set + { + m_data=value; + + if (m_data!=null) + { + m_length=m_data.Length; + } + else + { + m_length=0; + } + } + } + + /// + /// Index into the lump data as bytes + /// + public byte this[int index] + { + get {return m_data[index];} + set {m_data[index]=value;} + } + + /// + /// Index into the lump data as bytes + /// + public byte this[uint index] + { + get {return m_data[index];} + set {m_data[index]=value;} + } + + /// + /// Get the lump data as a MemoryStream + /// + public MemoryStream Stream + { + get {return new MemoryStream(m_data);} + } + + // ==================================== + // PRIVATE + // ==================================== + private string m_name; + private int m_length; + private byte[] m_data; + } +} diff --git a/WADEntryConvert.cs b/WADEntryConvert.cs new file mode 100644 index 0000000..7cd52b3 --- /dev/null +++ b/WADEntryConvert.cs @@ -0,0 +1,685 @@ +// Noddybox.DOOM - DOOM WAD Wrapper +// Copyright (C) 2004 Ian Cowburn +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// 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. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +using System; +using System.Collections; +using System.Drawing; +using System.Drawing.Imaging; +using System.IO; +using System.Resources; +using System.Reflection; +using System.Text; + +namespace Noddybox.DOOM +{ + /// + /// Provides routines to convert WADEntrys to other entities + /// + public class WADEntryConvert + { + // ==================================== + // PUBLIC + // ==================================== + + /// + /// Converts a palette lump into an array of 256 colours. + /// + /// The palette lump, or null for the default DOOM 2 + /// palette + /// The colours + /// + /// Lump is too small to hold a palette + /// + public static Color[] Palette(WADEntry e) + { + if (e==null) + { + ResourceManager mgr=new ResourceManager("DOOM", + Assembly.GetExecutingAssembly()); + + Bitmap bmp=(Bitmap)mgr.GetObject("palette"); + + if (bmp==null) + { + throw new DoomException("Failed to retrieve DOOM 2 palette from resources"); + } + + return bmp.Palette.Entries; + } + + if (e.Length<768) + { + throw new DoomException("Not enough in LUMP " + e.Name + " for a palette"); + } + + Color[] pal=new Color[256];; + + for(int f=0;f<256;f++) + { + int r=e.Data[f*3+0]; + int g=e.Data[f*3+1]; + int b=e.Data[f*3+2]; + + pal[f]=Color.FromArgb(r,g,b); + } + + return pal; + } + + /// + /// Converts a Doom texture/sprite lump into a bitmap + /// + /// The lump + /// The palette + /// The 8-bit bitmap + /// + /// There aren't 256 colours in the palette + /// + /// + /// Empty lump + /// + /// + /// Nonsense size + /// + /// + /// Short lump + /// + public static Bitmap Gfx(WADEntry e, Color[] pal) + { + if (pal.Length<256) + { + throw new DoomException("Need a 256 colour palette to create images"); + } + + if (e.Length==0) + { + throw new DoomException("Empty lump"); + } + + MemoryStream str=e.Stream; + + int lw=GetWord(str); + int lh=GetWord(str); + + if (lw<1 || lw>1024 || lh<1 || lh>1024) + { + throw new DoomException("Nonsense size"); + } + + // Ignore the offsets + // + GetWord(str); + GetWord(str); + + Bitmap bmp=new Bitmap(lw,lh,PixelFormat.Format8bppIndexed); + + SetBitmapPal(bmp,pal); + + BitmapData bmp_data=bmp.LockBits(new Rectangle(0,0,bmp.Width,bmp.Height), + ImageLockMode.WriteOnly, + PixelFormat.Format8bppIndexed); + try + { + for(int x=0;x=0 && x=0 && y + /// Converts a flat-style lump into a bitmap + /// + /// The lump + /// The palette + /// The 8-bit bitmap + /// + /// There aren't 256 colours in the palette + /// + public static Bitmap Flat(WADEntry e, Color[] pal) + { + if (pal.Length<256) + { + throw new DoomException("Need a 256 colour palette to create images"); + } + + if (e.Length!=4096 && e.Length!=16384 && e.Length!=65536) + { + throw new DoomException("FLAT Lump must be 4096, 16384 or 65536 bytes"); + } + + int size=(int)Math.Sqrt(e.Length); + + Bitmap bmp=new Bitmap(size,size,PixelFormat.Format8bppIndexed); + + SetBitmapPal(bmp,pal); + + for(int f=0;f<256;f++) + { + bmp.Palette.Entries[f]=pal[f]; + } + + BitmapData bmp_data=bmp.LockBits(new Rectangle(0,0,bmp.Width,bmp.Height), + ImageLockMode.WriteOnly, + PixelFormat.Format8bppIndexed); + try + { + int i=0; + + for(int y=0;y + /// Convert a bitmap into a graphical lump + /// + /// The name to give the new lump + /// The 8-bit indexed bitmap + /// The X-offset to set in the graphic lump + /// The Y-offset to set in the graphic lump + /// If true, assume colour 247 is transparent + /// The lump + /// + /// The bitmap isn't 8bpp, indexed + /// + public static WADEntry Gfx(string name, Bitmap bmp, int xoff, int yoff, bool trans) + { + if (bmp.PixelFormat!=PixelFormat.Format8bppIndexed) + { + throw new DoomException("Bitmap must be 8-bits, indexed"); + } + + if (bmp.Height>255) + { + throw new DoomException("Doom graphics cannot be over 255 pixels high"); + } + + ArrayList al=new ArrayList(); + MemoryStream str=new MemoryStream(); + + uint data_offset=8u+4u*(uint)bmp.Width; + + PutWord(str,bmp.Width); + PutWord(str,bmp.Height); + PutWord(str,xoff); + PutWord(str,yoff); + + BitmapData bmp_data=bmp.LockBits(new Rectangle(0,0,bmp.Width,bmp.Height), + ImageLockMode.ReadOnly, + PixelFormat.Format8bppIndexed); + try + { + for(int x=0;x + /// Convert a bitmap into a graphical lump + /// + /// The name to give the new lump + /// The 8-bit indexed bitmap + /// If true, assume colour 247 is transparent + /// The lump + /// + /// The bitmap isn't 8bpp, indexed + /// + public static WADEntry Gfx(string name, Bitmap bmp, bool trans) + { + return Gfx(name,bmp,0,0,trans); + } + + /// + /// Convert a flat into a lump + /// + /// The name to give the new lump + /// The 8-bit indexed bitmap + /// The lump + /// + /// The bitmap isn't 8bpp, indexed + /// + public static WADEntry Flat(string name, Bitmap bmp) + { + if (bmp.Width!=bmp.Height ||(bmp.Width!=64 && + bmp.Width!=128 && + bmp.Width!=256)) + { + throw new DoomException("Flats must be 64x64, 128x128 or 256x256"); + } + + if (bmp.PixelFormat!=PixelFormat.Format8bppIndexed) + { + throw new DoomException("Bitmap must be 8-bits, indexed"); + } + + byte[] data=new byte[bmp.Width*bmp.Height]; + BitmapData bmp_data=bmp.LockBits(new Rectangle(0,0,bmp.Width,bmp.Height), + ImageLockMode.ReadOnly, + PixelFormat.Format8bppIndexed); + try + { + for(int y=0;y + /// Converts a sample lump to a WAV file + /// + /// The stream to write the WAV into. Closed on exit. + /// The lump containing the sample data + /// + /// Not a sample lump + /// + public static void Wav(Stream file, WADEntry e) + { + MemoryStream str=e.Stream; + + try + { + if (GetWord(str)!=3) + { + throw new DoomException("Not a sample lump"); + } + + int rate=GetWord(str); + int len=GetWord(str); + + if (GetWord(str)!=0 || len>e.Length-8) + { + throw new DoomException("Not a sample lump"); + } + + // Write RIFF header + // + file.Write(m_ascii.GetBytes("RIFF"),0,4); + PutLong(file,(uint)len+36u); + file.Write(m_ascii.GetBytes("WAVE"),0,4); + + // Write 'fmt' chunk + // + file.Write(m_ascii.GetBytes("fmt "),0,4); + PutLong(file,16); // Size + PutWord(file,1); // PCM + PutWord(file,1); // No channels + PutLong(file,(uint)rate); // Sample Rate + PutLong(file,(uint)rate); // Byte rate + PutWord(file,1); // Block align + PutWord(file,8); // Bits per sample + + // Write 'data' chunk + // + file.Write(m_ascii.GetBytes("data"),0,4); + PutLong(file,(uint)len); + + while(str.Position + /// Converts a WAV file to a sample lump + /// + /// The stream containing the WAV. Closed on exit. + /// The lump + /// + /// Must be a WAV, uncompressed, mono, 8-bits and less than 65535 samples + /// + public static WADEntry Wav(string name, Stream file) + { + string error="Must be a WAV, uncompressed, mono, 8-bits and less than 65535 samples"; + WADEntry e=new WADEntry(); + MemoryStream data=new MemoryStream(); + + e.Name=name; + + try + { + // Get RIFF Header + // + if (Get4CharString(file)!="RIFF") + { + throw new DoomException(error); + } + + GetLong(file); + + if (Get4CharString(file)!="WAVE") + { + throw new DoomException(error); + } + + // Find 'fmt' chunk + // + while(Get4CharString(file)!="fmt ") + { + uint chunklen=GetLong(file); + file.Position+=chunklen; + } + + GetLong(file); + + int pcm=GetWord(file); + int chan=GetWord(file); + uint rate=GetLong(file); + GetLong(file); + int align=GetWord(file); + int bps=GetWord(file); + + if (pcm!=1 || chan!=1 || align!=1 || bps!=8) + { + throw new DoomException(error); + } + + PutWord(data,3); + PutWord(data,(int)rate); + + // Find 'data' chunk + // + while(Get4CharString(file)!="data") + { + uint chunklen=GetLong(file); + file.Position+=chunklen; + } + + uint len=GetLong(file); + + if (len>65535) + { + throw new DoomException(error); + } + + PutWord(data,(int)len); + PutWord(data,0); + + byte[] buff=new byte[len]; + + file.Read(buff,0,(int)len); + data.Write(buff,0,(int)len); + + e.Data=data.ToArray(); + } + finally + { + data.Close(); + file.Close(); + } + + return e; + } + + // ==================================== + // PRIVATE + // ==================================== + + private static ASCIIEncoding m_ascii=new ASCIIEncoding(); + + private WADEntryConvert() {} + + private static void SetBitmapPal(Bitmap bmp, Color[] pal) + { + ColorPalette bmppal=bmp.Palette; + + for(int f=0;f<256;f++) + { + bmppal.Entries[f]=pal[f]; + } + + bmp.Palette=bmppal; + } + + private static byte Read8bppPixel(BitmapData data, int x, int y) + { + unsafe + { + byte *p=(byte *)data.Scan0+x+y*data.Stride; + return *p; + } + } + + private static void Write8bppPixel(BitmapData data, int x, int y, byte col) + { + unsafe + { + byte *p=(byte *)data.Scan0+x+y*data.Stride; + *p=col; + } + } + + private static int GetWord(Stream str) + { + int w=0; + + for(int f=0;f<2;f++) + { + if (str.Position>str.Length) + { + throw new DoomException("Unexpected EOF"); + } + + w|=str.ReadByte()<<(f*8); + } + + return w; + } + + private static uint GetLong(Stream str) + { + uint l=0; + + for(int f=0;f<4;f++) + { + if (str.Position>str.Length) + { + throw new DoomException("Unexpected EOF"); + } + + l|=(uint)str.ReadByte()<<(f*8); + } + + return l; + } + + private static string Get4CharString(Stream str) + { + byte[] b=new byte[4]; + + for(int f=0;f<4;f++) + { + if (str.Position>str.Length) + { + throw new DoomException("Unexpected EOF"); + } + + b[f]=(byte)str.ReadByte(); + } + + return m_ascii.GetString(b); + } + + private static void PutWord(Stream str, int w) + { + for(int f=0;f<2;f++) + { + str.WriteByte((byte)(w&0xff)); + w>>=8; + } + } + + private static void PutLong(Stream str, uint w) + { + for(int f=0;f<4;f++) + { + str.WriteByte((byte)(w&0xff)); + w>>=8; + } + } + + private static void EncodeTransColumn(BitmapData bmp, + int x, + int height, + ArrayList al) + { + ArrayList block=null; + byte block_start=0; + + for(byte y=0;y