diff --git a/Build/Configurations/Includes/ZDoom_common.cfg b/Build/Configurations/Includes/ZDoom_common.cfg index 7ccbdb7fb1fe3637fac06c7f9b4b1118cf062079..d371cf1d1fcd5b9c80ba783786e0e0f6e5af2d44 100644 --- a/Build/Configurations/Includes/ZDoom_common.cfg +++ b/Build/Configurations/Includes/ZDoom_common.cfg @@ -40,6 +40,12 @@ common include("Doom_misc.cfg", "textures"); include("ZDoom_misc.cfg", "textures"); } + + //mxd. HiRes sources + hires + { + include("ZDoom_misc.cfg", "hires"); + } // Patch sources patches diff --git a/Build/Configurations/Includes/ZDoom_misc.cfg b/Build/Configurations/Includes/ZDoom_misc.cfg index 7e0474e6d49a2126f052b5fa8edba7f6131d3c68..894dee675af033c64d1b24c1caaf217ce50d20f1 100644 --- a/Build/Configurations/Includes/ZDoom_misc.cfg +++ b/Build/Configurations/Includes/ZDoom_misc.cfg @@ -203,6 +203,15 @@ textures } } +hires //mxd +{ + zdoom1 + { + start = "HI_START"; + end = "HI_END"; + } +} + voxels //mxd { zdoom1 diff --git a/Build/Scripting/ZDoom_DECORATE.cfg b/Build/Scripting/ZDoom_DECORATE.cfg index 4dddd270e8ac6398f2f070fdb580dd0cd9f1aa58..48a4f82dc828cabb43222f431291782e5a3f0f42 100644 --- a/Build/Scripting/ZDoom_DECORATE.cfg +++ b/Build/Scripting/ZDoom_DECORATE.cfg @@ -174,7 +174,7 @@ keywords A_CheckCeiling = "state A_CheckCeiling(str state)\nstate A_CheckCeiling(int offset)"; A_CheckFloor = "state A_CheckFloor(str state)\nstate A_CheckFloor(int offset)"; A_CheckFlag = "state A_CheckFlag(str flagname, state label[, int check_pointer = AAPTR_DEFAULT])"; - A_CheckLOF = "state A_CheckLOF(state jump[, int flags = 0[, float range = 0.0[, float minrange = 0.0[, float angle = 0.0[, float pitch = 0.0[, float offsetheight = 0.0[, float offsetwidth = 0.0[, int ptr_target = AAPTR_DEFAULT]]]]]]]])"; + A_CheckLOF = "state A_CheckLOF(state jump[, int flags = 0[, float range = 0.0[, float minrange = 0.0[, float angle = 0.0[, float pitch = 0.0[, float offsetheight = 0.0[, float offsetwidth = 0.0[, int ptr_target = AAPTR_DEFAULT[, float offsetforward = 0.0]]]]]]]]])"; A_CheckProximity = "state A_CheckProximity(str jump, str classname, float distance[, int count = 1[, int flags = 0[, int pointer = AAPTR_DEFAULT]]])"; A_CheckRange = "state A_CheckRange(float distance, str state[, bool 2d_check = false])\nstate A_CheckRange(float distance, int offset[, bool 2d_check = false])"; A_CheckSight = "state A_CheckSight(str state)\nstate A_CheckSight(int offsete)"; diff --git a/Source/Core/Builder.csproj b/Source/Core/Builder.csproj index cc46ff2ffb9301529801e0b4cf7a3d4b2e2c9b8b..08661b94ed2e4adad8050e1980c77a5df3470546 100644 --- a/Source/Core/Builder.csproj +++ b/Source/Core/Builder.csproj @@ -808,7 +808,8 @@ <Compile Include="Data\CameraTextureImage.cs" /> <Compile Include="Data\ColorImage.cs" /> <Compile Include="Data\ColormapImage.cs" /> - <Compile Include="Data\HighResImage.cs" /> + <Compile Include="Data\HiResImage.cs" /> + <Compile Include="Data\TEXTURESImage.cs" /> <Compile Include="Data\PK3FileImage.cs" /> <Compile Include="Data\PK3StructuredReader.cs" /> <Compile Include="Data\DynamicBitmapImage.cs" /> diff --git a/Source/Core/Config/GameConfiguration.cs b/Source/Core/Config/GameConfiguration.cs index 1b40ea2d89cc9fd2598fc72ee2a3b2db306245b2..164e84187847563dc757d39b44ef2e32bf4fcf0b 100644 --- a/Source/Core/Config/GameConfiguration.cs +++ b/Source/Core/Config/GameConfiguration.cs @@ -101,6 +101,7 @@ namespace CodeImp.DoomBuilder.Config // Texture/flat/voxel sources private readonly IDictionary textureranges; + private readonly IDictionary hiresranges; //mxd private readonly IDictionary flatranges; private readonly IDictionary patchranges; private readonly IDictionary spriteranges; @@ -221,6 +222,7 @@ namespace CodeImp.DoomBuilder.Config // Texture/flat/voxel sources public IDictionary TextureRanges { get { return textureranges; } } + public IDictionary HiResRanges { get { return hiresranges; } } //mxd public IDictionary FlatRanges { get { return flatranges; } } public IDictionary PatchRanges { get { return patchranges; } } public IDictionary SpriteRanges { get { return spriteranges; } } @@ -383,6 +385,7 @@ namespace CodeImp.DoomBuilder.Config // Get texture and flat sources textureranges = cfg.ReadSetting("textures", new Hashtable()); + hiresranges = cfg.ReadSetting("hires", new Hashtable()); //mxd flatranges = cfg.ReadSetting("flats", new Hashtable()); patchranges = cfg.ReadSetting("patches", new Hashtable()); spriteranges = cfg.ReadSetting("sprites", new Hashtable()); diff --git a/Source/Core/Controls/FlatSelectorControl.cs b/Source/Core/Controls/FlatSelectorControl.cs index e14f79ad9f728d5154a57812f883abdec46c4cbf..a0d287ce50db1871a7d842bbf1a8d25e2cd2f6d2 100644 --- a/Source/Core/Controls/FlatSelectorControl.cs +++ b/Source/Core/Controls/FlatSelectorControl.cs @@ -67,7 +67,8 @@ namespace CodeImp.DoomBuilder.Controls if(usepreviews ? !texture.IsPreviewLoaded : !texture.IsImageLoaded) timer.Start(); //mxd // Set the image - return new Bitmap(usepreviews ? texture.GetPreview() : texture.GetBitmap()); + // mxd. GetPreview() returns a copy of preview, GetBitmap() returns actual bitmap + return (usepreviews ? texture.GetPreview() : new Bitmap(texture.GetBitmap())); } } diff --git a/Source/Core/Controls/ScriptEditorPanel.cs b/Source/Core/Controls/ScriptEditorPanel.cs index 184242fc706e95d21695c909c6fb1633225d32fb..ce39b01c74d8da1542de15acc4c151f6ad13a530 100644 --- a/Source/Core/Controls/ScriptEditorPanel.cs +++ b/Source/Core/Controls/ScriptEditorPanel.cs @@ -180,7 +180,7 @@ namespace CodeImp.DoomBuilder.Controls tabs.SelectedTab = activetab; } //mxd. Select "Scripts" tab, because that's what user will want 99% of time - else + else if(tabs.TabPages.Count > 0) { int scriptsindex = GetTabPageIndex("SCRIPTS"); tabs.SelectedIndex = (scriptsindex == -1 ? 0 : scriptsindex); @@ -195,8 +195,13 @@ namespace CodeImp.DoomBuilder.Controls //mxd. If the map or script navigator has any compile errors, show them if(activetab != null) { - List<CompilerError> errors = activetab.UpdateNavigator(); - ShowErrors(General.Map.Errors.Count > 0 ? General.Map.Errors : errors); + List<CompilerError> errors = (General.Map.Errors.Count > 0 ? General.Map.Errors : activetab.UpdateNavigator()); + if(errors.Count > 0) ShowErrors(errors); + else ClearErrors(); + } + else + { + ClearErrors(); } // Done @@ -574,6 +579,11 @@ namespace CodeImp.DoomBuilder.Controls buttonunindent.Enabled = (t != null && t.Scintilla.Lines[t.Scintilla.CurrentLine].Indentation > 0); //mxd buttonwhitespace.Enabled = (t != null); //mxd buttonwordwrap.Enabled = (t != null); //mxd + searchbox.Enabled = (t != null); //mxd + searchprev.Enabled = (t != null); //mxd + searchnext.Enabled = (t != null); //mxd + searchmatchcase.Enabled = (t != null); //mxd + searchwholeword.Enabled = (t != null); //mxd if(t != null) { diff --git a/Source/Core/Controls/TextureSelectorControl.cs b/Source/Core/Controls/TextureSelectorControl.cs index cc60bd6294f447c51e063ae093d15e031e0c5d6d..9f5d580c6a75b9fd64b5d023243b12f705c9b953 100644 --- a/Source/Core/Controls/TextureSelectorControl.cs +++ b/Source/Core/Controls/TextureSelectorControl.cs @@ -79,7 +79,8 @@ namespace CodeImp.DoomBuilder.Controls else if(!texture.IsImageLoaded) texture.LoadImage(); //mxd. In some cases the image may never me loaded by the DataManager // Set the image - return new Bitmap((usepreviews ? texture.GetPreview() : texture.GetBitmap())); + // mxd. GetPreview() returns a copy of preview, GetBitmap() returns actual bitmap + return (usepreviews ? texture.GetPreview() : new Bitmap(texture.GetBitmap())); } } diff --git a/Source/Core/Data/DataManager.cs b/Source/Core/Data/DataManager.cs index 54e6b1f4121981b1985c5507e3a143eed904a354..d8c6a6a49558c8570026e7fbf354f3572d5790c9 100644 --- a/Source/Core/Data/DataManager.cs +++ b/Source/Core/Data/DataManager.cs @@ -61,6 +61,7 @@ namespace CodeImp.DoomBuilder.Data public const string INTERNAL_PREFIX = "internal:"; public const int CLASIC_IMAGE_NAME_LENGTH = 8; //mxd + private const int MAX_SKYTEXTURE_SIZE = 2048; //mxd #endregion @@ -454,7 +455,7 @@ namespace CodeImp.DoomBuilder.Data if(t.Value.HasLongName) flatnames.Add(t.Value.ShortName); flatnames.Add(t.Value.Name); } - else if(t.Value is HighResImage || t.Value is SimpleTextureImage) //mxd. Textures defined in TEXTURES or placed between TX_START and TX_END markers override "regular" flats in ZDoom + else if(t.Value is TEXTURESImage || t.Value is SimpleTextureImage) //mxd. Textures defined in TEXTURES or placed between TX_START and TX_END markers override "regular" flats in ZDoom { //TODO: check this! flats[t.Key] = t.Value; @@ -488,6 +489,7 @@ namespace CodeImp.DoomBuilder.Data } //mxd. Should be done after loading textures... + int hirestexcount = LoadHiResTextures(); LoadGldefs(actorsbyclass); //mxd. Create camera textures. Should be done after loading textures. @@ -535,7 +537,7 @@ namespace CodeImp.DoomBuilder.Data StartBackgroundLoader(); // Output info - General.WriteLogLine("Loaded " + texcount + " textures, " + flatcount + " flats, " + + General.WriteLogLine("Loaded " + texcount + " textures, " + flatcount + " flats, " + hirestexcount + " hires textures, " + colormapcount + " colormaps, " + spritecount + " sprites, " + thingcount + " decorate things, " + modeldefentries.Count + " model/voxel deinitions, " + gldefsentries.Count + " dynamic light definitions, " + @@ -988,8 +990,7 @@ namespace CodeImp.DoomBuilder.Data foreach(ImageData img in images) { // Add or replace in textures list - list.Remove(img.LongName); - list.Add(img.LongName, img); + list[img.LongName] = img; counter++; //mxd. Also add as short name when texture name is longer than 8 chars @@ -998,8 +999,7 @@ namespace CodeImp.DoomBuilder.Data if(img.HasLongName) { long longshortname = Lump.MakeLongName(Path.GetFileNameWithoutExtension(img.Name), false); - nametranslation.Remove(longshortname); - nametranslation.Add(longshortname, img.LongName); + nametranslation[longshortname] = img.LongName; } else if(img is TextureImage && nametranslation.ContainsKey(img.LongName)) { @@ -1070,7 +1070,9 @@ namespace CodeImp.DoomBuilder.Data public ImageData GetTextureImage(long longname) { // Does this texture exist? - if(textures.ContainsKey(longname) && textures[longname] is HighResImage) return textures[longname]; //TEXTURES textures should still override regular ones... + if(textures.ContainsKey(longname) + && (textures[longname] is TEXTURESImage || textures[longname] is HiResImage)) + return textures[longname]; //TEXTURES and HiRes textures should still override regular ones... if(texturenamesshorttofull.ContainsKey(longname)) return textures[texturenamesshorttofull[longname]]; //mxd if(textures.ContainsKey(longname)) return textures[longname]; @@ -1079,7 +1081,8 @@ namespace CodeImp.DoomBuilder.Data } //mxd. This tries to find and load any image with given name - internal Bitmap GetTextureBitmap(string name) + internal Bitmap GetTextureBitmap(string name) { Vector2D unused = new Vector2D(); return GetTextureBitmap(name, out unused); } + internal Bitmap GetTextureBitmap(string name, out Vector2D scale) { // Check the textures first... ImageData img = GetTextureImage(name); @@ -1091,11 +1094,15 @@ namespace CodeImp.DoomBuilder.Data if(!img.IsImageLoaded) img.LoadImage(); if(!img.LoadFailed) { - return new Bitmap(img.GetBitmap()); + // HiResImage will not give us it's actual scale + Bitmap texture = img.GetBitmap(); + scale = new Vector2D((float)img.Width / texture.Width, (float)img.Height / texture.Height); + return texture; } } // Try to find any image... + scale = new Vector2D(1.0f, 1.0f); for(int i = containers.Count - 1; i >= 0; i--) { // This container has a lump with given name? @@ -1145,7 +1152,8 @@ namespace CodeImp.DoomBuilder.Data name = name.Substring(0, CLASIC_IMAGE_NAME_LENGTH); long hash = MurmurHash2.Hash(name.Trim().ToUpperInvariant()); - if(textures.ContainsKey(hash) && textures[hash] is HighResImage) return textures[hash].Name; //TEXTURES textures should still override regular ones... + if(textures.ContainsKey(hash) && (textures[hash] is TEXTURESImage || textures[hash] is HiResImage)) + return textures[hash].Name; //TEXTURES and HiRes textures should still override regular ones... if(texturenamesshorttofull.ContainsKey(hash)) return textures[texturenamesshorttofull[hash]].Name; if(textures.ContainsKey(hash)) return textures[hash].Name; return name; @@ -1154,7 +1162,8 @@ namespace CodeImp.DoomBuilder.Data //mxd internal long GetFullLongTextureName(long hash) { - if(textures.ContainsKey(hash) && textures[hash] is HighResImage) return hash; //TEXTURES textures should still override regular ones... + if(textures.ContainsKey(hash) && (textures[hash] is TEXTURESImage || textures[hash] is HiResImage)) + return hash; //TEXTURES and HiRes textures should still override regular ones... return (General.Map.Config.UseLongTextureNames && texturenamesshorttofull.ContainsKey(hash) ? texturenamesshorttofull[hash] : hash); } @@ -1207,8 +1216,7 @@ namespace CodeImp.DoomBuilder.Data foreach(ImageData img in images) { // Add or replace in flats list - list.Remove(img.LongName); - list.Add(img.LongName, img); + list[img.LongName] = img; //mxd counter++; //mxd. Also add as short name when texture name is longer than 8 chars @@ -1217,8 +1225,7 @@ namespace CodeImp.DoomBuilder.Data if(img.HasLongName) { long longshortname = Lump.MakeLongName(Path.GetFileNameWithoutExtension(img.Name), false); - nametranslation.Remove(longshortname); - nametranslation.Add(longshortname, img.LongName); + nametranslation[longshortname] = img.LongName; } else if(img is FlatImage && nametranslation.ContainsKey(img.LongName)) { @@ -1274,7 +1281,8 @@ namespace CodeImp.DoomBuilder.Data public ImageData GetFlatImage(long longname) { // Does this flat exist? - if(flats.ContainsKey(longname) && flats[longname] is HighResImage) return flats[longname]; //TEXTURES flats should still override regular ones... + if(flats.ContainsKey(longname) && (flats[longname] is TEXTURESImage || flats[longname] is HiResImage)) + return flats[longname]; //TEXTURES and HiRes flats should still override regular ones... if(flatnamesshorttofull.ContainsKey(longname)) return flats[flatnamesshorttofull[longname]]; //mxd if(flats.ContainsKey(longname)) return flats[longname]; @@ -1296,7 +1304,8 @@ namespace CodeImp.DoomBuilder.Data name = name.Substring(0, CLASIC_IMAGE_NAME_LENGTH); long hash = MurmurHash2.Hash(name.ToUpperInvariant()); - if(flats.ContainsKey(hash) && flats[hash] is HighResImage) return flats[hash].Name; //TEXTURES flats should still override regular ones... + if(flats.ContainsKey(hash) && (flats[hash] is TEXTURESImage || flats[hash] is HiResImage)) + return flats[hash].Name; //TEXTURES and HiRes flats should still override regular ones... if(flatnamesshorttofull.ContainsKey(hash)) return flats[flatnamesshorttofull[hash]].Name; if(flats.ContainsKey(hash)) return flats[hash].Name; return name; @@ -1305,12 +1314,88 @@ namespace CodeImp.DoomBuilder.Data //mxd internal long GetFullLongFlatName(long hash) { - if(flats.ContainsKey(hash) && flats[hash] is HighResImage) return hash; //TEXTURES flats should still override regular ones... + if(flats.ContainsKey(hash) && (flats[hash] is TEXTURESImage || flats[hash] is HiResImage)) + return hash; //TEXTURES and HiRes flats should still override regular ones... return (General.Map.Config.UseLongTextureNames && flatnamesshorttofull.ContainsKey(hash) ? flatnamesshorttofull[hash] : hash); } #endregion + #region ================== mxd. HiRes textures + + // This loads the textures + private int LoadHiResTextures() + { + int counter = 0; + + // Go for all opened containers + foreach(DataReader dr in containers) + { + //mxd. Load HiRes texures + IEnumerable<HiResImage> hiresimages = dr.LoadHiResTextures(); + if(hiresimages != null) + { + // Go for all textures + foreach(HiResImage img in hiresimages) + { + bool replaced = false; + + // Replace texture? + if(textures.ContainsKey(img.LongName)) + { + HiResImage replacer = new HiResImage(img); + replacer.ApplySettings(textures[img.LongName]); + textures[img.LongName] = replacer; + replaced = true; + + // Add to preview manager + previews.AddImage(replacer); + } + + // Replace flat? + if(flats.ContainsKey(img.LongName)) + { + HiResImage replacer = new HiResImage(img); + replacer.ApplySettings(flats[img.LongName]); + flats[img.LongName] = replacer; + replaced = true; + + // Add to preview manager + previews.AddImage(replacer); + } + + if(!replaced) + { + General.ErrorLogger.Add(ErrorType.Warning, "HiRes texture \"" + Path.Combine(dr.Location.GetShortName(), img.FilePathName) + "\" does not override any existing texture or flat."); + dr.TextureSet.AddTexture(img); + } + + counter++; + } + } + } + + // Output info + return counter; + } + + //mxd. This returns a specific HiRes texture stream + internal Stream GetHiResTextureData(string name) + { + // Go for all opened containers + for(int i = containers.Count - 1; i >= 0; i--) + { + // This container provides this texture? + Stream data = containers[i].GetHiResTextureData(name); + if(data != null) return data; + } + + // No such patch texture + return null; + } + + #endregion + #region ================== Sprites // This loads the hard defined sprites (not all the lumps, we do that on a need-to-know basis, see LoadThingSprites) @@ -2502,10 +2587,11 @@ namespace CodeImp.DoomBuilder.Data else { // Create classic texture - Bitmap img = GetTextureBitmap(skytex); + Vector2D scale; + Bitmap img = GetTextureBitmap(skytex, out scale); if(img != null) { - skybox = MakeClassicSkyBox(img); + skybox = MakeClassicSkyBox(img, scale); } } } @@ -2531,12 +2617,15 @@ namespace CodeImp.DoomBuilder.Data //INFO: 1. Looks like GZDoom tries to tile a sky texture into a 1024 pixel width texture. //INFO: 2. If sky texture width <= height, it will be tiled to fit into 512 pixel height texture vertically. - private static CubeTexture MakeClassicSkyBox(Bitmap img) + private static CubeTexture MakeClassicSkyBox(Bitmap img) { return MakeClassicSkyBox(img, new Vector2D(1.0f, 1.0f)); } + private static CubeTexture MakeClassicSkyBox(Bitmap img, Vector2D scale) { // Get averaged top and bottom colors from the original image int tr = 0, tg = 0, tb = 0, br = 0, bg = 0, bb = 0; - const int defaultcolorsampleheight = 28; + int defaultcolorsampleheight = (int)Math.Round(28 / scale.x); int colorsampleheight = Math.Max(1, Math.Min(defaultcolorsampleheight, img.Height / 2)); // TODO: is this value calculated from the image's height? + int scaledwidth = (int)Math.Round(img.Width * scale.x); + int scaledheight = (int)Math.Round(img.Height * scale.y); bool dogradients = colorsampleheight < img.Height / 2; for(int w = 0; w < img.Width; w++) @@ -2559,11 +2648,11 @@ namespace CodeImp.DoomBuilder.Data Color topcolor = Color.FromArgb(255, tr / pixelscount, tg / pixelscount, tb / pixelscount); Color bottomcolor = Color.FromArgb(255, br / pixelscount, bg / pixelscount, bb / pixelscount); - // Make tiling image - int horiztiles = (int)Math.Ceiling(1024.0f / img.Width); - int verttiles = img.Height > 256 ? 1 : 2; + // Make tiling image. Take custom scale into account + int horiztiles = (int)Math.Ceiling(1024.0f / scaledwidth); + int verttiles = scaledheight > 256 ? 1 : 2; - Bitmap skyimage = new Bitmap(1024, img.Height * verttiles, img.PixelFormat); + Bitmap skyimage = new Bitmap((int)Math.Round(1024 / scale.x), img.Height * verttiles, img.PixelFormat); // Draw original image using(Graphics g = Graphics.FromImage(skyimage)) @@ -2578,7 +2667,7 @@ namespace CodeImp.DoomBuilder.Data } // Make top and bottom images - const int capsimgsize = 16; + int capsimgsize = (int)Math.Round(16 / scale.x); Bitmap topimg = new Bitmap(capsimgsize, capsimgsize); using(Graphics g = Graphics.FromImage(topimg)) { @@ -2613,6 +2702,13 @@ namespace CodeImp.DoomBuilder.Data } } + // Rendering errors occure when image size exceeds MAX_SKYTEXTURE_SIZE... + if(skyimage.Width > MAX_SKYTEXTURE_SIZE || skyimage.Height > MAX_SKYTEXTURE_SIZE) + { + float scaler = (float)MAX_SKYTEXTURE_SIZE / Math.Max(skyimage.Width, skyimage.Height); + skyimage = ResizeImage(skyimage, (int)Math.Round(skyimage.Width * scaler), (int)Math.Round(skyimage.Height * scaler)); + } + // Get Device and shader... Device device = General.Map.Graphics.Device; World3DShader effect = General.Map.Graphics.Shaders.World3D; @@ -2639,7 +2735,8 @@ namespace CodeImp.DoomBuilder.Data BoundingBoxSizes bbs = new BoundingBoxSizes(); Stream modeldata = General.ThisAssembly.GetManifestResourceStream("CodeImp.DoomBuilder.Resources.SkySphere.md3"); ModelReader.MD3LoadResult meshes = ModelReader.ReadMD3Model(ref bbs, true, modeldata, device, 0); - if(meshes.Meshes.Count != 3) throw new Exception("Skybox creation failed: " + meshes.Errors); + if(meshes.Meshes.Count != 3) throw new Exception("Skybox creation failed: " + + (string.IsNullOrEmpty(meshes.Errors) ? "skybox model must contain 3 surfaces" : meshes.Errors)); // Make skysphere textures... Texture texside = TextureFromBitmap(device, skyimage); @@ -2648,9 +2745,9 @@ namespace CodeImp.DoomBuilder.Data // Calculate model scaling (gl.skydone.cpp:RenderDome() in GZDoom) float yscale; - if(img.Height < 128) yscale = 128 / 230.0f; - else if(img.Height < 200) yscale = img.Height / 230.0f; - else if(img.Height < 241) yscale = 1.0f + ((img.Height - 200.0f) / 200.0f) * 1.17f; + if(scaledheight < 128) yscale = 128 / 230.0f; + else if(scaledheight < 200) yscale = scaledheight / 230.0f; + else if(scaledheight < 241) yscale = 1.0f + ((scaledheight - 200.0f) / 200.0f) * 1.17f; else yscale = 1.2f * 1.17f; // I guess my sky model doesn't exactly match the one GZDoom generates... @@ -2776,7 +2873,7 @@ namespace CodeImp.DoomBuilder.Data } // Make it Po2 - targetsize = General.NextPowerOf2(targetsize); + targetsize = Math.Min(General.NextPowerOf2(targetsize), MAX_SKYTEXTURE_SIZE); for(int i = 0; i < sides.Length; i++) { @@ -2809,7 +2906,7 @@ namespace CodeImp.DoomBuilder.Data } // Make it Po2 - targetsize = General.NextPowerOf2(targetsize); + targetsize = Math.Min(General.NextPowerOf2(targetsize), MAX_SKYTEXTURE_SIZE); // Resize if needed if(sideimg.Width != targetsize * 4 || sideimg.Height != targetsize) diff --git a/Source/Core/Data/DataReader.cs b/Source/Core/Data/DataReader.cs index 13091f339d57b7064a8509f162991cc9477c16a5..a3be5e1a2ff0ddab31c0947628914b9a5550a135 100644 --- a/Source/Core/Data/DataReader.cs +++ b/Source/Core/Data/DataReader.cs @@ -179,6 +179,12 @@ namespace CodeImp.DoomBuilder.Data // When implemented, this loads the textures public abstract IEnumerable<ImageData> LoadTextures(PatchNames pnames, Dictionary<string, TexturesParser> cachedparsers); + + //mxd. When implemented, this returns the HiRes texture lump + public abstract Stream GetHiResTextureData(string pname); + + //mxd. When implemented, this loads the HiRes textures + public abstract IEnumerable<HiResImage> LoadHiResTextures(); #endregion diff --git a/Source/Core/Data/DirectoryReader.cs b/Source/Core/Data/DirectoryReader.cs index d33109d3f3ecaa022e42bf90e1ef227f18bb83fa..6713b516747475c75945b0c67682be47b7e4deb0 100644 --- a/Source/Core/Data/DirectoryReader.cs +++ b/Source/Core/Data/DirectoryReader.cs @@ -177,6 +177,37 @@ namespace CodeImp.DoomBuilder.Data return null; } + //mxd. This finds and returns a HiRes textue stream + public override Stream GetHiResTextureData(string name) + { + // 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].GetHiResTextureData(name); + if(data != null) return data; + } + + try + { + // Find in hires directory + string path = Path.Combine(HIRES_DIR, Path.GetDirectoryName(name)); + string filename = FindFirstFile(path, Path.GetFileName(name), false); + if(!string.IsNullOrEmpty(filename) && FileExists(filename)) + return LoadFile(filename); + } + catch(Exception e) + { + General.ErrorLogger.Add(ErrorType.Error, e.GetType().Name + " while loading HiRes texture \"" + name + "\" from directory: " + e.Message); + } + + // Nothing found + return null; + } + // This finds and returns a colormap stream public override Stream GetColormapData(string pname) { diff --git a/Source/Core/Data/HiResImage.cs b/Source/Core/Data/HiResImage.cs new file mode 100644 index 0000000000000000000000000000000000000000..5d2f5d7c71b880fbe9a2c9173481587209b3bdf6 --- /dev/null +++ b/Source/Core/Data/HiResImage.cs @@ -0,0 +1,158 @@ +#region ================== Namespaces + +using System; +using System.Drawing; +using System.IO; +using CodeImp.DoomBuilder.Geometry; +using CodeImp.DoomBuilder.IO; + +#endregion + +namespace CodeImp.DoomBuilder.Data +{ + internal class HiResImage : ImageData + { + #region ================== Variables + + private Vector2D sourcescale; + private Size sourcesize; + private bool overridesettingsapplied; + + #endregion + + #region ================== Properties + + public override int Width { get { return sourcesize.Width; } } + public override int Height { get { return sourcesize.Height; } } + public override float ScaledWidth { get { return (float)Math.Round(sourcesize.Width * sourcescale.x); } } + public override float ScaledHeight { get { return (float)Math.Round(sourcesize.Height * sourcescale.y); } } + public override Vector2D Scale { get { return sourcescale; } } + + #endregion + + #region ================== Constructor / Disposer + + public HiResImage(string name) + { + // Initialize + this.scale.x = General.Map.Config.DefaultTextureScale; + this.scale.y = General.Map.Config.DefaultTextureScale; + this.sourcescale = scale; + this.sourcesize = Size.Empty; + + if(name.Length > DataManager.CLASIC_IMAGE_NAME_LENGTH) + name = name.Substring(0, DataManager.CLASIC_IMAGE_NAME_LENGTH); + + SetName(name.ToUpperInvariant()); + + // We have no destructor + GC.SuppressFinalize(this); + } + + // Copy constructor + public HiResImage(HiResImage other) + { + // Initialize + this.scale = other.scale; + this.sourcescale = other.sourcescale; + this.sourcesize = other.sourcesize; + + SetName(other.name); + + // We have no destructor + GC.SuppressFinalize(this); + } + + #endregion + + #region ================== Methods + + internal void ApplySettings(ImageData overridden) + { + virtualname = overridden.VirtualName; + isFlat = overridden.IsFlat; + overridesettingsapplied = true; + + if(!overridden.IsImageLoaded) overridden.LoadImage(); + if(overridden.ImageState == ImageLoadState.Ready) + { + // Store source properteis + sourcesize = new Size(overridden.Width, overridden.Height); + sourcescale = overridden.Scale; + } + } + + // This loads the image + protected override void LocalLoadImage() + { + // Checks + if(this.IsImageLoaded) return; + + lock(this) + { + // Get the patch data stream + if(bitmap != null) bitmap.Dispose(); bitmap = null; + Stream data = General.Map.Data.GetHiResTextureData(shortname); + if(data != null) + { + // Copy patch data to memory + data.Seek(0, SeekOrigin.Begin); + byte[] membytes = new byte[(int)data.Length]; + data.Read(membytes, 0, (int)data.Length); + MemoryStream mem = new MemoryStream(membytes); + mem.Seek(0, SeekOrigin.Begin); + + // Get a reader for the data + IImageReader reader = ImageDataFormat.GetImageReader(mem, (isFlat ? ImageDataFormat.DOOMFLAT : ImageDataFormat.DOOMPICTURE), General.Map.Data.Palette); + if(!(reader is UnknownImageReader)) + { + // Load the image + mem.Seek(0, SeekOrigin.Begin); + try { bitmap = reader.ReadAsBitmap(mem); } + catch(InvalidDataException) + { + // Data cannot be read! + bitmap = null; + } + } + + // Not loaded? + if(bitmap == null) + { + General.ErrorLogger.Add(ErrorType.Error, "Image lump \"" + shortname + "\" data format could not be read, while loading texture \"" + this.Name + "\". Does this lump contain valid picture data at all?"); + loadfailed = true; + } + else + { + // Get width and height from image + width = bitmap.Size.Width; + height = bitmap.Size.Height; + + // Apply source overrides? + if(!sourcesize.IsEmpty) + { + scale = new Vector2D(ScaledWidth / width, ScaledHeight / height); + } + else if(overridesettingsapplied) + { + General.ErrorLogger.Add(ErrorType.Warning, "Unable to get source texture dimensions while loading HiRes texture \"" + this.Name + "\"."); + } + } + + // Done + mem.Dispose(); + } + else + { + General.ErrorLogger.Add(ErrorType.Error, "Image lump \"" + shortname + "\" could not be found, while loading texture \"" + this.Name + "\". Did you forget to include required resources?"); + loadfailed = true; + } + + // Pass on to base + base.LocalLoadImage(); + } + } + + #endregion + } +} diff --git a/Source/Core/Data/ImageData.cs b/Source/Core/Data/ImageData.cs index 365ac8ae4875bb1c77176e64a337d606fc257793..9f1303bf6ae407f233987439f6c04083832812d9 100644 --- a/Source/Core/Data/ImageData.cs +++ b/Source/Core/Data/ImageData.cs @@ -113,13 +113,13 @@ namespace CodeImp.DoomBuilder.Data public bool IsReferenced { get { return (references > 0) || usedinmap; } } public bool UsedInMap { get { return usedinmap; } } public int MipMapLevels { get { return mipmaplevels; } set { mipmaplevels = value; } } - public int Width { get { return width; } } - public int Height { get { return height; } } + public virtual int Width { get { return width; } } + public virtual int Height { get { return height; } } internal int PreviewIndex { get { return previewindex; } set { previewindex = value; } } //mxd. Scaled texture size is integer in ZDoom. - public float ScaledWidth { get { return (float)Math.Round(width * scale.x); } } - public float ScaledHeight { get { return (float)Math.Round(height * scale.y); } } - public Vector2D Scale { get { return scale; } } + public virtual float ScaledWidth { get { return (float)Math.Round(width * scale.x); } } + public virtual float ScaledHeight { get { return (float)Math.Round(height * scale.y); } } + public virtual Vector2D Scale { get { return scale; } } public bool WorldPanning { get { return worldpanning; } } public int Level { get { return level; } } //mxd diff --git a/Source/Core/Data/PK3Reader.cs b/Source/Core/Data/PK3Reader.cs index e063795f703c8468dde93998a1948e6b3fa3bba9..8b1ec9da3352115fd41276e6139f99d73e1ff8ee 100644 --- a/Source/Core/Data/PK3Reader.cs +++ b/Source/Core/Data/PK3Reader.cs @@ -224,6 +224,29 @@ namespace CodeImp.DoomBuilder.Data return null; } + //mxd. This finds and returns a HiRes textue stream + public override Stream GetHiResTextureData(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].GetTextureData(pname, false); + if(data != null) return data; + } + + // Find in HiRes directory + string filename = FindFirstFile(HIRES_DIR, pname, false); + if(!string.IsNullOrEmpty(filename) && FileExists(filename)) + return LoadFile(filename); + + // Nothing found + return null; + } + // This finds and returns a colormap stream public override Stream GetColormapData(string pname) { diff --git a/Source/Core/Data/PK3StructuredReader.cs b/Source/Core/Data/PK3StructuredReader.cs index 195bf01c203b27354ecabcce47bfb2342c20e325..a6cb81ac3e6f26245b9fa1ecb7769c89819b7bd4 100644 --- a/Source/Core/Data/PK3StructuredReader.cs +++ b/Source/Core/Data/PK3StructuredReader.cs @@ -217,7 +217,7 @@ namespace CodeImp.DoomBuilder.Data { MemoryStream filedata = LoadFile(texturesfile); TextResourceData data = new TextResourceData(this, filedata, texturesfile, true); //mxd - cachedparsers.Add(fullpath, WADReader.LoadHighresTextures(data, ref imgset)); //mxd + cachedparsers.Add(fullpath, WADReader.LoadTEXTURESTextures(data, ref imgset)); //mxd filedata.Dispose(); } } @@ -234,7 +234,31 @@ namespace CodeImp.DoomBuilder.Data return new List<ImageData>(images.Values); } - + + //mxd + public override IEnumerable<HiResImage> LoadHiResTextures() + { + // Go for all files + string[] files = GetAllFiles(HIRES_DIR, false); + List<HiResImage> result = new List<HiResImage>(files.Length); + foreach(string f in files) + { + string name = Path.GetFileNameWithoutExtension(f); + if(string.IsNullOrEmpty(name)) + { + // Can't load image without name + General.ErrorLogger.Add(ErrorType.Error, "Can't load an unnamed HiRes texture from \"" + HIRES_DIR + "\". Please consider giving names to your resources."); + } + else + { + // Add image to list + result.Add(new HiResImage(name)); + } + } + + return result; + } + // This returns the patch names from the PNAMES lump // A directory resource does not support this lump, but the wads in the directory may contain this lump public override PatchNames LoadPatchNames() @@ -314,7 +338,7 @@ namespace CodeImp.DoomBuilder.Data { MemoryStream filedata = LoadFile(texturesfile); TextResourceData data = new TextResourceData(this, filedata, texturesfile, true); //mxd - cachedparsers.Add(fullpath, WADReader.LoadHighresFlats(data, ref imgset)); //mxd + cachedparsers.Add(fullpath, WADReader.LoadTEXTURESFlats(data, ref imgset)); //mxd filedata.Dispose(); } } @@ -388,7 +412,7 @@ namespace CodeImp.DoomBuilder.Data { MemoryStream filedata = LoadFile(texturesfile); TextResourceData data = new TextResourceData(this, filedata, texturesfile, true); //mxd - cachedparsers.Add(fullpath, WADReader.LoadHighresSprites(data, ref imgset)); //mxd + cachedparsers.Add(fullpath, WADReader.LoadTEXTURESSprites(data, ref imgset)); //mxd filedata.Dispose(); } } diff --git a/Source/Core/Data/HighResImage.cs b/Source/Core/Data/TEXTURESImage.cs similarity index 94% rename from Source/Core/Data/HighResImage.cs rename to Source/Core/Data/TEXTURESImage.cs index 9ec9da1d65fa25d33b8cf1fc4aed6faee44371ee..d67619120693a9684a276dfe89076ca55873bc8b 100644 --- a/Source/Core/Data/HighResImage.cs +++ b/Source/Core/Data/TEXTURESImage.cs @@ -29,7 +29,7 @@ using CodeImp.DoomBuilder.Rendering; namespace CodeImp.DoomBuilder.Data { - internal sealed unsafe class HighResImage : ImageData + internal sealed unsafe class TEXTURESImage : ImageData { #region ================== Variables @@ -40,7 +40,7 @@ namespace CodeImp.DoomBuilder.Data #region ================== Constructor / Disposer // Constructor - public HighResImage(string name, string virtualpath, int width, int height, float scalex, float scaley, bool worldpanning, bool isflat) + public TEXTURESImage(string name, string virtualpath, int width, int height, float scalex, float scaley, bool worldpanning, bool isflat) { // Initialize this.width = width; @@ -52,7 +52,7 @@ namespace CodeImp.DoomBuilder.Data //mxd SetName(name); - this.virtualname = "[TEXTURES]" + Path.AltDirectorySeparatorChar + (!string.IsNullOrEmpty(virtualpath) ? virtualpath + Path.AltDirectorySeparatorChar : "") + this.name; + this.virtualname = (!string.IsNullOrEmpty(virtualpath) ? virtualpath : "[TEXTURES]") + Path.AltDirectorySeparatorChar + this.name; this.level = virtualname.Split(new[] { Path.AltDirectorySeparatorChar }).Length - 1; this.isFlat = isflat; diff --git a/Source/Core/Data/WADReader.cs b/Source/Core/Data/WADReader.cs index 88e2e4df9ec107d32241c16b6cba1c7f9cdc944a..e29ae59d73c331c84f1795dee41df122d25dd6f0 100644 --- a/Source/Core/Data/WADReader.cs +++ b/Source/Core/Data/WADReader.cs @@ -58,6 +58,7 @@ namespace CodeImp.DoomBuilder.Data private readonly List<LumpRange> patchranges; private readonly List<LumpRange> spriteranges; private readonly List<LumpRange> textureranges; + private readonly List<LumpRange> hiresranges; //mxd private readonly List<LumpRange> colormapranges; private readonly List<LumpRange> voxelranges; //mxd @@ -88,6 +89,7 @@ namespace CodeImp.DoomBuilder.Data spriteranges = new List<LumpRange>(); flatranges = new List<LumpRange>(); textureranges = new List<LumpRange>(); + hiresranges = new List<LumpRange>(); //mxd colormapranges = new List<LumpRange>(); voxelranges = new List<LumpRange>(); //mxd @@ -96,6 +98,7 @@ namespace CodeImp.DoomBuilder.Data FindRanges(spriteranges, General.Map.Config.SpriteRanges, "sprites", "Sprite"); FindRanges(flatranges, General.Map.Config.FlatRanges, "flats", "Flat"); FindRanges(textureranges, General.Map.Config.TextureRanges, "textures", "Texture"); + FindRanges(hiresranges, General.Map.Config.HiResRanges, "hires", "HiRes texture"); FindRanges(colormapranges, General.Map.Config.ColormapRanges, "colormaps", "Colormap"); FindRanges(voxelranges, General.Map.Config.VoxelRanges, "voxels", "Voxel"); @@ -403,7 +406,7 @@ namespace CodeImp.DoomBuilder.Data else { MemoryStream filedata = new MemoryStream(file.Lumps[lumpindex].Stream.ReadAllBytes()); - cachedparsers.Add(fullpath, LoadHighresTextures(new TextResourceData(this, filedata, "TEXTURES", lumpindex, true), ref images)); //mxd + cachedparsers.Add(fullpath, LoadTEXTURESTextures(new TextResourceData(this, filedata, "TEXTURES", lumpindex, true), ref images)); //mxd filedata.Dispose(); } @@ -418,8 +421,36 @@ namespace CodeImp.DoomBuilder.Data return images; } + //mxd. This loads the HiRes textures + public override IEnumerable<HiResImage> LoadHiResTextures() + { + List<HiResImage> images = new List<HiResImage>(); + + // Read ranges from configuration + foreach(LumpRange range in hiresranges) + { + // Go for all lumps between start and end exclusive + for(int i = range.start + 1; i < range.end; i++) + { + // Lump not zero length? + if(file.Lumps[i].Length > 0) + { + // Add image to collection + images.Add(new HiResImage(file.Lumps[i].Name)); + } + else + { + // Can't load image without size + General.ErrorLogger.Add(ErrorType.Error, "Can't load HiRes texture \"" + file.Lumps[i].Name + "\" because it doesn't contain any data."); + } + } + } + + return images; + } + // This loads the texture definitions from a TEXTURES lump - public static TexturesParser LoadHighresTextures(TextResourceData data, ref List<ImageData> images) + public static TexturesParser LoadTEXTURESTextures(TextResourceData data, ref List<ImageData> images) { // Parse the data TexturesParser parser = new TexturesParser(); @@ -430,8 +461,7 @@ namespace CodeImp.DoomBuilder.Data foreach(TextureStructure t in parser.Textures) { // Add the texture - ImageData img = t.MakeImage(); - images.Add(img); + images.Add(t.MakeImage()); } //mxd. Add to text resources collection @@ -609,6 +639,22 @@ namespace CodeImp.DoomBuilder.Data return null; } + //mxd. This finds and returns a HiRes texture stream + public override Stream GetHiResTextureData(string name) + { + // Error when suspended + if(issuspended) throw new Exception("Data reader is suspended"); + + // Find the lump in ranges + foreach(LumpRange range in hiresranges) + { + Lump lump = file.FindLump(name, range.start, range.end); + if(lump != null) return lump.Stream; + } + + return null; + } + #endregion #region ================== Flats @@ -653,7 +699,7 @@ namespace CodeImp.DoomBuilder.Data else { MemoryStream filedata = new MemoryStream(file.Lumps[lumpindex].Stream.ReadAllBytes()); - cachedparsers.Add(fullpath, LoadHighresFlats(new TextResourceData(this, filedata, "TEXTURES", lumpindex, true), ref images)); //mxd + cachedparsers.Add(fullpath, LoadTEXTURESFlats(new TextResourceData(this, filedata, "TEXTURES", lumpindex, true), ref images)); //mxd filedata.Dispose(); } @@ -669,19 +715,18 @@ namespace CodeImp.DoomBuilder.Data } // This loads the flat definitions from a TEXTURES lump - public static TexturesParser LoadHighresFlats(TextResourceData data, ref List<ImageData> images) + public static TexturesParser LoadTEXTURESFlats(TextResourceData data, ref List<ImageData> images) { // Parse the data TexturesParser parser = new TexturesParser(); parser.Parse(data, false); if(parser.HasError) parser.LogError(); //mxd - // Make the textures + // Make the flat foreach(TextureStructure t in parser.Flats) { - // Add the texture - ImageData img = t.MakeImage(); - images.Add(img); + // Add the flat + images.Add(t.MakeImage()); } //mxd. Add to text resources collection @@ -738,7 +783,7 @@ namespace CodeImp.DoomBuilder.Data else { MemoryStream filedata = new MemoryStream(file.Lumps[lumpindex].Stream.ReadAllBytes()); - cachedparsers.Add(fullpath, LoadHighresSprites(new TextResourceData(this, filedata, "TEXTURES", lumpindex, true), ref images)); //mxd + cachedparsers.Add(fullpath, LoadTEXTURESSprites(new TextResourceData(this, filedata, "TEXTURES", lumpindex, true), ref images)); //mxd filedata.Dispose(); } @@ -751,19 +796,18 @@ namespace CodeImp.DoomBuilder.Data } // This loads the sprites definitions from a TEXTURES lump - public static TexturesParser LoadHighresSprites(TextResourceData data, ref List<ImageData> images) + public static TexturesParser LoadTEXTURESSprites(TextResourceData data, ref List<ImageData> images) { // Parse the data TexturesParser parser = new TexturesParser(); parser.Parse(data, false); if(parser.HasError) parser.LogError(); //mxd - // Make the textures + // Make the sprites foreach(TextureStructure t in parser.Sprites) { // Add the sprite - ImageData img = t.MakeImage(); - images.Add(img); + images.Add(t.MakeImage()); } //mxd. Add to text resources collection diff --git a/Source/Core/IO/DirectoryFilesList.cs b/Source/Core/IO/DirectoryFilesList.cs index 4c39ff127ef751dd988f96aa7c947cd53a3e6ad3..5ab2f6b1cdec90047219f0445261d391b82283f6 100644 --- a/Source/Core/IO/DirectoryFilesList.cs +++ b/Source/Core/IO/DirectoryFilesList.cs @@ -19,6 +19,7 @@ using System; using System.Collections.Generic; using System.IO; +using CodeImp.DoomBuilder.Data; #endregion @@ -272,13 +273,13 @@ namespace CodeImp.DoomBuilder.IO if(subdirectories) { for(int i = 0; i < entries.Length; i++) - if((entries[i].filetitle == title) && entries[i].path.StartsWith(path)) + if((entries[i].filetitle.Length > DataManager.CLASIC_IMAGE_NAME_LENGTH ? entries[i].filetitle.StartsWith(title) : entries[i].filetitle == title) && entries[i].path.StartsWith(path)) return entries[i].filepathname; } else { for(int i = 0; i < entries.Length; i++) - if((entries[i].filetitle == title) && (entries[i].path == path)) + if((entries[i].filetitle.Length > DataManager.CLASIC_IMAGE_NAME_LENGTH ? entries[i].filetitle.StartsWith(title) : entries[i].filetitle == title) && (entries[i].path == path)) return entries[i].filepathname; } diff --git a/Source/Core/ZDoom/TextureStructure.cs b/Source/Core/ZDoom/TextureStructure.cs index 88c2817cf3b52c9bb625383cc10151437fddf734..16edd481db5e317e7ff6f76139e6eccb5a162dc8 100644 --- a/Source/Core/ZDoom/TextureStructure.cs +++ b/Source/Core/ZDoom/TextureStructure.cs @@ -234,14 +234,14 @@ namespace CodeImp.DoomBuilder.ZDoom } // This makes a HighResImage texture for this texture - internal HighResImage MakeImage() + internal TEXTURESImage MakeImage() { // Determine scale for texture float scalex = ((xscale == 0.0f) ? General.Map.Config.DefaultTextureScale : 1f / xscale); float scaley = ((yscale == 0.0f) ? General.Map.Config.DefaultTextureScale : 1f / yscale); // Make texture - HighResImage tex = new HighResImage(name, virtualpath, width, height, scalex, scaley, worldpanning, typename == "flat"); + TEXTURESImage tex = new TEXTURESImage(name, virtualpath, width, height, scalex, scaley, worldpanning, typename == "flat"); // Add patches foreach(PatchStructure p in patches) tex.AddPatch(new TexturePatch(p));//mxd