From 5bb3e70344cfafa8c09561b6d7d157026ce18b4f Mon Sep 17 00:00:00 2001 From: Ian C Date: Fri, 21 Jan 2005 00:52:26 +0000 Subject: Initial checkin --- WADEntryConvert.cs | 685 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 685 insertions(+) create mode 100644 WADEntryConvert.cs (limited to 'WADEntryConvert.cs') 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