Added HiRes textures support.

Fixed, Script Editor: fixed a crash when trying to open Script Editor in a Doom map format map.
This commit is contained in:
MaxED 2016-03-04 08:10:56 +00:00
parent 9a10ef9b78
commit 87a54b1e4a
19 changed files with 486 additions and 71 deletions

View file

@ -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

View file

@ -203,6 +203,15 @@ textures
}
}
hires //mxd
{
zdoom1
{
start = "HI_START";
end = "HI_END";
}
}
voxels //mxd
{
zdoom1

View file

@ -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)";

View file

@ -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" />

View file

@ -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());

View file

@ -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()));
}
}

View file

@ -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)
{

View file

@ -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()));
}
}

View file

@ -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)

View file

@ -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

View file

@ -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)
{

View file

@ -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
}
}

View file

@ -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

View file

@ -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)
{

View file

@ -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();
}
}

View file

@ -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;

View file

@ -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

View file

@ -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;
}

View file

@ -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