diff --git a/Build/Configurations/Boom.cfg b/Build/Configurations/Boom.cfg index dc67aff7..64bc85b2 100644 --- a/Build/Configurations/Boom.cfg +++ b/Build/Configurations/Boom.cfg @@ -152,6 +152,16 @@ flats } } +// Colormap sources +colormaps +{ + standard1 + { + start = "C_START"; + end = "C_END"; + } +} + /* GAME DETECT PATTERN diff --git a/Build/Configurations/Eternity_Doom.cfg b/Build/Configurations/Eternity_Doom.cfg index e41ae3c9..14ad8987 100644 --- a/Build/Configurations/Eternity_Doom.cfg +++ b/Build/Configurations/Eternity_Doom.cfg @@ -147,6 +147,16 @@ flats } } +// Colormap sources +colormaps +{ + standard1 + { + start = "C_START"; + end = "C_END"; + } +} + /* GAME DETECT PATTERN diff --git a/Build/Configurations/Eternity_DoomUDMF.cfg b/Build/Configurations/Eternity_DoomUDMF.cfg index 9a215013..60e10bbd 100644 --- a/Build/Configurations/Eternity_DoomUDMF.cfg +++ b/Build/Configurations/Eternity_DoomUDMF.cfg @@ -152,6 +152,16 @@ flats } } +// Colormap sources +colormaps +{ + standard1 + { + start = "C_START"; + end = "C_END"; + } +} + /* GAME DETECT PATTERN diff --git a/Build/Configurations/Legacy.cfg b/Build/Configurations/Legacy.cfg index 0e223341..8f675647 100644 --- a/Build/Configurations/Legacy.cfg +++ b/Build/Configurations/Legacy.cfg @@ -147,6 +147,16 @@ flats } } +// Colormap sources +colormaps +{ + standard1 + { + start = "C_START"; + end = "C_END"; + } +} + /* GAME DETECT PATTERN diff --git a/Build/Configurations/Risen3D.cfg b/Build/Configurations/Risen3D.cfg index b694ae08..12274901 100644 --- a/Build/Configurations/Risen3D.cfg +++ b/Build/Configurations/Risen3D.cfg @@ -147,6 +147,16 @@ flats } } +// Colormap sources +colormaps +{ + standard1 + { + start = "C_START"; + end = "C_END"; + } +} + /* GAME DETECT PATTERN diff --git a/Build/Configurations/Skulltag_Doom.cfg b/Build/Configurations/Skulltag_Doom.cfg index cc52ae9a..39b53a1c 100644 --- a/Build/Configurations/Skulltag_Doom.cfg +++ b/Build/Configurations/Skulltag_Doom.cfg @@ -155,6 +155,16 @@ flats } } +// Colormap sources +colormaps +{ + standard1 + { + start = "C_START"; + end = "C_END"; + } +} + /* GAME DETECT PATTERN diff --git a/Build/Configurations/Skulltag_DoomHexen.cfg b/Build/Configurations/Skulltag_DoomHexen.cfg index 33b0ced7..d526dfdb 100644 --- a/Build/Configurations/Skulltag_DoomHexen.cfg +++ b/Build/Configurations/Skulltag_DoomHexen.cfg @@ -166,6 +166,16 @@ flats } } +// Colormap sources +colormaps +{ + standard1 + { + start = "C_START"; + end = "C_END"; + } +} + /* GAME DETECT PATTERN diff --git a/Build/Configurations/ZDoom_Doom.cfg b/Build/Configurations/ZDoom_Doom.cfg index 0e7cecae..2d50e426 100644 --- a/Build/Configurations/ZDoom_Doom.cfg +++ b/Build/Configurations/ZDoom_Doom.cfg @@ -155,6 +155,16 @@ flats } } +// Colormap sources +colormaps +{ + standard1 + { + start = "C_START"; + end = "C_END"; + } +} + /* GAME DETECT PATTERN diff --git a/Build/Configurations/ZDoom_DoomHexen.cfg b/Build/Configurations/ZDoom_DoomHexen.cfg index 057de632..c29ba243 100644 --- a/Build/Configurations/ZDoom_DoomHexen.cfg +++ b/Build/Configurations/ZDoom_DoomHexen.cfg @@ -166,6 +166,16 @@ flats } } +// Colormap sources +colormaps +{ + standard1 + { + start = "C_START"; + end = "C_END"; + } +} + /* GAME DETECT PATTERN diff --git a/Build/Configurations/ZDoom_DoomUDMF.cfg b/Build/Configurations/ZDoom_DoomUDMF.cfg index f2e25fc4..518daf36 100644 --- a/Build/Configurations/ZDoom_DoomUDMF.cfg +++ b/Build/Configurations/ZDoom_DoomUDMF.cfg @@ -176,6 +176,16 @@ flats } } +// Colormap sources +colormaps +{ + standard1 + { + start = "C_START"; + end = "C_END"; + } +} + /* GAME DETECT PATTERN diff --git a/Build/Configurations/ZDoom_HereticHexen.cfg b/Build/Configurations/ZDoom_HereticHexen.cfg index ab6e7c75..c64ea8ae 100644 --- a/Build/Configurations/ZDoom_HereticHexen.cfg +++ b/Build/Configurations/ZDoom_HereticHexen.cfg @@ -165,6 +165,16 @@ flats } } +// Colormap sources +colormaps +{ + standard1 + { + start = "C_START"; + end = "C_END"; + } +} + /* GAME DETECT PATTERN diff --git a/Build/Configurations/ZDoom_Hexen.cfg b/Build/Configurations/ZDoom_Hexen.cfg index 1a8f9a5f..db6cc4b4 100644 --- a/Build/Configurations/ZDoom_Hexen.cfg +++ b/Build/Configurations/ZDoom_Hexen.cfg @@ -165,6 +165,16 @@ flats } } +// Colormap sources +colormaps +{ + standard1 + { + start = "C_START"; + end = "C_END"; + } +} + /* GAME DETECT PATTERN diff --git a/Source/Core/Builder.csproj b/Source/Core/Builder.csproj index 8b032aac..103b8f03 100644 --- a/Source/Core/Builder.csproj +++ b/Source/Core/Builder.csproj @@ -667,12 +667,14 @@ ThingBrowserControl.cs + + Form @@ -872,4 +874,4 @@ - \ No newline at end of file + diff --git a/Source/Core/Config/GameConfiguration.cs b/Source/Core/Config/GameConfiguration.cs index 124dfbb4..8d2e9fbc 100644 --- a/Source/Core/Config/GameConfiguration.cs +++ b/Source/Core/Config/GameConfiguration.cs @@ -83,6 +83,7 @@ namespace CodeImp.DoomBuilder.Config private IDictionary flatranges; private IDictionary patchranges; private IDictionary spriteranges; + private IDictionary colormapranges; // Things private List defaultthingflags; @@ -163,6 +164,7 @@ namespace CodeImp.DoomBuilder.Config public IDictionary FlatRanges { get { return flatranges; } } public IDictionary PatchRanges { get { return patchranges; } } public IDictionary SpriteRanges { get { return spriteranges; } } + public IDictionary ColormapRanges { get { return colormapranges; } } // Things public ICollection DefaultThingFlags { get { return defaultthingflags; } } @@ -276,6 +278,7 @@ namespace CodeImp.DoomBuilder.Config flatranges = cfg.ReadSetting("flats", new Hashtable()); patchranges = cfg.ReadSetting("patches", new Hashtable()); spriteranges = cfg.ReadSetting("sprites", new Hashtable()); + colormapranges = cfg.ReadSetting("colormaps", new Hashtable()); // Map lumps LoadMapLumps(); diff --git a/Source/Core/Data/ColormapImage.cs b/Source/Core/Data/ColormapImage.cs new file mode 100644 index 00000000..0e02ef38 --- /dev/null +++ b/Source/Core/Data/ColormapImage.cs @@ -0,0 +1,121 @@ + +#region ================== Copyright (c) 2007 Pascal vd Heiden + +/* + * Copyright (c) 2007 Pascal vd Heiden, www.codeimp.com + * This program is released under GNU General Public License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#endregion + +#region ================== Namespaces + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; +using System.Text; +using System.Drawing; +using System.Drawing.Imaging; +using System.IO; +using CodeImp.DoomBuilder.IO; + +#endregion + +namespace CodeImp.DoomBuilder.Data +{ + internal sealed class ColormapImage : ImageData + { + #region ================== Constructor / Disposer + + // Constructor + public ColormapImage(string name) + { + // Initialize + SetName(name); + + // We have no destructor + GC.SuppressFinalize(this); + } + + #endregion + + #region ================== Methods + + // This loads the image + protected override void LocalLoadImage() + { + Stream lumpdata; + MemoryStream mem; + IImageReader reader; + byte[] membytes; + + // Leave when already loaded + if(this.IsImageLoaded) return; + + lock(this) + { + // Get the lump data stream + lumpdata = General.Map.Data.GetColormapData(Name); + if(lumpdata != null) + { + // Copy lump data to memory + lumpdata.Seek(0, SeekOrigin.Begin); + membytes = new byte[(int)lumpdata.Length]; + lumpdata.Read(membytes, 0, (int)lumpdata.Length); + mem = new MemoryStream(membytes); + mem.Seek(0, SeekOrigin.Begin); + + // Get a reader for the data + reader = ImageDataFormat.GetImageReader(mem, ImageDataFormat.DOOMCOLORMAP, General.Map.Data.Palette); + if(reader is UnknownImageReader) + { + // Data is in an unknown format! + General.ErrorLogger.Add(ErrorType.Error, "Colormap lump '" + Name + "' data format could not be read. Does this lump contain valid colormap data at all?"); + bitmap = null; + } + else + { + // Read data as bitmap + mem.Seek(0, SeekOrigin.Begin); + if(bitmap != null) bitmap.Dispose(); + bitmap = reader.ReadAsBitmap(mem); + } + + // Done + mem.Dispose(); + + if(bitmap != null) + { + // Get width and height from image + width = bitmap.Size.Width; + height = bitmap.Size.Height; + scaledwidth = (float)width * General.Map.Config.DefaultFlatScale; + scaledheight = (float)height * General.Map.Config.DefaultFlatScale; + } + else + { + loadfailed = true; + } + } + else + { + // Missing a patch lump! + General.ErrorLogger.Add(ErrorType.Error, "Missing colormap lump '" + Name + "'. Did you forget to include required resources?"); + loadfailed = true; + } + + // Pass on to base + base.LocalLoadImage(); + } + } + + #endregion + } +} diff --git a/Source/Core/Data/DataManager.cs b/Source/Core/Data/DataManager.cs index e4faef9c..717130c9 100644 --- a/Source/Core/Data/DataManager.cs +++ b/Source/Core/Data/DataManager.cs @@ -207,8 +207,9 @@ namespace CodeImp.DoomBuilder.Data // This loads all data resources internal void Load(DataLocationList locations) { - int texcount, flatcount, spritecount, thingcount; + int texcount, flatcount, spritecount, thingcount, colormapcount; Dictionary texturesonly = new Dictionary(); + Dictionary colormapsonly = new Dictionary(); Dictionary flatsonly = new Dictionary(); DataReader c; @@ -289,10 +290,18 @@ namespace CodeImp.DoomBuilder.Data LoadPalette(); texcount = LoadTextures(texturesonly); flatcount = LoadFlats(flatsonly); + colormapcount = LoadColormaps(colormapsonly); thingcount = LoadDecorateThings(); spritecount = LoadSprites(); LoadInternalSprites(); - + + // Process colormaps (we just put them in as textures) + foreach(KeyValuePair t in colormapsonly) + { + textures.Add(t.Key, t.Value); + texturenames.Add(t.Value.Name); + } + // Process textures foreach(KeyValuePair t in texturesonly) { @@ -369,7 +378,7 @@ namespace CodeImp.DoomBuilder.Data StartBackgroundLoader(); // Output info - General.WriteLogLine("Loaded " + texcount + " textures, " + flatcount + " flats, " + spritecount + " sprites, " + thingcount + " decorate things"); + General.WriteLogLine("Loaded " + texcount + " textures, " + flatcount + " flats, " + colormapcount + " colormaps, " + spritecount + " sprites, " + thingcount + " decorate things"); } // This unloads all data @@ -677,8 +686,60 @@ namespace CodeImp.DoomBuilder.Data #endregion + #region ================== Colormaps + + // This loads the colormaps + private int LoadColormaps(Dictionary list) + { + ICollection images; + int counter = 0; + + // Go for all opened containers + foreach(DataReader dr in containers) + { + // Load colormaps + images = dr.LoadColormaps(); + if(images != null) + { + // Go for all colormaps + foreach(ImageData img in images) + { + // Add or replace in flats list + list.Remove(img.LongName); + list.Add(img.LongName, img); + counter++; + + // Add to preview manager + previews.AddImage(img); + } + } + } + + // Output info + return counter; + } + + // This returns a specific colormap stream + internal Stream GetColormapData(string pname) + { + Stream colormap; + + // Go for all opened containers + for(int i = containers.Count - 1; i >= 0; i--) + { + // This contain provides this flat? + colormap = containers[i].GetColormapData(pname); + if(colormap != null) return colormap; + } + + // No such patch found + return null; + } + + #endregion + #region ================== Textures - + // This loads the textures private int LoadTextures(Dictionary list) { @@ -758,7 +819,7 @@ namespace CodeImp.DoomBuilder.Data // No such patch found return null; } - + // This returns an image by string public ImageData GetTextureImage(string name) { diff --git a/Source/Core/Data/DataReader.cs b/Source/Core/Data/DataReader.cs index e32837f9..84784514 100644 --- a/Source/Core/Data/DataReader.cs +++ b/Source/Core/Data/DataReader.cs @@ -102,6 +102,16 @@ namespace CodeImp.DoomBuilder.Data #endregion + #region ================== Colormaps + + // When implemented, this loads the colormaps + public virtual ICollection LoadColormaps() { return null; } + + // When implemented, this returns the colormap lump + public virtual Stream GetColormapData(string pname) { return null; } + + #endregion + #region ================== Textures // When implemented, this should read the patch names diff --git a/Source/Core/Data/DirectoryReader.cs b/Source/Core/Data/DirectoryReader.cs index b26e982b..5258d1fc 100644 --- a/Source/Core/Data/DirectoryReader.cs +++ b/Source/Core/Data/DirectoryReader.cs @@ -137,6 +137,39 @@ namespace CodeImp.DoomBuilder.Data return null; } + // This finds and returns a colormap stream + public override Stream GetColormapData(string pname) + { + // Error when suspended + if(issuspended) throw new Exception("Data reader is suspended"); + + // Find in any of the wad files + // Note the backward order, because the last wad's images have priority + for(int i = wads.Count - 1; i >= 0; i--) + { + Stream data = wads[i].GetColormapData(pname); + if(data != null) return data; + } + + try + { + // Find in patches directory + string path = Path.Combine(COLORMAPS_DIR, Path.GetDirectoryName(pname)); + string filename = FindFirstFile(path, Path.GetFileName(pname), true); + if((filename != null) && FileExists(filename)) + { + return LoadFile(filename); + } + } + catch(Exception e) + { + General.ErrorLogger.Add(ErrorType.Error, e.GetType().Name + " while loading colormap '" + pname + "' from directory: " + e.Message); + } + + // Nothing found + return null; + } + #endregion #region ================== Sprites @@ -215,9 +248,23 @@ namespace CodeImp.DoomBuilder.Data } // This creates an image - protected override ImageData CreateImage(string name, string filename, bool flat) + protected override ImageData CreateImage(string name, string filename, int imagetype) { - return new FileImage(name, Path.Combine(location.location, filename), flat); + switch(imagetype) + { + case ImageDataFormat.DOOMFLAT: + return new FileImage(name, Path.Combine(location.location, filename), true); + + case ImageDataFormat.DOOMPICTURE: + return new FileImage(name, Path.Combine(location.location, filename), false); + + case ImageDataFormat.DOOMCOLORMAP: + return new ColormapImage(name); + + default: + throw new ArgumentException("Invalid image format specified!"); + return null; + } } // This returns true if the specified file exists diff --git a/Source/Core/Data/ImageDataFormat.cs b/Source/Core/Data/ImageDataFormat.cs index 86f4443c..5bfcc358 100644 --- a/Source/Core/Data/ImageDataFormat.cs +++ b/Source/Core/Data/ImageDataFormat.cs @@ -35,6 +35,7 @@ namespace CodeImp.DoomBuilder.Data public const int UNKNOWN = 0; // No clue. public const int DOOMPICTURE = 1; // Could be Doom Picture format (column list rendered data) public const int DOOMFLAT = 2; // Could be Doom Flat format (raw 8-bit pixel data) + public const int DOOMCOLORMAP = 3; // Could be Doom Colormap format (raw 8-bit pixel palette mapping) // File format signatures private static readonly int[] PNG_SIGNATURE = new int[] { 137, 80, 78, 71, 13, 10, 26, 10 }; @@ -47,6 +48,7 @@ namespace CodeImp.DoomBuilder.Data BinaryReader bindata = new BinaryReader(data); DoomPictureReader picreader; DoomFlatReader flatreader; + DoomColormapReader colormapreader; // First check the formats that provide the means to 'ensure' that // it actually is that format. Then guess the Doom image format. @@ -87,6 +89,14 @@ namespace CodeImp.DoomBuilder.Data flatreader = new DoomFlatReader(palette); if(flatreader.Validate(data)) return flatreader; } + // Could it be a doom colormap? + else if(guessformat == DOOMCOLORMAP) + { + // Check if data is valid for a doom colormap + data.Seek(0, SeekOrigin.Begin); + colormapreader = new DoomColormapReader(palette); + if(colormapreader.Validate(data)) return colormapreader; + } // Format not supported return new UnknownImageReader(); diff --git a/Source/Core/Data/PK3Reader.cs b/Source/Core/Data/PK3Reader.cs index 6b35a7c4..c7abade9 100644 --- a/Source/Core/Data/PK3Reader.cs +++ b/Source/Core/Data/PK3Reader.cs @@ -153,6 +153,31 @@ namespace CodeImp.DoomBuilder.Data return null; } + // This finds and returns a colormap stream + public override Stream GetColormapData(string pname) + { + // Error when suspended + if(issuspended) throw new Exception("Data reader is suspended"); + + // Find in any of the wad files + // Note the backward order, because the last wad's images have priority + for(int i = wads.Count - 1; i >= 0; i--) + { + Stream data = wads[i].GetColormapData(pname); + if(data != null) return data; + } + + // Find in patches directory + string filename = FindFirstFile(COLORMAPS_DIR, pname, true); + if((filename != null) && FileExists(filename)) + { + return LoadFile(filename); + } + + // Nothing found + return null; + } + #endregion #region ================== Sprites @@ -219,9 +244,23 @@ namespace CodeImp.DoomBuilder.Data } // This creates an image - protected override ImageData CreateImage(string name, string filename, bool flat) + protected override ImageData CreateImage(string name, string filename, int imagetype) { - return new PK3FileImage(this, name, filename, flat); + switch(imagetype) + { + case ImageDataFormat.DOOMFLAT: + return new PK3FileImage(this, name, filename, true); + + case ImageDataFormat.DOOMPICTURE: + return new PK3FileImage(this, name, filename, false); + + case ImageDataFormat.DOOMCOLORMAP: + return new ColormapImage(name); + + default: + throw new ArgumentException("Invalid image format specified!"); + return null; + } } // This returns true if the specified file exists diff --git a/Source/Core/Data/PK3StructuredReader.cs b/Source/Core/Data/PK3StructuredReader.cs index b58b3a64..e99a36d6 100644 --- a/Source/Core/Data/PK3StructuredReader.cs +++ b/Source/Core/Data/PK3StructuredReader.cs @@ -39,6 +39,7 @@ namespace CodeImp.DoomBuilder.Data protected const string FLATS_DIR = "flats"; protected const string HIRES_DIR = "hires"; protected const string SPRITES_DIR = "sprites"; + protected const string COLORMAPS_DIR = "colormaps"; #endregion @@ -175,12 +176,12 @@ namespace CodeImp.DoomBuilder.Data // Should we load the images in this directory as textures? if(roottextures) { - collection = LoadDirectoryImages("", false, false); + collection = LoadDirectoryImages("", ImageDataFormat.DOOMPICTURE, false); AddImagesToList(images, collection); } // Add images from texture directory - collection = LoadDirectoryImages(TEXTURES_DIR, false, true); + collection = LoadDirectoryImages(TEXTURES_DIR, ImageDataFormat.DOOMPICTURE, true); AddImagesToList(images, collection); // Load TEXTURE1 lump file @@ -279,12 +280,12 @@ namespace CodeImp.DoomBuilder.Data // Should we load the images in this directory as flats? if(rootflats) { - collection = LoadDirectoryImages("", true, false); + collection = LoadDirectoryImages("", ImageDataFormat.DOOMFLAT, false); AddImagesToList(images, collection); } // Add images from flats directory - collection = LoadDirectoryImages(FLATS_DIR, true, true); + collection = LoadDirectoryImages(FLATS_DIR, ImageDataFormat.DOOMFLAT, true); AddImagesToList(images, collection); // Add images to the container-specific texture set @@ -296,6 +297,38 @@ namespace CodeImp.DoomBuilder.Data #endregion + #region ================== Colormaps + + // This loads the textures + public override ICollection LoadColormaps() + { + Dictionary images = new Dictionary(); + ICollection collection; + + // Error when suspended + if(issuspended) throw new Exception("Data reader is suspended"); + + // Load from wad files + // Note the backward order, because the last wad's images have priority + for(int i = wads.Count - 1; i >= 0; i--) + { + collection = wads[i].LoadColormaps(); + AddImagesToList(images, collection); + } + + // Add images from flats directory + collection = LoadDirectoryImages(COLORMAPS_DIR, ImageDataFormat.DOOMCOLORMAP, true); + AddImagesToList(images, collection); + + // Add images to the container-specific texture set + foreach(ImageData img in images.Values) + textureset.AddFlat(img); + + return new List(images.Values); + } + + #endregion + #region ================== Decorate // This finds and returns a sprite stream @@ -329,7 +362,7 @@ namespace CodeImp.DoomBuilder.Data #region ================== Methods // This loads the images in this directory - private ICollection LoadDirectoryImages(string path, bool flats, bool includesubdirs) + private ICollection LoadDirectoryImages(string path, int imagetype, bool includesubdirs) { List images = new List(); string[] files; @@ -345,7 +378,7 @@ namespace CodeImp.DoomBuilder.Data if(name.Length > 0) { // Add image to list - images.Add(CreateImage(name, f, flats)); + images.Add(CreateImage(name, f, imagetype)); } else { @@ -371,7 +404,7 @@ namespace CodeImp.DoomBuilder.Data } // This must create an image - protected abstract ImageData CreateImage(string name, string filename, bool flat); + protected abstract ImageData CreateImage(string name, string filename, int imagetype); // This must return true if the specified file exists protected abstract bool FileExists(string filename); diff --git a/Source/Core/Data/WADReader.cs b/Source/Core/Data/WADReader.cs index 1502cd3a..44a38f65 100644 --- a/Source/Core/Data/WADReader.cs +++ b/Source/Core/Data/WADReader.cs @@ -60,6 +60,7 @@ namespace CodeImp.DoomBuilder.Data private List patchranges; private List spriteranges; private List textureranges; + private List colormapranges; #endregion @@ -84,12 +85,14 @@ namespace CodeImp.DoomBuilder.Data spriteranges = new List(); flatranges = new List(); textureranges = new List(); + colormapranges = new List(); // Find ranges FindRanges(patchranges, General.Map.Config.PatchRanges, "patches"); FindRanges(spriteranges, General.Map.Config.SpriteRanges, "sprites"); FindRanges(flatranges, General.Map.Config.FlatRanges, "flats"); FindRanges(textureranges, General.Map.Config.TextureRanges, "textures"); + FindRanges(colormapranges, General.Map.Config.ColormapRanges, "colormaps"); // We have no destructor GC.SuppressFinalize(this); @@ -195,6 +198,96 @@ namespace CodeImp.DoomBuilder.Data #endregion + #region ================== Colormaps + + // This loads the textures + public override ICollection LoadColormaps() + { + List images = new List(); + string rangestart, rangeend; + + // Error when suspended + if(issuspended) throw new Exception("Data reader is suspended"); + + // Read ranges from configuration + foreach(DictionaryEntry r in General.Map.Config.ColormapRanges) + { + // Read start and end + rangestart = General.Map.Config.ReadSetting("colormaps." + r.Key + ".start", ""); + rangeend = General.Map.Config.ReadSetting("colormaps." + r.Key + ".end", ""); + if((rangestart.Length > 0) && (rangeend.Length > 0)) + { + // Load texture range + LoadColormapsRange(rangestart, rangeend, ref images); + } + } + + // Add images to the container-specific texture set + foreach(ImageData img in images) + textureset.AddFlat(img); + + // Return result + return images; + } + + // This loads a range of colormaps + private void LoadColormapsRange(string startlump, string endlump, ref List images) + { + int startindex, endindex; + float defaultscale; + ColormapImage image; + + // Determine default scale + defaultscale = General.Map.Config.DefaultTextureScale; + + // Continue until no more start can be found + startindex = file.FindLumpIndex(startlump); + while(startindex > -1) + { + // Find end index + endindex = file.FindLumpIndex(endlump, startindex + 1); + if(endindex > -1) + { + // Go for all lumps between start and end exclusive + for(int i = startindex + 1; i < endindex; i++) + { + // Lump not zero-length? + if(file.Lumps[i].Length > 0) + { + // Make the image object + image = new ColormapImage(file.Lumps[i].Name); + + // Add image to collection + images.Add(image); + } + } + } + + // Find the next start + startindex = file.FindLumpIndex(startlump, startindex + 1); + } + } + + // This finds and returns a colormap stream + public override Stream GetColormapData(string pname) + { + Lump lump; + + // Error when suspended + if(issuspended) throw new Exception("Data reader is suspended"); + + // Find the lump in ranges + foreach(LumpRange range in colormapranges) + { + lump = file.FindLump(pname, range.start, range.end); + if(lump != null) return lump.Stream; + } + + return null; + } + + #endregion + #region ================== Textures // This loads the textures @@ -460,7 +553,7 @@ namespace CodeImp.DoomBuilder.Data return null; } - + #endregion #region ================== Flats diff --git a/Source/Core/IO/DoomColormapReader.cs b/Source/Core/IO/DoomColormapReader.cs new file mode 100644 index 00000000..8b9649b7 --- /dev/null +++ b/Source/Core/IO/DoomColormapReader.cs @@ -0,0 +1,242 @@ + +#region ================== Copyright (c) 2007 Pascal vd Heiden + +/* + * Copyright (c) 2007 Pascal vd Heiden, www.codeimp.com + * This program is released under GNU General Public License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#endregion + +#region ================== Namespaces + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; +using System.Text; +using System.IO; +using CodeImp.DoomBuilder.Map; +using CodeImp.DoomBuilder.Geometry; +using System.Drawing; +using CodeImp.DoomBuilder.Data; +using CodeImp.DoomBuilder.Rendering; +using System.Drawing.Imaging; + +#endregion + +namespace CodeImp.DoomBuilder.IO +{ + internal unsafe class DoomColormapReader : IImageReader + { + #region ================== Variables + + // Palette to use + private Playpal palette; + + #endregion + + #region ================== Constructor / Disposer + + // Constructor + public DoomColormapReader(Playpal palette) + { + // Initialize + this.palette = palette; + + // We have no destructor + GC.SuppressFinalize(this); + } + + #endregion + + #region ================== Methods + + // This validates the data as doom flat + public bool Validate(Stream stream) + { + int remainder; + + // Check if the data can be divided by 256 (each palette is 256 bytes) + remainder = (int)stream.Length % 256; + if(remainder == 0) + { + // Success when not 0 + return (stream.Length > 0); + } + + // Format invalid + return false; + } + + // This creates a Bitmap from the given data + // Returns null on failure + public Bitmap ReadAsBitmap(Stream stream, out int offsetx, out int offsety) + { + offsetx = int.MinValue; + offsety = int.MinValue; + return ReadAsBitmap(stream); + } + + // This creates a Bitmap from the given data + // Returns null on failure + public Bitmap ReadAsBitmap(Stream stream) + { + BitmapData bitmapdata; + PixelColorBlock pixeldata; + PixelColor* targetdata; + int width, height; + Bitmap bmp; + + // Read pixel data + pixeldata = ReadAsPixelData(stream, out width, out height); + if(pixeldata != null) + { + try + { + // Create bitmap and lock pixels + bmp = new Bitmap(width, height, PixelFormat.Format32bppArgb); + bitmapdata = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); + targetdata = (PixelColor*)bitmapdata.Scan0.ToPointer(); + + // Copy the pixels + General.CopyMemory(targetdata, pixeldata.Pointer, (uint)(width * height * sizeof(PixelColor))); + + // Done + bmp.UnlockBits(bitmapdata); + } + catch(Exception e) + { + // Unable to make bitmap + General.ErrorLogger.Add(ErrorType.Error, "Unable to make Doom flat data. " + e.GetType().Name + ": " + e.Message); + return null; + } + } + else + { + // Failed loading picture + bmp = null; + } + + // Return result + return bmp; + } + + // This draws the picture to the given pixel color data + // Throws exception on failure + public unsafe void DrawToPixelData(Stream stream, PixelColor* target, int targetwidth, int targetheight, int x, int y) + { + Bitmap bmp; + BitmapData bmpdata; + PixelColor* pixels; + int ox, oy, tx, ty; + int width, height; + + // Get bitmap + bmp = ReadAsBitmap(stream); + width = bmp.Size.Width; + height = bmp.Size.Height; + + // Lock bitmap pixels + bmpdata = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); + pixels = (PixelColor*)bmpdata.Scan0.ToPointer(); + + // Go for all pixels in the original image + for(ox = 0; ox < width; ox++) + { + for(oy = 0; oy < height; oy++) + { + // Copy this pixel? + if(pixels[oy * width + ox].a > 0.5f) + { + // Calculate target pixel and copy when within bounds + tx = x + ox; + ty = y + oy; + if((tx >= 0) && (tx < targetwidth) && (ty >= 0) && (ty < targetheight)) + target[ty * targetwidth + tx] = pixels[oy * width + ox]; + } + } + } + + // Done + bmp.UnlockBits(bmpdata); + bmp.Dispose(); + } + + // This creates pixel color data from the given data + // Returns null on failure + private PixelColorBlock ReadAsPixelData(Stream stream, out int width, out int height) + { + BinaryReader reader = new BinaryReader(stream); + PixelColorBlock pixeldata = null; + byte[] bytes; + + // Image will be 128x128 + width = 128; + height = 128; + +#if !DEBUG + try + { +#endif + + // Allocate memory + pixeldata = new PixelColorBlock(width, height); + pixeldata.Clear(); + + // Read flat bytes from stream + bytes = new byte[width * height]; + stream.Read(bytes, 0, width * height); + + // Draw blocks using the palette + // We want to draw 8x8 blocks for each color + // 16 wide and 16 high + uint i = 0; + for(int by = 0; by < 16; by++) + { + for(int bx = 0; bx < 16; bx++) + { + PixelColor bc = palette[bytes[i++]]; + PixelColor bc1 = General.Colors.CreateBrightVariant(palette[bytes[i++]]); + PixelColor bc2 = General.Colors.CreateDarkVariant(palette[bytes[i++]]); + for(int py = 0; py < 8; py++) + { + for(int px = 0; px < 8; px++) + { + int p = ((by * 8) + py) * width + (bx * 8) + px; + + // We make the borders slightly brighter and darker + if((py == 0) || (px == 0)) + pixeldata.Pointer[p] = bc1; + else if((py == 7) || (px == 7)) + pixeldata.Pointer[p] = bc2; + else + pixeldata.Pointer[p] = bc; + } + } + } + } + + // Return pointer + return pixeldata; + +#if !DEBUG + } + catch(Exception) + { + // Return nothing + return null; + } +#endif + } + + #endregion + + } +} diff --git a/Source/Core/Rendering/ColorCollection.cs b/Source/Core/Rendering/ColorCollection.cs index 1f8aa6a7..994f5aaf 100644 --- a/Source/Core/Rendering/ColorCollection.cs +++ b/Source/Core/Rendering/ColorCollection.cs @@ -228,29 +228,41 @@ namespace CodeImp.DoomBuilder.Rendering // This creates assist colors internal void CreateAssistColors() { - Color4 o; - Color4 c = new Color4(1f, 0f, 0f, 0f); - // Go for all colors for(int i = 0; i < NUM_COLORS; i++) { - // Get original color - o = colors[i].ToColorValue(); - - // Create brighter color - c.Red = Saturate(o.Red * BRIGHT_MULTIPLIER + BRIGHT_ADDITION); - c.Green = Saturate(o.Green * BRIGHT_MULTIPLIER + BRIGHT_ADDITION); - c.Blue = Saturate(o.Blue * BRIGHT_MULTIPLIER + BRIGHT_ADDITION); - brightcolors[i] = PixelColor.FromInt(c.ToArgb()); - - // Create darker color - c.Red = Saturate(o.Red * DARK_MULTIPLIER + DARK_ADDITION); - c.Green = Saturate(o.Green * DARK_MULTIPLIER + DARK_ADDITION); - c.Blue = Saturate(o.Blue * DARK_MULTIPLIER + DARK_ADDITION); - darkcolors[i] = PixelColor.FromInt(c.ToArgb()); + // Create assist colors + brightcolors[i] = CreateBrightVariant(colors[i]); + darkcolors[i] = CreateDarkVariant(colors[i]); } } + // This creates a brighter color + public PixelColor CreateBrightVariant(PixelColor pc) + { + Color4 o = pc.ToColorValue(); + Color4 c = new Color4(1f, 0f, 0f, 0f); + + // Create brighter color + c.Red = Saturate(o.Red * BRIGHT_MULTIPLIER + BRIGHT_ADDITION); + c.Green = Saturate(o.Green * BRIGHT_MULTIPLIER + BRIGHT_ADDITION); + c.Blue = Saturate(o.Blue * BRIGHT_MULTIPLIER + BRIGHT_ADDITION); + return PixelColor.FromInt(c.ToArgb()); + } + + // This creates a darker color + public PixelColor CreateDarkVariant(PixelColor pc) + { + Color4 o = pc.ToColorValue(); + Color4 c = new Color4(1f, 0f, 0f, 0f); + + // Create darker color + c.Red = Saturate(o.Red * DARK_MULTIPLIER + DARK_ADDITION); + c.Green = Saturate(o.Green * DARK_MULTIPLIER + DARK_ADDITION); + c.Blue = Saturate(o.Blue * DARK_MULTIPLIER + DARK_ADDITION); + return PixelColor.FromInt(c.ToArgb()); + } + // This saves colors to configuration internal void SaveColors(Configuration cfg) {