summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan C <ianc@noddybox.co.uk>2005-01-21 00:52:26 +0000
committerIan C <ianc@noddybox.co.uk>2005-01-21 00:52:26 +0000
commit5bb3e70344cfafa8c09561b6d7d157026ce18b4f (patch)
tree072d4c6764c67dee203e7d8d5294975e96c41c39
parent90648a22d6268df497cd4384e6ba7a0ae4e23b8b (diff)
Initial checkin
-rw-r--r--AssemblyInfo.cs32
-rw-r--r--DOOM.resourcesbin0 -> 1575 bytes
-rw-r--r--DoomException.cs35
-rw-r--r--Noddybox.DOOM.cmbx16
-rw-r--r--Noddybox.DOOM.prjx30
-rw-r--r--WAD.cs365
-rw-r--r--WADCollection.cs196
-rw-r--r--WADEntry.cs143
-rw-r--r--WADEntryConvert.cs685
-rw-r--r--palette.bmpbin0 -> 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.resources
new file mode 100644
index 0000000..8a54a4c
--- /dev/null
+++ b/DOOM.resources
Binary files 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
+{
+ /// <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
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
+{
+ /// <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.bmp
new file mode 100644
index 0000000..1d46c83
--- /dev/null
+++ b/palette.bmp
Binary files differ