background resource loading implemented

This commit is contained in:
codeimp 2007-10-26 15:28:32 +00:00
parent 383ed6583f
commit 5e53809f96
9 changed files with 386 additions and 186 deletions

View file

@ -78,6 +78,7 @@ namespace CodeImp.DoomBuilder.Config
// Things
public List<ThingCategory> ThingCategories { get { return thingcategories; } }
public ICollection<ThingTypeInfo> Things { get { return things.Values; } }
#endregion

View file

@ -27,6 +27,8 @@ using System.IO;
using CodeImp.DoomBuilder.IO;
using System.Windows.Forms;
using SlimDX.Direct3D9;
using CodeImp.DoomBuilder.Config;
using System.Threading;
#endregion
@ -55,6 +57,9 @@ namespace CodeImp.DoomBuilder.Data
// Sprites
private Dictionary<long, ImageData> sprites;
// Background loading
private Thread backgroundloader;
// Disposing
private bool isdisposed = false;
@ -169,11 +174,19 @@ namespace CodeImp.DoomBuilder.Data
LoadTextures();
General.WriteLogLine("Loading flats...");
LoadFlats();
General.WriteLogLine("Loading sprites...");
LoadSprites();
// Start background loading
StartBackgroundLoader();
}
// This unloads all data
public void Unload()
{
// Stop background loader
StopBackgroundLoader();
// Dispose resources
foreach(KeyValuePair<long, ImageData> i in textures) i.Value.Dispose();
foreach(KeyValuePair<long, ImageData> i in flats) i.Value.Dispose();
@ -192,6 +205,9 @@ namespace CodeImp.DoomBuilder.Data
// This suspends data resources
public void Suspend()
{
// Stop background loader
StopBackgroundLoader();
// Go for all containers
foreach(DataReader d in containers)
{
@ -219,10 +235,123 @@ namespace CodeImp.DoomBuilder.Data
General.ShowErrorMessage("Unable to load resources from location \"" + d.Location.location + "\". Please make sure the location is accessible and not in use by another program.", MessageBoxButtons.OK);
}
}
// Start background loading
StartBackgroundLoader();
}
#endregion
#region ================== Background Loading
// This starts background loading
private void StartBackgroundLoader()
{
// If a loader is already running, stop it first
if(backgroundloader != null) StopBackgroundLoader();
// Start a low priority thread to load images in background
General.WriteLogLine("Starting background resource loading...");
backgroundloader = new Thread(new ThreadStart(BackgroundLoad));
backgroundloader.Name = "BackgroundLoader";
backgroundloader.Priority = ThreadPriority.Lowest;
backgroundloader.Start();
}
// This stops background loading
private void StopBackgroundLoader()
{
// Stop the thread and wait for it to end
General.WriteLogLine("Stopping background resource loading...");
backgroundloader.Interrupt();
backgroundloader.Join();
// Done
backgroundloader = null;
}
// The background loader
private void BackgroundLoad()
{
int loadedtextures;
int loadedflats;
int loadedsprites;
try
{
// Load all lists
loadedtextures = LoadImagesList(textures);
loadedflats = LoadImagesList(flats);
loadedsprites = LoadImagesList(sprites);
}
catch(ThreadInterruptedException)
{
return;
}
// Done
General.WriteLogLine("Background resource loading completed");
General.WriteLogLine("Loaded textures: " + loadedtextures + " / " + textures.Count);
General.WriteLogLine("Loaded flats: " + loadedflats + " / " + flats.Count);
General.WriteLogLine("Loaded sprites: " + loadedsprites + " / " + sprites.Count);
}
// This loads a list of ImageData
private int LoadImagesList(Dictionary<long, ImageData> list)
{
Dictionary<long, ImageData>.Enumerator walker;
bool moveresult = false;
bool interrupted = false;
int numloaded;
do
{
// Get enumerator
lock(list)
{
walker = list.GetEnumerator();
moveresult = walker.MoveNext();
numloaded = 0;
}
// Continue until at end of list
while(moveresult)
{
lock(list)
{
// Load image
walker.Current.Value.LoadImage();
//walker.Current.Value.CreateTexture();
if(walker.Current.Value.IsLoaded) numloaded++;
}
// Wait a bit
Thread.Sleep(10);
lock(list)
{
try
{
// Move to next item
moveresult = walker.MoveNext();
}
catch(InvalidOperationException)
{
// List was modified, restart!
interrupted = true;
break;
}
}
}
}
while(interrupted);
// Return result
return numloaded;
}
#endregion
#region ================== Palette
// This loads the PLAYPAL palette
@ -301,19 +430,22 @@ namespace CodeImp.DoomBuilder.Data
// This returns an image by long
public ImageData GetTextureImage(long longname)
{
// Does this texture exist?
if(textures.ContainsKey(longname))
lock(textures)
{
// Return texture
return textures[longname];
}
else
{
// Return null image
return new NullImage();
// Does this texture exist?
if(textures.ContainsKey(longname))
{
// Return texture
return textures[longname];
}
else
{
// Return null image
return new NullImage();
}
}
}
// This returns a bitmap by string
public Bitmap GetTextureBitmap(string name)
{
@ -403,16 +535,19 @@ namespace CodeImp.DoomBuilder.Data
// This returns an image by long
public ImageData GetFlatImage(long longname)
{
// Does this flat exist?
if(flats.ContainsKey(longname))
lock(flats)
{
// Return flat
return flats[longname];
}
else
{
// Return null image
return new NullImage();
// Does this flat exist?
if(flats.ContainsKey(longname))
{
// Return flat
return flats[longname];
}
else
{
// Return null image
return new NullImage();
}
}
}
@ -454,6 +589,39 @@ namespace CodeImp.DoomBuilder.Data
#region ================== Sprites
// This loads the sprites
private void LoadSprites()
{
Stream spritedata = null;
SpriteImage image;
// Go for all things
foreach(ThingTypeInfo ti in General.Map.Config.Things)
{
// Sprite not added to collection yet?
if(!sprites.ContainsKey(ti.SpriteLongName))
{
// Go for all opened containers
for(int i = containers.Count - 1; i >= 0; i--)
{
// This contain provides this sprite?
spritedata = containers[i].GetSpriteData(ti.Sprite);
if(spritedata != null) break;
}
// Found anything?
if(spritedata != null)
{
// Make new sprite image
image = new SpriteImage(ti.Sprite);
// Add to collection
sprites.Add(ti.SpriteLongName, image);
}
}
}
}
// This returns an image by long
public ImageData GetSpriteImage(string name)
{
@ -461,38 +629,41 @@ namespace CodeImp.DoomBuilder.Data
long longname = Lump.MakeLongName(name);
SpriteImage image;
// Sprite already loaded?
if(sprites.ContainsKey(longname))
lock(sprites)
{
// Return exiting sprite
return sprites[longname];
}
else
{
// Go for all opened containers
for(int i = containers.Count - 1; i >= 0; i--)
// Sprite already loaded?
if(sprites.ContainsKey(longname))
{
// This contain provides this sprite?
spritedata = containers[i].GetSpriteData(name);
if(spritedata != null) break;
}
// Found anything?
if(spritedata != null)
{
// Make new sprite image
image = new SpriteImage(name);
// Add to collection
sprites.Add(longname, image);
// Return result
return image;
// Return exiting sprite
return sprites[longname];
}
else
{
// Return null image
return new NullImage();
// Go for all opened containers
for(int i = containers.Count - 1; i >= 0; i--)
{
// This contain provides this sprite?
spritedata = containers[i].GetSpriteData(name);
if(spritedata != null) break;
}
// Found anything?
if(spritedata != null)
{
// Make new sprite image
image = new SpriteImage(name);
// Add to collection
sprites.Add(longname, image);
// Return result
return image;
}
else
{
// Return null image
return new NullImage();
}
}
}
}

View file

@ -60,11 +60,14 @@ namespace CodeImp.DoomBuilder.Data
// Leave when already loaded
if(this.IsLoaded) return;
// Load file
bitmap = (Bitmap)Bitmap.FromFile(filepathname);
lock(this)
{
// Load file
bitmap = (Bitmap)Bitmap.FromFile(filepathname);
// Pass on to base
base.LoadImage();
// Pass on to base
base.LoadImage();
}
}
#endregion

View file

@ -62,37 +62,40 @@ namespace CodeImp.DoomBuilder.Data
// Leave when already loaded
if(this.IsLoaded) return;
// Get the lump data stream
lumpdata = General.Map.Data.GetPatchData(Name);
if(lumpdata != null)
lock(this)
{
// Copy lump data to memory
lumpdata.Seek(0, SeekOrigin.Begin);
membytes = new byte[(int)lumpdata.Length];
lumpdata.Read(membytes, 0, (int)lumpdata.Length);
mem = new MemoryStream(membytes);
mem.Seek(0, SeekOrigin.Begin);
// Get a reader for the data
reader = ImageDataFormat.GetImageReader(mem, ImageDataFormat.DOOMFLAT, General.Map.Data.Palette);
if(reader is UnknownImageReader)
// Get the lump data stream
lumpdata = General.Map.Data.GetPatchData(Name);
if(lumpdata != null)
{
// Data is in an unknown format!
General.WriteLogLine("WARNING: Flat lump '" + Name + "' data format could not be read!");
// Copy lump data to memory
lumpdata.Seek(0, SeekOrigin.Begin);
membytes = new byte[(int)lumpdata.Length];
lumpdata.Read(membytes, 0, (int)lumpdata.Length);
mem = new MemoryStream(membytes);
mem.Seek(0, SeekOrigin.Begin);
// Get a reader for the data
reader = ImageDataFormat.GetImageReader(mem, ImageDataFormat.DOOMFLAT, General.Map.Data.Palette);
if(reader is UnknownImageReader)
{
// Data is in an unknown format!
General.WriteLogLine("WARNING: Flat lump '" + Name + "' data format could not be read!");
}
// Read data as bitmap
mem.Seek(0, SeekOrigin.Begin);
bitmap = reader.ReadAsBitmap(mem);
}
else
{
// Missing a patch lump!
General.WriteLogLine("WARNING: Missing flat lump '" + Name + "'!");
}
// Read data as bitmap
mem.Seek(0, SeekOrigin.Begin);
bitmap = reader.ReadAsBitmap(mem);
// Pass on to base
base.LoadImage();
}
else
{
// Missing a patch lump!
General.WriteLogLine("WARNING: Missing flat lump '" + Name + "'!");
}
// Pass on to base
base.LoadImage();
}
#endregion

View file

@ -94,18 +94,21 @@ namespace CodeImp.DoomBuilder.Data
// Not already disposed?
if(!isdisposed)
{
// Clean up
if(bitmap != null) bitmap.Dispose();
if(texture != null) texture.Dispose();
if(pixeldata != null)
lock(this)
{
General.VirtualFree((void*)pixeldata, new UIntPtr(pixeldatasize), General.MEM_RELEASE);
pixeldata = null;
GC.RemoveMemoryPressure(pixeldatasize);
}
// Clean up
if(bitmap != null) bitmap.Dispose();
if(texture != null) texture.Dispose();
if(pixeldata != null)
{
General.VirtualFree((void*)pixeldata, new UIntPtr(pixeldatasize), General.MEM_RELEASE);
pixeldata = null;
GC.RemoveMemoryPressure(pixeldatasize);
}
// Done
isdisposed = true;
// Done
isdisposed = true;
}
}
}
@ -133,21 +136,24 @@ namespace CodeImp.DoomBuilder.Data
// Only do this when data is not created yet
if((pixeldata == null) && IsLoaded)
{
// Clean up old memory if reserved
if(pixeldata != null)
lock(this)
{
General.VirtualFree((void*)pixeldata, new UIntPtr(pixeldatasize), General.MEM_RELEASE);
pixeldata = null;
GC.RemoveMemoryPressure(pixeldatasize);
}
// Clean up old memory if reserved
if(pixeldata != null)
{
General.VirtualFree((void*)pixeldata, new UIntPtr(pixeldatasize), General.MEM_RELEASE);
pixeldata = null;
GC.RemoveMemoryPressure(pixeldatasize);
}
// Make a data copy of the bits for the 2D renderer
bmpdata = bitmap.LockBits(new Rectangle(0, 0, bitmap.Size.Width, bitmap.Size.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
pixeldatasize = (uint)(bmpdata.Width * bmpdata.Height * sizeof(PixelColor));
pixeldata = (PixelColor*)General.VirtualAlloc(IntPtr.Zero, new UIntPtr(pixeldatasize), General.MEM_COMMIT, General.PAGE_READWRITE);
General.CopyMemory((void*)pixeldata, bmpdata.Scan0.ToPointer(), new UIntPtr(pixeldatasize));
bitmap.UnlockBits(bmpdata);
GC.AddMemoryPressure(pixeldatasize);
// Make a data copy of the bits for the 2D renderer
bmpdata = bitmap.LockBits(new Rectangle(0, 0, bitmap.Size.Width, bitmap.Size.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
pixeldatasize = (uint)(bmpdata.Width * bmpdata.Height * sizeof(PixelColor));
pixeldata = (PixelColor*)General.VirtualAlloc(IntPtr.Zero, new UIntPtr(pixeldatasize), General.MEM_COMMIT, General.PAGE_READWRITE);
General.CopyMemory((void*)pixeldata, bmpdata.Scan0.ToPointer(), new UIntPtr(pixeldatasize));
bitmap.UnlockBits(bmpdata);
GC.AddMemoryPressure(pixeldatasize);
}
}
}
@ -159,22 +165,28 @@ namespace CodeImp.DoomBuilder.Data
// Only do this when texture is not created yet
if((texture == null) && IsLoaded)
{
// Write to memory stream and read from memory
memstream = new MemoryStream();
bitmap.Save(memstream, ImageFormat.Bmp);
memstream.Seek(0, SeekOrigin.Begin);
texture = Texture.FromStream(General.Map.Graphics.Device, memstream, (int)memstream.Length, bitmap.Size.Width, bitmap.Size.Height, 0,
Usage.None, Format.Unknown, Pool.Managed, Filter.Box, Filter.Box, 0);
memstream.Dispose();
lock(this)
{
// Write to memory stream and read from memory
memstream = new MemoryStream();
bitmap.Save(memstream, ImageFormat.Bmp);
memstream.Seek(0, SeekOrigin.Begin);
texture = Texture.FromStream(General.Map.Graphics.Device, memstream, (int)memstream.Length, bitmap.Size.Width, bitmap.Size.Height, 0,
Usage.None, Format.Unknown, Pool.Managed, Filter.Box, Filter.Box, 0);
memstream.Dispose();
}
}
}
// This destroys the Direct3D texture
public void ReleaseTexture()
{
// Trash it
if(texture != null) texture.Dispose();
texture = null;
lock(this)
{
// Trash it
if(texture != null) texture.Dispose();
texture = null;
}
}
#endregion

View file

@ -78,13 +78,16 @@ namespace CodeImp.DoomBuilder.Data
public override void LoadImage()
{
Stream bitmapdata;
// Get resource from memory
bitmapdata = General.ThisAssembly.GetManifestResourceStream("CodeImp.DoomBuilder.Resources." + Name);
bitmap = (Bitmap)Image.FromStream(bitmapdata);
// Pass on to base
base.LoadImage();
lock(this)
{
// Get resource from memory
bitmapdata = General.ThisAssembly.GetManifestResourceStream("CodeImp.DoomBuilder.Resources." + Name);
bitmap = (Bitmap)Image.FromStream(bitmapdata);
// Pass on to base
base.LoadImage();
}
}
#endregion

View file

@ -62,37 +62,40 @@ namespace CodeImp.DoomBuilder.Data
// Leave when already loaded
if(this.IsLoaded) return;
// Get the lump data stream
lumpdata = General.Map.Data.GetPatchData(Name);
if(lumpdata != null)
lock(this)
{
// Copy lump data to memory
lumpdata.Seek(0, SeekOrigin.Begin);
membytes = new byte[(int)lumpdata.Length];
lumpdata.Read(membytes, 0, (int)lumpdata.Length);
mem = new MemoryStream(membytes);
mem.Seek(0, SeekOrigin.Begin);
// Get a reader for the data
reader = ImageDataFormat.GetImageReader(mem, ImageDataFormat.DOOMPICTURE, General.Map.Data.Palette);
if(reader is UnknownImageReader)
// Get the lump data stream
lumpdata = General.Map.Data.GetPatchData(Name);
if(lumpdata != null)
{
// Data is in an unknown format!
General.WriteLogLine("WARNING: Sprite lump '" + Name + "' data format could not be read!");
// Copy lump data to memory
lumpdata.Seek(0, SeekOrigin.Begin);
membytes = new byte[(int)lumpdata.Length];
lumpdata.Read(membytes, 0, (int)lumpdata.Length);
mem = new MemoryStream(membytes);
mem.Seek(0, SeekOrigin.Begin);
// Get a reader for the data
reader = ImageDataFormat.GetImageReader(mem, ImageDataFormat.DOOMPICTURE, General.Map.Data.Palette);
if(reader is UnknownImageReader)
{
// Data is in an unknown format!
General.WriteLogLine("WARNING: Sprite lump '" + Name + "' data format could not be read!");
}
// Read data as bitmap
mem.Seek(0, SeekOrigin.Begin);
bitmap = reader.ReadAsBitmap(mem);
}
else
{
// Missing a patch lump!
General.WriteLogLine("WARNING: Missing sprite lump '" + Name + "'!");
}
// Read data as bitmap
mem.Seek(0, SeekOrigin.Begin);
bitmap = reader.ReadAsBitmap(mem);
// Pass on to base
base.LoadImage();
}
else
{
// Missing a patch lump!
General.WriteLogLine("WARNING: Missing sprite lump '" + Name + "'!");
}
// Pass on to base
base.LoadImage();
}
#endregion

View file

@ -106,56 +106,59 @@ namespace CodeImp.DoomBuilder.Data
// Leave when already loaded
if(this.IsLoaded) return;
// Create texture bitmap
bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb);
bitmapdata = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
pixels = (PixelColor*)bitmapdata.Scan0.ToPointer();
General.ZeroMemory(new IntPtr(pixels), width * height * sizeof(PixelColor));
// Go for all patches
foreach(TexturePatch p in patches)
lock(this)
{
// Get the patch data stream
patchdata = General.Map.Data.GetPatchData(p.lumpname);
if(patchdata != null)
{
// Copy patch data to memory
patchdata.Seek(0, SeekOrigin.Begin);
membytes = new byte[(int)patchdata.Length];
patchdata.Read(membytes, 0, (int)patchdata.Length);
mem = new MemoryStream(membytes);
mem.Seek(0, SeekOrigin.Begin);
// Create texture bitmap
bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb);
bitmapdata = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
pixels = (PixelColor*)bitmapdata.Scan0.ToPointer();
General.ZeroMemory(new IntPtr(pixels), width * height * sizeof(PixelColor));
// Get a reader for the data
reader = ImageDataFormat.GetImageReader(mem, ImageDataFormat.DOOMPICTURE, General.Map.Data.Palette);
if(reader is UnknownImageReader)
{
// Data is in an unknown format!
General.WriteLogLine("WARNING: Patch lump '" + p.lumpname + "' data format could not be read, while loading texture '" + this.Name + "'!");
failed = true;
break;
}
// Draw the patch
mem.Seek(0, SeekOrigin.Begin);
reader.DrawToPixelData(mem, pixels, width, height, p.x, p.y);
}
else
// Go for all patches
foreach(TexturePatch p in patches)
{
// Missing a patch lump!
General.WriteLogLine("WARNING: Missing patch lump '" + p.lumpname + "' while loading texture '" + this.Name + "'!");
// Get the patch data stream
patchdata = General.Map.Data.GetPatchData(p.lumpname);
if(patchdata != null)
{
// Copy patch data to memory
patchdata.Seek(0, SeekOrigin.Begin);
membytes = new byte[(int)patchdata.Length];
patchdata.Read(membytes, 0, (int)patchdata.Length);
mem = new MemoryStream(membytes);
mem.Seek(0, SeekOrigin.Begin);
// Get a reader for the data
reader = ImageDataFormat.GetImageReader(mem, ImageDataFormat.DOOMPICTURE, General.Map.Data.Palette);
if(reader is UnknownImageReader)
{
// Data is in an unknown format!
General.WriteLogLine("WARNING: Patch lump '" + p.lumpname + "' data format could not be read, while loading texture '" + this.Name + "'!");
failed = true;
break;
}
// Draw the patch
mem.Seek(0, SeekOrigin.Begin);
reader.DrawToPixelData(mem, pixels, width, height, p.x, p.y);
}
else
{
// Missing a patch lump!
General.WriteLogLine("WARNING: Missing patch lump '" + p.lumpname + "' while loading texture '" + this.Name + "'!");
}
}
// Done
bitmap.UnlockBits(bitmapdata);
// When failed, use the error picture
if(failed) bitmap = UnknownImageReader.ReadAsBitmap();
// Pass on to base
base.LoadImage();
}
// Done
bitmap.UnlockBits(bitmapdata);
// When failed, use the error picture
if(failed) bitmap = UnknownImageReader.ReadAsBitmap();
// Pass on to base
base.LoadImage();
}
#endregion

View file

@ -52,6 +52,7 @@ namespace CodeImp.DoomBuilder.Interface
{
// Initialize
InitializeComponent();
this.Text = "Open Map from " + Path.GetFileName(filepathname);
this.filepathname = filepathname;
this.options = new MapOptions();
}