Load images when they accessed

Load previews when they are accessed
This commit is contained in:
Magnus Norddahl 2020-01-12 23:10:57 +01:00
parent acfd4f5283
commit fc7093b959
16 changed files with 71 additions and 208 deletions

View file

@ -102,8 +102,6 @@ namespace CodeImp.DoomBuilder.Data
private object syncobject = new object();
private Queue<ImageData> imageque;
private Thread[] backgroundloader;
private int threadsfinished;
private bool notifiedbusy;
// Special images
private ImageData missingtexture3d;
@ -134,10 +132,6 @@ namespace CodeImp.DoomBuilder.Data
private List<ThingCategory> thingcategories;
private Dictionary<int, ThingTypeInfo> thingtypes;
// Timing
private long loadstarttime;
private long loadfinishtime;
// Disposing
private bool isdisposed;
@ -235,16 +229,12 @@ namespace CodeImp.DoomBuilder.Data
// Load special images (mxd: the rest is loaded in LoadInternalTextures())
whitetexture = new ResourceImage("CodeImp.DoomBuilder.Resources.White.png") { UseColorCorrection = false };
whitetexture.LoadImage();
blacktexture = new ResourceImage("CodeImp.DoomBuilder.Resources.Black.png") { UseColorCorrection = false }; //mxd
blacktexture.LoadImage(); //mxd
unknownimage = new UnknownImage(Properties.Resources.UnknownImage); //mxd. There should be only one!
//mxd. Textures browser images
foldertexture = new ResourceImage("CodeImp.DoomBuilder.Resources.Folder96.png") { UseColorCorrection = false };
foldertexture.LoadImage();
folderuptexture = new ResourceImage("CodeImp.DoomBuilder.Resources.Folder96Up.png") { UseColorCorrection = false };
folderuptexture.LoadImage();
//mxd. Create comment icons
commenttextures = new ImageData[]
@ -255,12 +245,6 @@ namespace CodeImp.DoomBuilder.Data
new ResourceImage("CodeImp.DoomBuilder.Resources.CommentProblem.png") { UseColorCorrection = false },
new ResourceImage("CodeImp.DoomBuilder.Resources.CommentSmile.png") { UseColorCorrection = false },
};
//mxd. Load comment icons
foreach(ImageData data in commenttextures)
{
data.LoadImage();
}
}
// Disposer
@ -661,12 +645,6 @@ namespace CodeImp.DoomBuilder.Data
mapinfo = null; //mxd
}
//mxd. Called before Clock is reset
internal void OnBeforeClockReset()
{
if(loadstarttime > 0) loadstarttime -= Clock.CurrentTime;
}
#endregion
#region ================== Suspend / Resume
@ -717,11 +695,6 @@ namespace CodeImp.DoomBuilder.Data
// This starts background loading
private void StartBackgroundLoader()
{
// Timing
loadstarttime = Clock.CurrentTime;
loadfinishtime = 0;
threadsfinished = 0;
// If a loader is already running, stop it first
if(backgroundloader != null) StopBackgroundLoader();
@ -756,7 +729,6 @@ namespace CodeImp.DoomBuilder.Data
}
// Done
notifiedbusy = false;
backgroundloader = null;
General.MainWindow.UpdateStatus();
}
@ -770,7 +742,7 @@ namespace CodeImp.DoomBuilder.Data
// Wait a bit before loading to give the main thread a headstart on acquiring the locks in the resource loader part of the codebase..
Thread.Sleep(666);
do
while (true)
{
// Get next item
ImageData image = null;
@ -778,78 +750,12 @@ namespace CodeImp.DoomBuilder.Data
{
// Fetch next image to process
if(imageque.Count > 0) image = imageque.Dequeue();
}
// Any image to process?
if(image != null)
{
image.LoadImage();
}
// Doing something?
if(image != null)
{
// Wait a bit and update icon
if(!notifiedbusy)
{
notifiedbusy = true;
General.MainWindow.UpdateStatus();
}
}
else
{
bool lastthread = false;
lock (syncobject)
{
threadsfinished++;
if (threadsfinished == backgroundloader.Length)
lastthread = true;
}
if (lastthread)
{
// Timing
if (loadfinishtime == 0)
{
//mxd. Release PK3 files
foreach (DataReader reader in containers)
{
if (reader is PK3Reader) (reader as PK3Reader).BatchMode = false;
}
loadfinishtime = Clock.CurrentTime;
string deltatimesec = ((loadfinishtime - loadstarttime) / 1000.0f).ToString("########0.00");
General.WriteLogLine("Resources loading took " + deltatimesec + " seconds");
loadstarttime = 0; //mxd
lock (syncobject)
{
threadsfinished = 0;
}
//mxd. Show more detailed message
if (notifiedbusy)
{
notifiedbusy = false;
General.MainWindow.ResourcesLoaded(deltatimesec);
}
}
else if (notifiedbusy) //mxd. Sould never happen (?)
{
notifiedbusy = false;
General.MainWindow.UpdateStatus();
}
}
// Wait until there's more to do.
lock (syncobject)
{
if (imageque.Count == 0) Monitor.Wait(syncobject);
}
image?.BackgroundLoadImage();
}
}
while (true);
}
catch(ThreadInterruptedException) { }
}
@ -867,7 +773,7 @@ namespace CodeImp.DoomBuilder.Data
}
}
void QueueLoadPreview(ImageData img)
internal void QueueLoadPreview(ImageData img)
{
if (img.PreviewState == ImageLoadState.None)
{
@ -944,8 +850,6 @@ namespace CodeImp.DoomBuilder.Data
list.Remove(img.LongName);
list.Add(img.LongName, img);
counter++;
QueueLoadPreview(img);
}
}
}
@ -1012,8 +916,6 @@ namespace CodeImp.DoomBuilder.Data
{
nametranslation.Remove(img.LongName);
}
QueueLoadPreview(img);
}
}
}
@ -1097,7 +999,7 @@ namespace CodeImp.DoomBuilder.Data
if(!(img is UnknownImage))
{
if(!img.IsImageLoaded) img.LoadImage();
img.LoadImageNow();
if(!img.LoadFailed)
{
// HiResImage will not give us it's actual scale
@ -1197,6 +1099,7 @@ namespace CodeImp.DoomBuilder.Data
if(File.Exists(path))
{
result = new FileImage(name, path) { AllowUnload = false };
result.LoadImageNow();
}
else
{
@ -1204,7 +1107,6 @@ namespace CodeImp.DoomBuilder.Data
result = new ResourceImage("CodeImp.DoomBuilder.Resources." + name);
}
result.LoadImage();
return result;
}
@ -1243,8 +1145,6 @@ namespace CodeImp.DoomBuilder.Data
{
nametranslation.Remove(img.LongName);
}
QueueLoadPreview(img);
}
}
}
@ -1373,7 +1273,6 @@ namespace CodeImp.DoomBuilder.Data
textures[img.LongName] = replacer;
//replaced = true;
QueueLoadPreview(img);
counter++;
}
@ -1386,7 +1285,6 @@ namespace CodeImp.DoomBuilder.Data
flats[img.LongName] = replacer;
//replaced = true;
QueueLoadPreview(img);
counter++;
}
@ -1398,7 +1296,6 @@ namespace CodeImp.DoomBuilder.Data
sprites[img.LongName] = replacer;
//replaced = true;
QueueLoadPreview(img);
counter++;
}
@ -1522,8 +1419,6 @@ namespace CodeImp.DoomBuilder.Data
// Add to collection
sprites.Add(image.LongName, image);
QueueLoadPreview(image);
}
}
else
@ -1569,8 +1464,6 @@ namespace CodeImp.DoomBuilder.Data
{
image = sprites[info.SpriteLongName];
}
if (image != null) QueueLoadPreview(image);
}
}
}
@ -1628,7 +1521,7 @@ namespace CodeImp.DoomBuilder.Data
foreach(string spritefile in files)
{
ImageData img = new FileImage(Path.GetFileNameWithoutExtension(spritefile).ToLowerInvariant(), spritefile);
img.LoadImage();
img.LoadImageNow();
img.AllowUnload = false;
name = INTERNAL_PREFIX + img.Name;
long hash = Lump.MakeLongName(name, true); //mxd
@ -1642,7 +1535,6 @@ namespace CodeImp.DoomBuilder.Data
if(!internalspriteslookup.ContainsKey(name))
{
ImageData img = new ResourceImage("CodeImp.DoomBuilder.Resources.Nothing.png");
img.LoadImage();
img.AllowUnload = false;
long hash = Lump.MakeLongName(name, true); //mxd
sprites[hash] = img; //mxd
@ -1654,7 +1546,6 @@ namespace CodeImp.DoomBuilder.Data
if(!internalspriteslookup.ContainsKey(name))
{
ImageData img = new ResourceImage("CodeImp.DoomBuilder.Resources.UnknownThing.png");
img.LoadImage();
img.AllowUnload = false;
sprites[UNKNOWN_THING] = img; //mxd
internalspriteslookup[name] = UNKNOWN_THING; //mxd
@ -1666,7 +1557,6 @@ namespace CodeImp.DoomBuilder.Data
if(!internalspriteslookup.ContainsKey(name))
{
ImageData img = new ResourceImage("CodeImp.DoomBuilder.Resources.MissingThing.png");
img.LoadImage();
img.AllowUnload = false;
sprites[MISSING_THING] = img; //mxd
internalspriteslookup[name] = MISSING_THING; //mxd
@ -1688,7 +1578,6 @@ namespace CodeImp.DoomBuilder.Data
if (img != null)
{
img.UsedInMap = true;
QueueLoadImage(img);
}
return img;
}
@ -1705,7 +1594,6 @@ namespace CodeImp.DoomBuilder.Data
if (img != null)
{
img.UsedInMap = true;
QueueLoadImage(img);
}
return img;
}
@ -1739,7 +1627,6 @@ namespace CodeImp.DoomBuilder.Data
if (image != null)
{
image.UsedInMap = true;
QueueLoadImage(image);
}
return image;
}
@ -1754,7 +1641,6 @@ namespace CodeImp.DoomBuilder.Data
if (img != null)
{
img.UsedInMap = true;
QueueLoadImage(img);
}
return img;
}
@ -2416,8 +2302,6 @@ namespace CodeImp.DoomBuilder.Data
// Add to collection
sprites.Add(sprite.LongName, sprite);
QueueLoadPreview(sprite);
}
// Apply VOXELDEF settings to the preview image...
@ -2783,8 +2667,6 @@ namespace CodeImp.DoomBuilder.Data
textures[camteximage.LongName] = camteximage;
flats[camteximage.LongName] = camteximage;
QueueLoadPreview(camteximage);
// Add to container's texture set
currentreader.TextureSet.AddFlat(camteximage);
currentreader.TextureSet.AddTexture(camteximage);
@ -3143,7 +3025,6 @@ namespace CodeImp.DoomBuilder.Data
if (i.Value.LoadFailed)
continue;
i.Value.UsedInMap = usedtextures.ContainsKey(i.Key);
QueueLoadImage(i.Value);
}
// Set used on all flats
@ -3152,7 +3033,6 @@ namespace CodeImp.DoomBuilder.Data
if (i.Value.LoadFailed)
continue;
i.Value.UsedInMap = usedtextures.ContainsKey(i.Key);
QueueLoadImage(i.Value);
}
}
//mxd. Use separate collections
@ -3164,7 +3044,6 @@ namespace CodeImp.DoomBuilder.Data
if (i.Value.LoadFailed)
continue;
i.Value.UsedInMap = usedtextures.ContainsKey(i.Key);
QueueLoadImage(i.Value);
}
// Set used on all flats
@ -3173,7 +3052,6 @@ namespace CodeImp.DoomBuilder.Data
if (i.Value.LoadFailed)
continue;
i.Value.UsedInMap = usedflats.ContainsKey(i.Key);
QueueLoadImage(i.Value);
}
}

View file

@ -98,7 +98,7 @@ namespace CodeImp.DoomBuilder.Data
hasLongName = overridden.HasLongName;
overridesettingsapplied = true;
if(!overridden.IsImageLoaded) overridden.LoadImage();
overridden.LoadImageNow();
if(overridden.ImageState == ImageLoadState.Ready)
{
// Store source properteis

View file

@ -106,8 +106,27 @@ namespace CodeImp.DoomBuilder.Data
internal bool HasLongName { get { return hasLongName; } } //mxd
public bool UseColorCorrection { get { return usecolorcorrection; } set { usecolorcorrection = value; } }
public Texture Texture { get { return GetTexture(); } }
public bool IsPreviewLoaded { get { return (previewstate == ImageLoadState.Ready); } }
public bool IsImageLoaded { get { return (imagestate == ImageLoadState.Ready); } }
public bool IsPreviewLoaded
{
get
{
if (previewstate == ImageLoadState.None)
General.Map.Data.QueueLoadPreview(this);
return (previewstate == ImageLoadState.Ready);
}
}
public bool IsImageLoaded
{
get
{
if (imagestate == ImageLoadState.None)
General.Map.Data.QueueLoadImage(this);
return (imagestate == ImageLoadState.Ready);
}
}
public bool LoadFailed { get { return loadfailed; } }
public bool IsDisposed { get { return isdisposed; } }
public bool AllowUnload { get; set; }
@ -251,7 +270,16 @@ namespace CodeImp.DoomBuilder.Data
return result.bitmap;
}
public void LoadImage()
public void LoadImageNow()
{
if (imagestate != ImageLoadState.Ready)
{
imagestate = ImageLoadState.Loading;
LoadImage(true);
}
}
internal void BackgroundLoadImage()
{
LoadImage(true);
}
@ -271,15 +299,16 @@ namespace CodeImp.DoomBuilder.Data
// Save memory by disposing the original image immediately if we only used it to load a preview image
bool onlyPreview = false;
if (imagestate == ImageLoadState.Ready)
if (imagestate != ImageLoadState.Loading)
{
loadResult.bitmap?.Dispose();
loadResult.bitmap = null;
onlyPreview = true;
}
General.MainWindow.RunOnUIThread(() =>
{
if (imagestate != ImageLoadState.Ready && !onlyPreview)
if (imagestate == ImageLoadState.Loading && !onlyPreview)
{
// Log errors and warnings
foreach (LogMessage message in loadResult.messages)
@ -712,6 +741,11 @@ namespace CodeImp.DoomBuilder.Data
return Properties.Resources.Failed;
}
if (previewstate == ImageLoadState.None)
{
General.Map.Data.QueueLoadPreview(this);
}
// Return loading bitmap
return Properties.Resources.Hourglass;
}

View file

@ -60,8 +60,7 @@ namespace CodeImp.DoomBuilder.Data
bmp.Dispose();
bitmapdata.Dispose();
// We have no destructor
GC.SuppressFinalize(this);
LoadImageNow();
}
#endregion

View file

@ -217,8 +217,6 @@ namespace CodeImp.DoomBuilder.Data
ImageData img = General.Map.Data.GetTextureImage(p.LumpName);
if(!(img is UnknownImage) && img != this)
{
if(!img.IsImageLoaded) img.LoadImage();
//mxd. Apply transformations from TexturePatch. We don't want to modify the original bitmap here, so make a copy
Bitmap bmp = new Bitmap(img.LocalGetBitmap());
Bitmap patchbmp = TransformPatch(bitmap, p, bmp);

View file

@ -42,10 +42,7 @@ namespace CodeImp.DoomBuilder.Data
this.loadbitmap = image;
SetName("");
LoadImage(false);
// We have no destructor
GC.SuppressFinalize(this);
LoadImageNow();
}
#endregion

View file

@ -234,7 +234,7 @@ namespace CodeImp.DoomBuilder.Editing
}
// Make sure it is loaded
backimage.LoadImage();
backimage.LoadImageNow();
}
// This returns the next higher coordinate

View file

@ -277,9 +277,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3
if (General.Map.Data.GetTextureExists(name))
{
ImageData image = General.Map.Data.GetTextureImage(name);
if (!image.IsImageLoaded)
image.LoadImage();
image.LoadImageNow();
t = image.Texture;
@ -296,9 +294,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3
if (General.Map.Data.GetTextureExists(name))
{
ImageData image = General.Map.Data.GetTextureImage(name);
if (!image.IsImageLoaded)
image.LoadImage();
image.LoadImageNow();
t = image.Texture;
}
@ -312,9 +308,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3
if (General.Map.Data.GetSpriteExists(name))
{
ImageData image = General.Map.Data.GetSpriteImage(name);
if (!image.IsImageLoaded)
image.LoadImage();
image.LoadImageNow();
t = image.Texture;
}

View file

@ -718,13 +718,7 @@ namespace CodeImp.DoomBuilder.Rendering
// Render the geometry collected
foreach (KeyValuePair<ImageData, List<VisualGeometry>> group in geopass)
{
// What texture to use?
if(group.Key is UnknownImage)
curtexture = General.Map.Data.UnknownTexture3D;
else if(group.Key.IsImageLoaded && !group.Key.IsDisposed)
curtexture = group.Key;
else
curtexture = General.Map.Data.Hourglass3D;
// Apply texture
graphics.SetTexture(curtexture.Texture);
@ -865,10 +859,6 @@ namespace CodeImp.DoomBuilder.Rendering
{
if(group.Key is UnknownImage) continue;
// What texture to use?
if(!group.Key.IsImageLoaded || group.Key.IsDisposed)
curtexture = General.Map.Data.Hourglass3D;
else
curtexture = group.Key;
// Apply texture
@ -1093,13 +1083,7 @@ namespace CodeImp.DoomBuilder.Rendering
// Change texture?
if(g.Texture.LongName != curtexturename)
{
// What texture to use?
if(g.Texture is UnknownImage)
curtexture = General.Map.Data.UnknownTexture3D;
else if(g.Texture.IsImageLoaded && !g.Texture.IsDisposed)
curtexture = g.Texture;
else
curtexture = General.Map.Data.Hourglass3D;
// Apply texture
graphics.SetTexture(curtexture.Texture);
@ -1226,11 +1210,7 @@ namespace CodeImp.DoomBuilder.Rendering
// Change texture?
if(t.Texture.LongName != curtexturename)
{
// What texture to use?
if(t.Texture.IsImageLoaded && !t.Texture.IsDisposed)
curtexture = t.Texture;
else
curtexture = General.Map.Data.Hourglass3D;
// Apply texture
graphics.SetTexture(curtexture.Texture);

View file

@ -93,7 +93,6 @@ namespace CodeImp.DoomBuilder.Windows
backgroundname = result;
backgroundsource = GridSetup.SOURCE_TEXTURES;
ImageData img = General.Map.Data.GetTextureImage(result);
img.LoadImage();
General.DisplayZoomedImage(backgroundimage, img.GetBackgroundBitmap());
}
}
@ -109,7 +108,6 @@ namespace CodeImp.DoomBuilder.Windows
backgroundname = result;
backgroundsource = GridSetup.SOURCE_FLATS;
ImageData img = General.Map.Data.GetFlatImage(result);
img.LoadImage();
General.DisplayZoomedImage(backgroundimage, img.GetBackgroundBitmap());
}
}
@ -124,7 +122,6 @@ namespace CodeImp.DoomBuilder.Windows
backgroundname = browsefile.FileName;
backgroundsource = GridSetup.SOURCE_FILE;
ImageData img = new FileImage(Path.GetFileNameWithoutExtension(backgroundname), backgroundname, false, 1.0f, 1.0f);
img.LoadImage();
General.DisplayZoomedImage(backgroundimage, new Bitmap(img.GetBackgroundBitmap()));
img.Dispose();
}

View file

@ -4214,14 +4214,6 @@ namespace CodeImp.DoomBuilder.Windows
});
}
public void ResourcesLoaded(string loadtime)
{
RunOnUIThread(() =>
{
DisplayStatus(StatusType.Info, "Resources loaded in " + loadtime + " seconds");
});
}
#endregion
#region ================== Message Pump
@ -4377,10 +4369,6 @@ namespace CodeImp.DoomBuilder.Windows
//mxd
internal void ResetClock()
{
// Let the data manager know...
if(General.Map != null && General.Map.Data != null)
General.Map.Data.OnBeforeClockReset();
Clock.Reset();
lastupdatetime = 0;

View file

@ -94,7 +94,6 @@ namespace CodeImp.DoomBuilder.BuilderModes.IO
continue;
}
if(!id.IsImageLoaded) id.LoadImage();
Bitmap bmp = id.ExportBitmap();
lock (bmp)
{
@ -122,7 +121,6 @@ namespace CodeImp.DoomBuilder.BuilderModes.IO
continue;
}
if(!id.IsImageLoaded) id.LoadImage();
Bitmap bmp = id.ExportBitmap();
// Handle duplicate names

View file

@ -1174,7 +1174,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
mode.SetActionResult("Auto-aligned textures " + rest + ".");
// Make sure the texture is loaded (we need the texture size)
if(!base.Texture.IsImageLoaded) base.Texture.LoadImage();
if(!base.Texture.IsImageLoaded) base.Texture.LoadImageNow();
if(mode.IsSingleSelection)
{

View file

@ -2988,7 +2988,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
BaseVisualGeometrySidedef side = (BaseVisualGeometrySidedef)i;
// Make sure the texture is loaded (we need the texture size)
if(!side.Texture.IsImageLoaded) side.Texture.LoadImage();
if(!side.Texture.IsImageLoaded) side.Texture.LoadImageNow();
//Align textures
AutoAlignTextures(side, side.Texture, alignX, alignY, false, false);

View file

@ -301,7 +301,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
// Check if the texture is loaded
ImageData sprite = sprites[i];
if (!sprite.IsImageLoaded && !sprite.LoadFailed)
sprite.LoadImage();
sprite.LoadImageNow();
if(sprite.IsImageLoaded)
{
base.textures[i] = sprite;
@ -354,7 +354,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
else
{
isloaded = false;
base.textures[i] = General.Map.Data.Hourglass3D;
base.textures[i] = sprite;
// Determine sprite size
float radius = Math.Min(thingradius, thingheight / 2f);

View file

@ -280,7 +280,7 @@ namespace CodeImp.DoomBuilder.Plugins.VisplaneExplorer
image = new DynamicBitmapImage(canvas, "_CANVAS_");
image.UseColorCorrection = false;
image.MipMapLevels = 1;
image.LoadImage();
image.LoadImageNow();
// Make custom presentation
CustomPresentation p = new CustomPresentation();