diff options
| -rw-r--r-- | AssemblyInfo.cs | 32 | ||||
| -rw-r--r-- | DOOM.resources | bin | 0 -> 1575 bytes | |||
| -rw-r--r-- | DoomException.cs | 35 | ||||
| -rw-r--r-- | Noddybox.DOOM.cmbx | 16 | ||||
| -rw-r--r-- | Noddybox.DOOM.prjx | 30 | ||||
| -rw-r--r-- | WAD.cs | 365 | ||||
| -rw-r--r-- | WADCollection.cs | 196 | ||||
| -rw-r--r-- | WADEntry.cs | 143 | ||||
| -rw-r--r-- | WADEntryConvert.cs | 685 | ||||
| -rw-r--r-- | palette.bmp | bin | 0 -> 1082 bytes | 
10 files changed, 1502 insertions, 0 deletions
| 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.resourcesBinary files differ new file mode 100644 index 0000000..8a54a4c --- /dev/null +++ b/DOOM.resources 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 +{ +	/// <summary> +	/// Namespace exception +	/// </summary> +	public class DoomException : Exception +	{ +		/// <summary> +		/// Base exception for the namespace +		/// </summary> +		/// <param name="message">Error message</param> +		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 @@ +<Combine fileversion="1.0" name="Noddybox.DOOM" description=""> +  <StartMode startupentry="Noddybox.DOOM" single="True"> +    <Execute entry="Noddybox.DOOM" type="None" /> +  </StartMode> +  <Entries> +    <Entry filename=".\.\Noddybox.DOOM.prjx" /> +  </Entries> +  <Configurations active="Debug"> +    <Configuration name="Release"> +      <Entry name="Noddybox.DOOM" configurationname="Debug" build="False" /> +    </Configuration> +    <Configuration name="Debug"> +      <Entry name="Noddybox.DOOM" configurationname="Debug" build="False" /> +    </Configuration> +  </Configurations> +</Combine>
\ 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 @@ +<Project name="Noddybox.DOOM" standardNamespace="Noddybox.DOOM" description="" newfilesearch="None" enableviewstate="True" version="1.1" projecttype="C#"> +  <Contents> +    <File name=".\AssemblyInfo.cs" subtype="Code" buildaction="Compile" dependson="" data="" /> +    <File name=".\DoomException.cs" subtype="Code" buildaction="Compile" dependson="" data="" /> +    <File name=".\WAD.cs" subtype="Code" buildaction="Compile" dependson="" data="" /> +    <File name=".\WADEntry.cs" subtype="Code" buildaction="Compile" dependson="" data="" /> +    <File name=".\WADCollection.cs" subtype="Code" buildaction="Compile" dependson="" data="" /> +    <File name=".\WADEntryConvert.cs" subtype="Code" buildaction="Compile" dependson="" data="" /> +    <File name=".\DOOM.resources" subtype="Code" buildaction="EmbedAsResource" dependson="" data="" /> +  </Contents> +  <References /> +  <DeploymentInformation target="" script="" strategy="File" /> +  <Configuration runwithwarnings="True" name="Debug"> +    <CodeGeneration runtime="MsNet" compiler="Csc" compilerversion="Standard" warninglevel="4" nowarn="" includedebuginformation="True" optimize="False" unsafecodeallowed="True" generateoverflowchecks="True" mainclass="" target="Library" definesymbols="" generatexmldocumentation="False" win32Icon="" noconfig="False" nostdlib="False" /> +    <Execution commandlineparameters="" consolepause="False" /> +    <Output directory=".\bin\Debug" assembly="Noddybox.DOOM" executeScript="" executeBeforeBuild="" executeAfterBuild="" executeBeforeBuildArguments="" executeAfterBuildArguments="" /> +  </Configuration> +  <Configurations active="Debug"> +    <Configuration runwithwarnings="True" name="Debug"> +      <CodeGeneration runtime="MsNet" compiler="Csc" compilerversion="Standard" warninglevel="4" nowarn="" includedebuginformation="True" optimize="False" unsafecodeallowed="True" generateoverflowchecks="True" mainclass="" target="Library" definesymbols="" generatexmldocumentation="False" win32Icon="" noconfig="False" nostdlib="False" /> +      <Execution commandlineparameters="" consolepause="False" /> +      <Output directory=".\bin\Debug" assembly="Noddybox.DOOM" executeScript="" executeBeforeBuild="" executeAfterBuild="" executeBeforeBuildArguments="" executeAfterBuildArguments="" /> +    </Configuration> +    <Configuration runwithwarnings="True" name="Release"> +      <CodeGeneration runtime="MsNet" compiler="Csc" compilerversion="" warninglevel="4" nowarn="" includedebuginformation="False" optimize="True" unsafecodeallowed="True" generateoverflowchecks="False" mainclass="" target="Library" definesymbols="" generatexmldocumentation="True" win32Icon="" noconfig="False" nostdlib="False" /> +      <Execution commandlineparameters="" consolepause="False" /> +      <Output directory=".\bin\Release" assembly="Noddybox.DOOM" executeScript="" executeBeforeBuild="" executeAfterBuild="" executeBeforeBuildArguments="" executeAfterBuildArguments="" /> +    </Configuration> +  </Configurations> +</Project>
\ No newline at end of file @@ -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 +{ +	/// <summary> +	/// Defines a WAD File +	/// </summary> +	public class WAD : IEnumerable, IEnumerator +	{ +		// ==================================== +		// PUBLIC +		// ==================================== +		 +		/// <summary> +		/// Describes the type of WAD +		/// </summary> +		public enum EWadType +		{ +			/// <summary> +			/// An Interal WAD (eg. DOOM 2) +			/// </summary> +			IWAD, +			 +			/// <summary> +			/// A Patch WAD (eg. a user-defined level) +			/// </summary> +			PWAD +		}; + +		/// <summary> +		/// Construct a new, empty WAD file +		/// </summary> +		public WAD() +		{ +			m_type=EWadType.PWAD; +			m_entry=new ArrayList(); +			m_ascii=new ASCIIEncoding(); +		} +		 +		/// <summary> +		/// Load a WAD file from disk +		/// </summary> +		/// <param name="path">The WAD file</param> +		/// <exception cref="System.IO.IOException"> +		/// I/O errors +		/// </exception> +		public WAD(string path) +		{ +			m_path=path; +			m_entry=new ArrayList(); +			m_ascii=new ASCIIEncoding(); +			Load(); +		} +		 +		/// <summary> +		/// Get/set the path of the WAD file on disk +		/// </summary> +		public string Path +		{ +			get {return m_path;} +			set {m_path=value;} +		} +		 +		/// <summary> +		/// Get the type of WAD file +		/// </summary> +		public EWadType WadType +		{ +			get {return m_type;} +		} +		 +		/// <summary> +		/// Adds a new lump to the WAD +		/// </summary> +		/// <param name="e">The lump</param> +		public void AddEntry(WADEntry e) +		{ +			m_entry.Add(e); +		} +		 +		/// <summary> +		/// Removes a lump from the WAD +		/// </summary> +		/// <param name="e">The lump</param> +		public void RemoveEntry(WADEntry e) +		{ +			m_entry.Remove(e); +		} +		 +		/// <summary> +		/// Find a lump +		/// </summary> +		/// <param name="name">The name to find</param> +		/// <returns>The first lump that matches the name, or null for no match</returns> +		public WADEntry FindEntry(string name) +		{ +			foreach (WADEntry e in m_entry) +			{ +				if (e.Name==name) +				{ +					return e; +				} +			} +			 +			return null; +		} +		 +		/// <summary> +		/// Load a WAD file +		/// </summary> +		/// <exception cref="System.IO.IOException"> +		/// I/O errors +		/// </exception> +		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<num;f++) +				{ +					int off=ReadLong(fs); +					int len=ReadLong(fs); +					string name=ReadString(fs,8); +					 +					long cur=fs.Position; +					 +					byte[] data=new byte[len]; +					 +					fs.Position=off; +					fs.Read(data,0,len); +					fs.Position=cur; +					 +					m_entry.Add(new WADEntry(name,data)); +				} +			} +			 +			fs.Close(); +		} +		 +		/// <summary> +		/// Saves the WAD file +		/// </summary> +		/// <exception cref="Noddybox.DOOM.DoomException"> +		/// Tried to save an IWAD file +		/// </exception> +		/// <exception cref="System.IO.IOException"> +		/// I/O errors +		/// </exception> +		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(); +		} + +		/// <summary> +		/// Returns the number of lumps in the WAD +		/// </summary> +		public int Count +		{ +			get {return m_entry.Count;} +		} +		 +		/// <summary> +		/// Index into the lumps +		/// </summary> +		public WADEntry this[int index] +		{ +			get {return (WADEntry)m_entry[index];} +		} + +		/// <summary> +		/// Gets an enumerator +		/// </summary> +		/// <returns>The enumerator</returns> +		public IEnumerator GetEnumerator() +		{ +			Reset(); +			return this; +		} +		 +		/// <summary> +		/// Get the current object from the enumerator +		/// </summary> +		public object Current +		{ +			get +			{ +				if (m_iter_index==-1) +				{ +					throw new InvalidOperationException(); +				} +				 +				return m_entry[m_iter_index]; +			} +		} + +		/// <summary> +		/// Reset the enumerator to the start of the collection. +		/// </summary> +		public void Reset() +		{ +			m_iter_index=-1; +		} + +		/// <summary> +		/// Move the enumerator to the next item. +		/// </summary> +		/// <returns>True if there are more objects to enumerate over</returns> +		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<len;f++) +			{ +				if (f<data.Length) +				{ +					fs.WriteByte(data[f]); +				} +				else +				{ +					fs.WriteByte(0); +				} +			} +		} +	} +} diff --git a/WADCollection.cs b/WADCollection.cs new file mode 100644 index 0000000..ba6eb5b --- /dev/null +++ b/WADCollection.cs @@ -0,0 +1,196 @@ +// 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; + +namespace Noddybox.DOOM +{ +	/// <summary> +	/// Performs operations on a collection of WADs +	/// </summary> +	public class WADCollection : IEnumerable, IEnumerator +	{ +		// ==================================== +		// PUBLIC +		// ==================================== +		 +		/// <summary> +		/// Delegate for WAD added event +		/// </summary> +		public delegate void WadAddedEvent(WADCollection collection, WAD wad); +		 +		/// <summary> +		/// Delegate for WAD removed event +		/// </summary> +		public delegate void WadRemovedEvent(WADCollection collection); +		 +		/// <summary> +		/// Create an empty collection of WADs +		/// </summary> +		public WADCollection() +		{ +			m_wads=new ArrayList(); +			m_iter_index=-1; +		} +		 +		/// <summary> +		/// Add a WAD to the collection +		/// </summary> +		/// <param name="w">The WAD</param> +		public void AddWad(WAD w) +		{ +			m_wads.Add(w); +			 +			if (WadAdded!=null) +			{ +				WadAdded(this,w); +			} +		} +		 +		/// <summary> +		/// Remove a WAD from the collection +		/// </summary> +		/// <param name="w">The WAD</param> +		public void RemoveWad(WAD w) +		{ +			m_wads.Remove(w); +			 +			if (WadRemoved!=null) +			{ +				WadRemoved(this); +			} +		} +		 +		 +		/// <summary> +		/// Get the first palette (PLAYPAL) lump from the WAD files +		/// </summary> +		/// <returns>The lump containing the palette, or null if not found</returns> +		public WADEntry GetPalette() +		{ +			return QueryDirectory("PLAYPAL"); +		} +		 +		 +		/// <summary> +		/// Queries the WAD directories for the named lump.  Note it searches +		/// back from the last loaded WAD as DOOM does. +		/// </summary> +		/// <param name="name">The lump name</param> +		/// <returns>The lump, or null if it doesn't exist</returns> +		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; +		} + +		/// <summary> +		/// Called when a WAD is added to the collection +		/// </summary> +		public event WadAddedEvent 		WadAdded; +		 +		/// <summary> +		/// Called when a WAD is removed from the collection +		/// </summary> +		public event WadRemovedEvent	WadRemoved; + +		/// <summary> +		/// Returns the number of WADs in the collection +		/// </summary> +		public int Count +		{ +			get {return m_wads.Count;} +		} +		 +		/// <summary> +		/// Index into the WADs  +		/// </summary> +		public WAD this[int index] +		{ +			get {return (WAD)m_wads[index];} +		} +		 +		/// <summary> +		/// Gets an enumerator +		/// </summary> +		/// <returns>The enumerator</returns> +		public IEnumerator GetEnumerator() +		{ +			Reset(); +			return this; +		} +		 +		/// <summary> +		/// Get the current object from the enumerator +		/// </summary> +		public object Current +		{ +			get +			{ +				if (m_iter_index==-1) +				{ +					throw new InvalidOperationException(); +				} +				 +				return m_wads[m_iter_index]; +			} +		} + +		/// <summary> +		/// Reset the enumerator to the start of the collection. +		/// </summary> +		public void Reset() +		{ +			m_iter_index=-1; +		} + +		/// <summary> +		/// Move the enumerator to the next item. +		/// </summary> +		/// <returns>True if there are more objects to enumerate over</returns> +		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 +{ +	/// <summary> +	/// Describes a directory entry in a WAD file +	/// </summary> +	public class WADEntry +	{ +		// ==================================== +		// PUBLIC +		// ==================================== + +		/// <summary> +		/// Create an empty lump +		/// </summary> +		public WADEntry() +		{ +			Name="LUMP"; +			Data=null; +		} + +		/// <summary> +		/// Create a lump +		/// </summary> +		/// <param name="name">The name</param> +		/// <param name="data">The data</param> +		public WADEntry(string name, byte[] data) +		{ +			Name=name; +			Data=data; +		} +		 +		/// <summary> +		/// Create a lump +		/// </summary> +		/// <param name="we">The lump to copy</param> +		public WADEntry(WADEntry we) +		{ +			Name=we.Name; +			Data=(byte[])we.Data.Clone(); +		} +		 +		/// <summary> +		/// Get/set the lump's name +		/// </summary> +		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'}); +			} +		} +		 +		/// <summary> +		/// Get the length of the lump's data +		/// </summary> +		public int Length +		{ +			get {return m_length;} +		} +		 +		/// <summary> +		/// Get/set the lump data +		/// </summary> +		public byte[] Data +		{ +			get {return m_data;} +			set +			{ +				m_data=value; +				 +				if (m_data!=null) +				{ +					m_length=m_data.Length; +				} +				else +				{ +					m_length=0; +				} +			} +		} +		 +		/// <summary> +		/// Index into the lump data as bytes +		/// </summary> +		public byte this[int index] +		{ +			get {return m_data[index];} +			set {m_data[index]=value;} +		} +		 +		/// <summary> +		/// Index into the lump data as bytes +		/// </summary> +		public byte this[uint index] +		{ +			get {return m_data[index];} +			set {m_data[index]=value;} +		} +		 +		/// <summary> +		/// Get the lump data as a MemoryStream +		/// </summary> +		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 +{ +	/// <summary> +	/// Provides routines to convert WADEntrys to other entities +	/// </summary> +	public class WADEntryConvert +	{ +		// ==================================== +		// PUBLIC +		// ==================================== +		 +		/// <summary> +		/// Converts a palette lump into an array of 256 colours. +		/// </summary> +		/// <param name="e">The palette lump, or null for the default DOOM 2 +		/// palette</param> +		/// <returns>The colours</returns> +		/// <exception cref="Noddybox.DOOM.DoomException"> +		/// Lump is too small to hold a palette +		/// </exception> +		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; +		} +		 +		/// <summary> +		/// Converts a Doom texture/sprite lump into a bitmap +		/// </summary> +		/// <param name="e">The lump</param> +		/// <param name="pal">The palette</param> +		/// <returns>The 8-bit bitmap</returns> +		/// <exception cref="Noddybox.DOOM.DoomException"> +		/// There aren't 256 colours in the palette +		/// </exception> +		/// <exception cref="Noddybox.DOOM.DoomException"> +		/// Empty lump +		/// </exception> +		/// <exception cref="Noddybox.DOOM.DoomException"> +		/// Nonsense size +		/// </exception> +		/// <exception cref="Noddybox.DOOM.DoomException"> +		/// Short lump +		/// </exception> +		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<lw;x++) +				{ +					uint offset=GetLong(str); + +					try +					{ +						while(e[offset]!=0xffu) +						{ +							int y=e[offset++]; +							int cno=e[offset++]; +			 +							offset++; +							 +							for(int f=0;f<cno;f++) +							{ +								if (x>=0 && x<lw && y>=0 && y<lh) +								{ +									Write8bppPixel(bmp_data,x,y,e[offset]); +								} +								 +								offset++; +								y++; +							} +							 +							offset++; +						} +					} +					catch (IndexOutOfRangeException) +					{ +						throw new DoomException("Short lump"); +					} +				} +			} +			finally +			{ +				bmp.UnlockBits(bmp_data); +			} +			 +			return bmp; +		} +		 +		/// <summary> +		/// Converts a flat-style lump into a bitmap +		/// </summary> +		/// <param name="e">The lump</param> +		/// <param name="pal">The palette</param> +		/// <returns>The 8-bit bitmap</returns> +		/// <exception cref="Noddybox.DOOM.DoomException"> +		/// There aren't 256 colours in the palette +		/// </exception> +		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<size;y++) +				{ +					for(int x=0;x<size;x++) +					{ +						Write8bppPixel(bmp_data,x,y,e[i++]); +					} +				} +			} +			finally +			{ +				bmp.UnlockBits(bmp_data); +			} +			 +			return bmp; +		} +		 +		/// <summary> +		/// Convert a bitmap into a graphical lump +		/// </summary> +		/// <param name="name">The name to give the new lump</param> +		/// <param name="bmp">The 8-bit indexed bitmap</param> +		/// <param name="xoff">The X-offset to set in the graphic lump</param> +		/// <param name="yoff">The Y-offset to set in the graphic lump</param> +		/// <param name="trans">If true, assume colour 247 is transparent</param> +		/// <returns>The lump</returns> +		/// <exception cref="Noddybox.DOOM.DoomException"> +		/// The bitmap isn't 8bpp, indexed +		/// </exception> +		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<bmp.Width;x++) +				{ +					PutLong(str,data_offset+(uint)al.Count); +					 +					if (trans) +					{ +						EncodeTransColumn(bmp_data,x,bmp.Height,al); +					} +					else +					{ +						EncodeNonTransColumn(bmp_data,x,bmp.Height,al); +					} +				} +			} +			finally +			{ +				bmp.UnlockBits(bmp_data); +			} + +			str.Write((byte[])al.ToArray(typeof(byte)),0,al.Count); +			str.Close(); +			 +			return new WADEntry(name,str.ToArray()); +		} +		 +		/// <summary> +		/// Convert a bitmap into a graphical lump +		/// </summary> +		/// <param name="name">The name to give the new lump</param> +		/// <param name="bmp">The 8-bit indexed bitmap</param> +		/// <param name="trans">If true, assume colour 247 is transparent</param> +		/// <returns>The lump</returns> +		/// <exception cref="Noddybox.DOOM.DoomException"> +		/// The bitmap isn't 8bpp, indexed +		/// </exception> +		public static WADEntry Gfx(string name, Bitmap bmp, bool trans) +		{ +			return Gfx(name,bmp,0,0,trans); +		} +		 +		/// <summary> +		/// Convert a flat into a lump +		/// </summary> +		/// <param name="name">The name to give the new lump</param> +		/// <param name="bmp">The 8-bit indexed bitmap</param> +		/// <returns>The lump</returns> +		/// <exception cref="Noddybox.DOOM.DoomException"> +		/// The bitmap isn't 8bpp, indexed +		/// </exception> +		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<bmp.Height;y++) +				{ +					for(int x=0;x<bmp.Width;x++) +					{ +						data[x+y*bmp.Width]=Read8bppPixel(bmp_data,x,y); +					} +				} +			} +			finally +			{ +				bmp.UnlockBits(bmp_data); +			} +				 +			return new WADEntry(name,data); +		} +		 +		/// <summary> +		/// Converts a sample lump to a WAV file +		/// </summary> +		/// <param name="file">The stream to write the WAV into.  Closed on exit.</param> +		/// <param name="e">The lump containing the sample data</param> +		/// <exception cref="Noddybox.DOOM.DoomException"> +		/// Not a sample lump +		/// </exception> +		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<str.Length) +				{ +					file.WriteByte((byte)str.ReadByte()); +				} +			} +			finally +			{ +				file.Close(); +				str.Close(); +			} +		} +		 +		/// <summary> +		/// Converts a WAV file to a sample lump +		/// </summary> +		/// <param name="file">The stream containing the WAV.  Closed on exit.</param> +		/// <returns>The lump</returns> +		/// <exception cref="Noddybox.DOOM.DoomException"> +		/// Must be a WAV, uncompressed, mono, 8-bits and less than 65535 samples +		/// </exception> +		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<height;y++) +			{ +				byte col=Read8bppPixel(bmp,x,y); +				 +				if (col!=247) +				{ +					if (block==null) +					{ +						block=new ArrayList(); +						block_start=y; +					} +					 +					block.Add(col); +				} +				else +				{ +					if (block!=null) +					{ +						al.Add(block_start); +						al.Add((byte)block.Count); +						al.Add((byte)0); +						al.AddRange(block); +						al.Add((byte)0); +						block=null; +					} +				} +			} +			 +			if (block!=null) +			{ +				al.Add(block_start); +				al.Add((byte)block.Count); +				al.Add((byte)0); +				al.AddRange(block); +				al.Add((byte)0); +				block=null; +			} + +			al.Add((byte)255); +		} + +		private static void EncodeNonTransColumn(BitmapData bmp, +												 int x, +												 int height, +												 ArrayList al) +		{ +			al.Add((byte)0); +			al.Add((byte)height); + +			al.Add((byte)0); +			 +			for(byte y=0;y<height;y++) +			{ +				al.Add(Read8bppPixel(bmp,x,y)); +			} +			 +			al.Add((byte)0); + +			al.Add((byte)255); +		} +	} +} diff --git a/palette.bmp b/palette.bmpBinary files differ new file mode 100644 index 0000000..1d46c83 --- /dev/null +++ b/palette.bmp | 
