- change a lot in the resources system

- fixed memory leak in PixelColorBlock
- several small changes and bugfixes
This commit is contained in:
codeimp 2008-09-28 21:20:56 +00:00
parent 2784090aca
commit 1dad4b68c6
51 changed files with 712 additions and 407 deletions

BIN
Resources/Failed.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

BIN
Resources/Hourglass3D.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 406 B

View file

@ -113,20 +113,30 @@ namespace CodeImp.DoomBuilder.Actions
float changex, changey;
// Poll the device
Result result = mouse.Poll();
if(result.IsSuccess)
try
{
// Get the changes since previous poll
ms = mouse.GetCurrentState();
Result result = mouse.Poll();
if(result.IsSuccess)
{
// Get the changes since previous poll
ms = mouse.GetCurrentState();
// Calculate changes depending on sensitivity
changex = (float)ms.X * General.Settings.VisualMouseSensX;
changey = (float)ms.Y * General.Settings.VisualMouseSensY;
// Calculate changes depending on sensitivity
changex = (float)ms.X * General.Settings.VisualMouseSensX;
changey = (float)ms.Y * General.Settings.VisualMouseSensY;
// Return changes
return new Vector2D(changex, changey);
// Return changes
return new Vector2D(changex, changey);
}
else
{
// Reaquire device
try { mouse.Acquire(); }
catch(Exception) { }
return new Vector2D();
}
}
else
catch(DirectInputException)
{
// Reaquire device
try { mouse.Acquire(); }

View file

@ -600,6 +600,8 @@
<None Include="Resources\Copy.png" />
<None Include="Resources\Cut.png" />
<Content Include="Resources\DB2.ico" />
<EmbeddedResource Include="Resources\Hourglass3D.png" />
<None Include="Resources\Failed.png" />
<None Include="Resources\Monster2.png" />
<None Include="Resources\Grid2_arrowup.png" />
<None Include="Resources\Zoom_arrowup.png" />

View file

@ -30,6 +30,7 @@ using CodeImp.DoomBuilder.Map;
using CodeImp.DoomBuilder.Rendering;
using CodeImp.DoomBuilder.Geometry;
using CodeImp.DoomBuilder.Editing;
using CodeImp.DoomBuilder.Actions;
#endregion
@ -215,6 +216,23 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
#region ================== Methods
[EndAction("reloadresources", BaseAction = true)]
public void ReloadResources()
{
foreach(KeyValuePair<Sector, BaseVisualSector> s in allsectors) s.Value.Dispose();
allsectors.Clear();
visiblesectors.Clear();
}
// Mode engages
public override void OnEngage()
{
// Update the used textures
General.Map.Data.UpdateUsedTextures();
base.OnEngage();
}
// This draws a frame
public override void OnRedrawDisplay()
{

View file

@ -62,7 +62,6 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
// Load floor texture
base.Texture = General.Map.Data.GetFlatImage(s.LongCeilTexture);
base.Texture.LoadImage();
// Make vertices
verts = new WorldVertex[s.Vertices.Length];
@ -74,8 +73,16 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
verts[i].c = -1;
// Grid aligned texture coordinates
verts[i].u = s.Vertices[i].x / base.Texture.ScaledWidth;
verts[i].v = s.Vertices[i].y / base.Texture.ScaledHeight;
if(base.Texture.IsImageLoaded)
{
verts[i].u = s.Vertices[i].x / base.Texture.ScaledWidth;
verts[i].v = s.Vertices[i].y / base.Texture.ScaledHeight;
}
else
{
verts[i].u = s.Vertices[i].x / 64;
verts[i].v = s.Vertices[i].y / 64;
}
// Vertex coordinates
verts[i].x = s.Vertices[i].x;

View file

@ -61,7 +61,6 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
// Load floor texture
base.Texture = General.Map.Data.GetFlatImage(s.LongFloorTexture);
base.Texture.LoadImage();
// Make vertices
verts = new WorldVertex[s.Vertices.Length];
@ -73,8 +72,16 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
verts[i].c = -1;
// Grid aligned texture coordinates
verts[i].u = s.Vertices[i].x / base.Texture.ScaledWidth;
verts[i].v = s.Vertices[i].y / base.Texture.ScaledHeight;
if(base.Texture.IsImageLoaded)
{
verts[i].u = s.Vertices[i].x / base.Texture.ScaledWidth;
verts[i].v = s.Vertices[i].y / base.Texture.ScaledHeight;
}
else
{
verts[i].u = s.Vertices[i].x / 64;
verts[i].v = s.Vertices[i].y / 64;
}
// Vertex coordinates
verts[i].x = s.Vertices[i].x;

View file

@ -74,7 +74,6 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
{
// Load texture
base.Texture = General.Map.Data.GetTextureImage(s.LongLowTexture);
base.Texture.LoadImage();
}
else
{

View file

@ -83,7 +83,6 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
{
// Load texture
base.Texture = General.Map.Data.GetTextureImage(s.LongMiddleTexture);
base.Texture.LoadImage();
}
else
{

View file

@ -74,7 +74,6 @@ namespace CodeImp.DoomBuilder.BuilderModes.Editing
{
// Load texture
base.Texture = General.Map.Data.GetTextureImage(s.LongHighTexture);
base.Texture.LoadImage();
}
else
{

View file

@ -59,7 +59,7 @@ namespace CodeImp.DoomBuilder.Controls
else
{
// Set the image
return General.Map.Data.GetFlatBitmap(imagename);
return General.Map.Data.GetFlatImage(imagename).GetPreview();
}
}

View file

@ -15,6 +15,7 @@ namespace CodeImp.DoomBuilder.Controls
{
if(disposing && (components != null))
{
CleanUp();
components.Dispose();
}
base.Dispose(disposing);

View file

@ -40,9 +40,6 @@ namespace CodeImp.DoomBuilder.Controls
{
#region ================== Constants
// Maximum loaded items
private const int MAX_LOADED_ITEMS = 200;
#endregion
#region ================== Delegates / Events
@ -61,9 +58,6 @@ namespace CodeImp.DoomBuilder.Controls
// All items
private List<ImageBrowserItem> items;
// Loaded items
private LinkedList<ImageBrowserItem> loadeditems;
#endregion
#region ================== Properties
@ -81,7 +75,6 @@ namespace CodeImp.DoomBuilder.Controls
// Initialize
InitializeComponent();
items = new List<ImageBrowserItem>();
loadeditems = new LinkedList<ImageBrowserItem>();
// Move textbox with label
objectname.Left = label.Right + label.Margin.Right + objectname.Margin.Left;
@ -98,7 +91,7 @@ namespace CodeImp.DoomBuilder.Controls
}
}
// This cleans everything up (we can't override Dispose?)
// This cleans everything up
public virtual void CleanUp()
{
// Stop refresh timer
@ -109,24 +102,16 @@ namespace CodeImp.DoomBuilder.Controls
list.SuspendLayout();
list.BeginUpdate();
// Go for all items
foreach(ImageBrowserItem i in list.Items)
{
// Queue image for unloading if only temporary
if(i.icon.IsLoaded && i.icon.Temporary) General.Map.Data.BackgroundLoadImage(i.icon, false);
// Dispose item
i.Dispose();
}
// Dispose items
foreach(ImageBrowserItem i in list.Items) i.Dispose();
// Trash list items
list.Clear();
loadeditems.Clear();
// Done updating list
updating = false;
list.EndUpdate();
list.ResumeLayout();
updating = false;
}
#endregion
@ -136,67 +121,34 @@ namespace CodeImp.DoomBuilder.Controls
// Draw item
private void list_DrawItem(object sender, DrawListViewItemEventArgs e)
{
if(!updating) e.Graphics.DrawImageUnscaled((e.Item as ImageBrowserItem).GetImage(e.Bounds), e.Bounds);
if(!updating) (e.Item as ImageBrowserItem).Draw(e.Graphics, e.Bounds);
}
// Refresher
private void refreshtimer_Tick(object sender, EventArgs e)
{
bool allpreviewsloaded = true;
// Go for all items
foreach(ImageBrowserItem i in list.Items)
{
// Bounds within view?
if(i.Bounds.IntersectsWith(list.ClientRectangle))
// Check if there are still previews that are not loaded
allpreviewsloaded &= i.IsPreviewLoaded;
// Items needs to be redrawn?
if(i.CheckRedrawNeeded())
{
// Remove from loaded list if in there
if(i.LoadedTicket != null) loadeditems.Remove(i.LoadedTicket);
// Image not loaded?
if(!i.icon.IsLoaded && !i.IsImageLoaded)
// Bounds within view?
if(i.Bounds.IntersectsWith(list.ClientRectangle))
{
// Queue for background loading
General.Map.Data.BackgroundLoadImage(i.icon, true);
}
// Items needs to be redrawn?
if(i.CheckRedrawNeeded(i.Bounds))
{
// Redraw item
i.GetImage(i.Bounds);
// Refresh item in list
list.RedrawItems(i.Index, i.Index, false);
}
else
{
// Queue for unloading if only temporary
if(i.icon.IsLoaded && i.icon.Temporary) General.Map.Data.BackgroundLoadImage(i.icon, false);
}
// Add to loaded list
i.LoadedTicket = loadeditems.AddLast(i);
}
else
{
// Queue for unloading if only temporary
if(i.icon.IsLoaded && i.icon.Temporary)
General.Map.Data.BackgroundLoadImage(i.icon, false);
else
General.Map.Data.BackgroundCancelImage(i.icon);
}
}
// More items laoded than allowed?
if(loadeditems.Count > MAX_LOADED_ITEMS)
{
// Unload items
for(int i = 0; i < (loadeditems.Count - MAX_LOADED_ITEMS); i++)
{
loadeditems.First.Value.ReleaseImage();
loadeditems.First.Value.LoadedTicket = null;
loadeditems.RemoveFirst();
}
}
// If all previews were loaded, stop this timer
if(allpreviewsloaded) refreshtimer.Stop();
}
#endregion

View file

@ -46,11 +46,8 @@ namespace CodeImp.DoomBuilder.Controls
// Group
private ListViewGroup listgroup;
private LinkedListNode<ImageBrowserItem> loadedticked;
// Image cache
private Image normalimage;
private Image selectedimage;
private bool imageloaded;
#endregion
@ -58,9 +55,7 @@ namespace CodeImp.DoomBuilder.Controls
#region ================== Properties
public ListViewGroup ListGroup { get { return listgroup; } set { listgroup = value; } }
public LinkedListNode<ImageBrowserItem> LoadedTicket { get { return loadedticked; } set { loadedticked = value; } }
public bool IsImageLoaded { get { return imageloaded; } }
public bool HasImage { get { return (normalimage != null); } }
public bool IsPreviewLoaded { get { return imageloaded; } }
#endregion
@ -78,8 +73,6 @@ namespace CodeImp.DoomBuilder.Controls
// Disposer
public void Dispose()
{
ReleaseImage();
loadedticked = null;
icon = null;
listgroup = null;
}
@ -89,36 +82,37 @@ namespace CodeImp.DoomBuilder.Controls
#region ================== Methods
// This checks if a redraw is needed
public bool CheckRedrawNeeded(Rectangle bounds)
public bool CheckRedrawNeeded()
{
return (normalimage == null) || (selectedimage == null) || (icon.IsLoaded && !imageloaded);
return (icon.IsPreviewLoaded != imageloaded);
}
// This draws the images
private Image DrawImage(Rectangle bounds, bool selected)
public void Draw(Graphics g, Rectangle bounds)
{
Brush forecolor;
Brush backcolor;
// Make a new image and graphics to draw with
Image image = new Bitmap(bounds.Width, bounds.Height, PixelFormat.Format32bppArgb);
Graphics g = Graphics.FromImage(image);
// Remember if the preview is loaded
imageloaded = icon.IsPreviewLoaded;
// Drawing settings
g.CompositingQuality = CompositingQuality.HighSpeed;
g.InterpolationMode = InterpolationMode.Bilinear;
g.SmoothingMode = SmoothingMode.HighQuality;
g.InterpolationMode = InterpolationMode.NearestNeighbor;
g.SmoothingMode = SmoothingMode.HighSpeed;
g.PixelOffsetMode = PixelOffsetMode.None;
// Determine coordinates
SizeF textsize = g.MeasureString(this.Text, this.ListView.Font, bounds.Width);
Size bordersize = new Size((bounds.Width - 64) >> 1, (bounds.Height - 64 - (int)textsize.Height) >> 1);
Rectangle imagerect = new Rectangle(bordersize.Width, bordersize.Height, 64, 64);
PointF textpos = new PointF(((float)bounds.Width - textsize.Width) * 0.5f, bounds.Height - textsize.Height - 2);
Rectangle imagerect = new Rectangle(bounds.Left + ((bounds.Width - 64) >> 1),
bounds.Top + ((bounds.Height - 64 - (int)textsize.Height) >> 1), 64, 64);
PointF textpos = new PointF(bounds.Left + ((float)bounds.Width - textsize.Width) * 0.5f, bounds.Bottom - textsize.Height - 2);
// Determine colors
if(selected)
if(this.Selected)
{
// Highlighted
backcolor = new LinearGradientBrush(new Point(0, 0), new Point(0, bounds.Height),
backcolor = new LinearGradientBrush(new Point(0, bounds.Top - 1), new Point(0, bounds.Bottom + 1),
AdjustedColor(SystemColors.Highlight, 0.2f),
AdjustedColor(SystemColors.Highlight, -0.1f));
forecolor = SystemBrushes.HighlightText;
@ -131,43 +125,9 @@ namespace CodeImp.DoomBuilder.Controls
}
// Draw!
g.FillRectangle(backcolor, 0, 0, bounds.Width, bounds.Height);
g.DrawImage(icon.Bitmap, General.MakeZoomedRect(icon.Bitmap.Size, imagerect));
g.FillRectangle(backcolor, bounds);
icon.DrawPreview(g, imagerect.Location);
g.DrawString(this.Text, this.ListView.Font, forecolor, textpos);
// Done
g.Dispose();
return image;
}
// This requests the cached image and redraws it if needed
public Image GetImage(Rectangle bounds)
{
// Do we need to redraw?
if(CheckRedrawNeeded(bounds))
{
// Keep image loaded state
imageloaded = icon.IsLoaded;
// Redraw both images
if(normalimage != null) normalimage.Dispose();
if(selectedimage != null) selectedimage.Dispose();
normalimage = DrawImage(bounds, false);
selectedimage = DrawImage(bounds, true);
}
// Return image
if(this.Selected) return selectedimage; else return normalimage;
}
// This releases image resources
public void ReleaseImage()
{
if(normalimage != null) normalimage.Dispose();
if(selectedimage != null) selectedimage.Dispose();
normalimage = null;
selectedimage = null;
imageloaded = false;
}
// This brightens or darkens a color

View file

@ -15,6 +15,7 @@ namespace CodeImp.DoomBuilder.Controls
{
if(disposing && (components != null))
{
bmp.Dispose();
components.Dispose();
}
base.Dispose(disposing);

View file

@ -38,16 +38,32 @@ namespace CodeImp.DoomBuilder.Controls
{
public abstract partial class ImageSelectorControl : UserControl
{
// Properties
#region ================== Variables
private Bitmap bmp;
#endregion
#region ================== Properties
public string TextureName { get { return name.Text; } set { name.Text = value; } }
#endregion
#region ================== Constructor / Destructor
// Constructor
public ImageSelectorControl()
{
// Initialize
InitializeComponent();
bmp = new Bitmap(PreviewManager.IMAGE_WIDTH, PreviewManager.IMAGE_HEIGHT);
}
#endregion
#region ================== Events
// When resized
private void ImageSelectorControl_Resize(object sender, EventArgs e)
{
@ -74,9 +90,27 @@ namespace CodeImp.DoomBuilder.Controls
// Name text changed
private void name_TextChanged(object sender, EventArgs e)
{
// Show it centered
General.DisplayZoomedImage(preview, FindImage(name.Text));
}
#endregion
#region ================== Methods
// This redraws the image preview
private void ShowPreview(ImageData image)
{
// Draw preview image
Graphics g = Graphics.FromImage(bmp);
g.Clear(Color.Transparent);
image.DrawPreview(g, new Point(0, 0));
g.Dispose();
// Show it centered
General.DisplayZoomedImage(preview, bmp);
}
// This must determine and return the image to show
protected abstract Image FindImage(string imagename);
@ -98,5 +132,7 @@ namespace CodeImp.DoomBuilder.Controls
return original;
}
}
#endregion
}
}

View file

@ -259,7 +259,7 @@ namespace CodeImp.DoomBuilder.Controls
else
{
// Set the image
panel.BackgroundImage = General.Map.Data.GetTextureBitmap(name);
panel.BackgroundImage = General.Map.Data.GetTextureImage(name).GetPreview();
}
// Image not null?

View file

@ -65,8 +65,8 @@ namespace CodeImp.DoomBuilder.Controls
brightness.Text = s.Brightness.ToString();
floorname.Text = s.FloorTexture;
ceilingname.Text = s.CeilTexture;
General.DisplayZoomedImage(floortex, General.Map.Data.GetFlatBitmap(s.FloorTexture));
General.DisplayZoomedImage(ceilingtex, General.Map.Data.GetFlatBitmap(s.CeilTexture));
General.DisplayZoomedImage(floortex, General.Map.Data.GetFlatImage(s.FloorTexture).GetPreview());
General.DisplayZoomedImage(ceilingtex, General.Map.Data.GetFlatImage(s.CeilTexture).GetPreview());
// Show the whole thing
this.Show();

View file

@ -68,7 +68,7 @@ namespace CodeImp.DoomBuilder.Controls
else
{
// Set the image
return General.Map.Data.GetTextureBitmap(imagename);
return General.Map.Data.GetTextureImage(imagename).GetPreview();
}
}

View file

@ -136,7 +136,7 @@ namespace CodeImp.DoomBuilder.Controls
tag.Text = t.Tag.ToString();
angle.Text = t.AngleDeg.ToString() + "\u00B0";
spritename.Text = ti.Sprite;
General.DisplayZoomedImage(spritetex, General.Map.Data.GetSpriteBitmap(ti.Sprite));
General.DisplayZoomedImage(spritetex, General.Map.Data.GetSpriteImage(ti.Sprite).GetPreview());
// Arguments
if(act != null)

View file

@ -29,6 +29,7 @@ using System.Windows.Forms;
using SlimDX.Direct3D9;
using CodeImp.DoomBuilder.Config;
using System.Threading;
using CodeImp.DoomBuilder.Map;
#endregion
@ -62,12 +63,14 @@ namespace CodeImp.DoomBuilder.Data
// Background loading
private Queue<ImageData> imageque;
private Thread backgroundloader;
private volatile bool updatedusedtextures;
// Image previews
private PreviewManager previews;
// Special images
private ImageData missingtexture3d;
private ImageData hourglass3d;
// Disposing
private bool isdisposed = false;
@ -77,21 +80,22 @@ namespace CodeImp.DoomBuilder.Data
#region ================== Properties
public Playpal Palette { get { return palette; } }
internal PreviewManager Previews { get { return previews; } }
public PreviewManager Previews { get { return previews; } }
public ICollection<ImageData> Textures { get { return textures.Values; } }
public ICollection<ImageData> Flats { get { return flats.Values; } }
public List<string> TextureNames { get { return texturenames; } }
public List<string> FlatNames { get { return flatnames; } }
public bool IsDisposed { get { return isdisposed; } }
public ImageData MissingTexture3D { get { return missingtexture3d; } }
public ImageData Hourglass3D { get { return hourglass3d; } }
public bool IsLoading
{
get
{
if(loadlist != null)
if(imageque != null)
{
return (backgroundloader != null) && backgroundloader.IsAlive && (loadlist.Count > 0);
return (backgroundloader != null) && backgroundloader.IsAlive && ((imageque.Count > 0) || previews.IsLoading);
}
else
{
@ -113,6 +117,8 @@ namespace CodeImp.DoomBuilder.Data
// Load special images
missingtexture3d = new ResourceImage("MissingTexture3D.png");
missingtexture3d.LoadImage();
hourglass3d = new ResourceImage("Hourglass3D.png");
hourglass3d.LoadImage();
}
// Disposer
@ -163,7 +169,7 @@ namespace CodeImp.DoomBuilder.Data
sprites = new Dictionary<long, ImageData>();
texturenames = new List<string>();
flatnames = new List<string>();
loadlist = new LinkedList<ImageData>();
imageque = new Queue<ImageData>();
previews = new PreviewManager();
// Go for all locations
@ -252,7 +258,7 @@ namespace CodeImp.DoomBuilder.Data
sprites = null;
texturenames = null;
flatnames = null;
loadlist = null;
imageque = null;
}
#endregion
@ -310,7 +316,7 @@ namespace CodeImp.DoomBuilder.Data
// 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.Name = "Background Loader";
backgroundloader.Priority = ThreadPriority.Lowest;
backgroundloader.Start();
}
@ -318,7 +324,7 @@ namespace CodeImp.DoomBuilder.Data
// This stops background loading
private void StopBackgroundLoader()
{
LinkedListNode<ImageData> n;
ImageData img;
General.WriteLogLine("Stopping background resource loading...");
if(backgroundloader != null)
@ -328,14 +334,32 @@ namespace CodeImp.DoomBuilder.Data
backgroundloader.Join();
// Reset load states on all images in the list
n = loadlist.First;
while(n != null)
while(imageque.Count > 0)
{
n.Value.LoadState = ImageData.LOADSTATE_NONE;
n.Value.LoadingTicket = null;
n = n.Next;
img = imageque.Dequeue();
switch(img.ImageState)
{
case ImageLoadState.Loading:
img.ImageState = ImageLoadState.None;
break;
case ImageLoadState.Unloading:
img.ImageState = ImageLoadState.Ready;
break;
}
switch(img.PreviewState)
{
case ImageLoadState.Loading:
img.PreviewState = ImageLoadState.None;
break;
case ImageLoadState.Unloading:
img.PreviewState = ImageLoadState.Ready;
break;
}
}
loadlist.Clear();
// Done
backgroundloader = null;
@ -350,11 +374,18 @@ namespace CodeImp.DoomBuilder.Data
{
do
{
// Do we have to update the used-in-map status?
if(updatedusedtextures)
{
BackgroundUpdateUsedTextures();
updatedusedtextures = false;
}
// Get next item
ImageData image = null;
lock(imageque)
{
// Fethc next image to process
// Fetch next image to process
if(imageque.Count > 0) image = imageque.Dequeue();
}
@ -362,23 +393,16 @@ namespace CodeImp.DoomBuilder.Data
if(image != null)
{
// Load this image?
if(image.ImageState == ImageLoadState.Loading)
if(image.IsReferenced && (image.ImageState != ImageLoadState.Ready))
{
// Still referenced?
if(image.IsReferenced)
image.LoadImage();
else
image.ImageState = ImageLoadState.None;
image.LoadImage();
}
// Unload this image?
if(image.ImageState == ImageLoadState.Unloading)
if(!image.IsReferenced && (image.ImageState != ImageLoadState.None))
{
// Still unreferenced?
if(!image.IsReferenced)
image.UnloadImage();
else
image.ImageState = ImageLoadState.Ready;
image.UnloadImage();
}
}
@ -405,9 +429,6 @@ namespace CodeImp.DoomBuilder.Data
Thread.Sleep(50);
}
}
// Done
image = null;
}
while(true);
}
@ -440,6 +461,41 @@ namespace CodeImp.DoomBuilder.Data
General.MainWindow.UpdateStatusIcon();
}
// This updates the used-in-map status on all textures and flats
private void BackgroundUpdateUsedTextures()
{
Dictionary<long, long> useditems = new Dictionary<long, long>();
// Go through the map to find the used textures
foreach(Sidedef sd in General.Map.Map.Sidedefs)
{
// Add used textures to dictionary
if(sd.HighTexture.Length > 0) useditems[sd.LongHighTexture] = 0;
if(sd.LowTexture.Length > 0) useditems[sd.LongMiddleTexture] = 0;
if(sd.MiddleTexture.Length > 0) useditems[sd.LongLowTexture] = 0;
}
// Go through the map to find the used flats
foreach(Sector s in General.Map.Map.Sectors)
{
// Add used flats to dictionary
useditems[s.LongFloorTexture] = 0;
useditems[s.LongCeilTexture] = 0;
}
// Set used on all textures
foreach(KeyValuePair<long, ImageData> i in textures)
i.Value.SetUsedInMap(useditems.ContainsKey(i.Key));
// Flats are not already included with the textures?
if(!General.Map.Config.MixTexturesFlats)
{
// Set used on all flats
foreach(KeyValuePair<long, ImageData> i in flats)
i.Value.SetUsedInMap(useditems.ContainsKey(i.Key));
}
}
#endregion
#region ================== Palette
@ -505,6 +561,9 @@ namespace CodeImp.DoomBuilder.Data
flats.Remove(img.LongName);
flats.Add(img.LongName, img);
}
// Add to preview manager
previews.AddImage(img);
}
}
}
@ -554,6 +613,10 @@ namespace CodeImp.DoomBuilder.Data
}
}
// BAD! These block while loading the image. That is not
// what our background loading system is for!
/*
// This returns a bitmap by string
public Bitmap GetTextureBitmap(string name)
{
@ -587,6 +650,7 @@ namespace CodeImp.DoomBuilder.Data
img.CreateTexture();
return img.Texture;
}
*/
#endregion
@ -621,6 +685,9 @@ namespace CodeImp.DoomBuilder.Data
textures.Remove(img.LongName);
textures.Add(img.LongName, img);
}
// Add to preview manager
previews.AddImage(img);
}
}
}
@ -670,6 +737,9 @@ namespace CodeImp.DoomBuilder.Data
}
}
// BAD! These block while loading the image. That is not
// what our background loading system is for!
/*
// This returns a bitmap by string
public Bitmap GetFlatBitmap(string name)
{
@ -703,6 +773,7 @@ namespace CodeImp.DoomBuilder.Data
img.CreateTexture();
return img.Texture;
}
*/
#endregion
@ -736,6 +807,9 @@ namespace CodeImp.DoomBuilder.Data
// Add to collection
sprites.Add(ti.SpriteLongName, image);
// Add to preview manager
previews.AddImage(image);
}
}
}
@ -787,6 +861,9 @@ namespace CodeImp.DoomBuilder.Data
}
}
// BAD! These block while loading the image. That is not
// what our background loading system is for!
/*
// This returns a bitmap by string
public Bitmap GetSpriteBitmap(string name)
{
@ -803,6 +880,7 @@ namespace CodeImp.DoomBuilder.Data
img.CreateTexture();
return img.Texture;
}
*/
#endregion
@ -834,6 +912,13 @@ namespace CodeImp.DoomBuilder.Data
return false;
}
// This signals the background thread to update the
// used-in-map status on all textures and flats
public void UpdateUsedTextures()
{
updatedusedtextures = true;
}
#endregion
}
}

View file

@ -58,7 +58,7 @@ namespace CodeImp.DoomBuilder.Data
public override void LoadImage()
{
// Leave when already loaded
if(this.IsLoaded) return;
if(this.IsImageLoaded) return;
lock(this)
{

View file

@ -57,7 +57,7 @@ namespace CodeImp.DoomBuilder.Data
byte[] membytes;
// Leave when already loaded
if(this.IsLoaded) return;
if(this.IsImageLoaded) return;
lock(this)
{
@ -86,6 +86,9 @@ namespace CodeImp.DoomBuilder.Data
bitmap = reader.ReadAsBitmap(mem);
if(bitmap == null) return;
// Done
mem.Dispose();
// Get width and height from image
width = bitmap.Size.Width;
height = bitmap.Size.Height;

View file

@ -51,13 +51,14 @@ namespace CodeImp.DoomBuilder.Data
protected bool usecolorcorrection;
// Loading
private LinkedListNode<ImageData> processticket;
private ImageLoadState previewstate;
private ImageLoadState imagestate;
private volatile ImageLoadState previewstate;
private volatile ImageLoadState imagestate;
private volatile int previewindex;
protected volatile bool loadfailed;
// References
private bool usedinmap;
private int references;
private volatile bool usedinmap;
private volatile int references;
// GDI bitmap
protected Bitmap bitmap;
@ -76,19 +77,21 @@ namespace CodeImp.DoomBuilder.Data
public string Name { get { return name; } }
public long LongName { get { return longname; } }
public bool UseColorCorrection { get { return usecolorcorrection; } set { usecolorcorrection = value; } }
public Bitmap Bitmap { get { lock(this) { if(bitmap != null) return new Bitmap(bitmap); else return CodeImp.DoomBuilder.Properties.Resources.Hourglass; } } }
//public Bitmap Bitmap { get { lock(this) { if(bitmap != null) return new Bitmap(bitmap); else return CodeImp.DoomBuilder.Properties.Resources.Hourglass; } } }
public Bitmap Bitmap { get { lock(this) { if(bitmap != null) return bitmap; else return CodeImp.DoomBuilder.Properties.Resources.Hourglass; } } }
public Texture Texture { get { lock(this) { return texture; } } }
public bool IsPreviewLoaded { get { lock(this) { return (previewstate == ImageLoadState.Ready); } } }
public bool IsImageLoaded { get { lock(this) { return (imagestate == ImageLoadState.Ready); } } }
public bool IsPreviewLoaded { get { return (previewstate == ImageLoadState.Ready); } }
public bool IsImageLoaded { get { return (imagestate == ImageLoadState.Ready); } }
public bool LoadFailed { get { return loadfailed; } }
public bool IsDisposed { get { return isdisposed; } }
internal ImageLoadState ImageState { get { return imagestate; } set { imagestate = value; } }
internal ImageLoadState PreviewState { get { return previewstate; } set { previewstate = value; } }
internal LinkedListNode<ImageData> ProcessTicket { get { return processticket; } set { processticket = value; } }
internal bool IsReferenced { get { return (references > 0) || usedinmap; } }
internal bool UsedInMap { get { return usedinmap; } set { usedinmap = value; } }
public ImageLoadState ImageState { get { return imagestate; } internal set { imagestate = value; } }
public ImageLoadState PreviewState { get { return previewstate; } internal set { previewstate = value; } }
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; } }
internal int PreviewIndex { get { return previewindex; } set { previewindex = value; } }
public float ScaledWidth { get { return scaledwidth; } }
public float ScaledHeight { get { return scaledheight; } }
@ -134,10 +137,21 @@ namespace CodeImp.DoomBuilder.Data
#region ================== Management
// This sets the status of the texture usage in the map
internal void SetUsedInMap(bool used)
{
if(used != usedinmap)
{
usedinmap = used;
General.Map.Data.ProcessImage(this);
}
}
// This adds a reference
public void AddReference()
{
references++;
if(references == 1) General.Map.Data.ProcessImage(this);
}
// This removes a reference
@ -145,6 +159,7 @@ namespace CodeImp.DoomBuilder.Data
{
references--;
if(references < 0) General.Fail("FAIL! (references < 0)", "Somewhere this image is dereferenced more than it was referenced.");
if(references == 0) General.Map.Data.ProcessImage(this);
}
// This sets the name
@ -172,28 +187,42 @@ namespace CodeImp.DoomBuilder.Data
lock(this)
{
// This applies brightness correction on the image
if((bitmap != null) && usecolorcorrection)
// Bitmap loaded successfully?
if(bitmap != null)
{
try
// This applies brightness correction on the image
if(usecolorcorrection)
{
// Try locking the bitmap
bmpdata = bitmap.LockBits(new Rectangle(0, 0, bitmap.Size.Width, bitmap.Size.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
}
catch(Exception e)
{
General.WriteLogLine("ERROR: Cannot lock image '" + name + "' for color correction. " + e.GetType().Name + ": " + e.Message);
}
try
{
// Try locking the bitmap
bmpdata = bitmap.LockBits(new Rectangle(0, 0, bitmap.Size.Width, bitmap.Size.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
}
catch(Exception e)
{
General.WriteLogLine("ERROR: Cannot lock image '" + name + "' for color correction. " + e.GetType().Name + ": " + e.Message);
}
// Bitmap locked?
if(bmpdata != null)
{
// Apply color correction
PixelColor* pixels = (PixelColor*)(bmpdata.Scan0.ToPointer());
General.Colors.ApplColorCorrection(pixels, bmpdata.Width * bmpdata.Height);
bitmap.UnlockBits(bmpdata);
// Bitmap locked?
if(bmpdata != null)
{
// Apply color correction
PixelColor* pixels = (PixelColor*)(bmpdata.Scan0.ToPointer());
General.Colors.ApplColorCorrection(pixels, bmpdata.Width * bmpdata.Height);
bitmap.UnlockBits(bmpdata);
}
}
}
else
{
// Loading failed
// We still mark the image as ready so that it will
// not try loading again until Reload Resources is used
loadfailed = true;
bitmap = new Bitmap(Properties.Resources.Failed);
width = bitmap.Size.Width;
height = bitmap.Size.Height;
}
// Image is ready
imagestate = ImageLoadState.Ready;
@ -208,14 +237,18 @@ namespace CodeImp.DoomBuilder.Data
lock(this)
{
// Only do this when texture is not created yet
if(((texture == null) || (texture.Disposed)) && this.IsLoaded)
if(((texture == null) || (texture.Disposed)) && this.IsImageLoaded)
{
Image img = bitmap;
if(loadfailed) img = Properties.Resources.Failed;
// Write to memory stream and read from memory
memstream = new MemoryStream();
bitmap.Save(memstream, ImageFormat.Bmp);
img.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, mipmaplevels,
Usage.None, Format.Unknown, Pool.Managed, Filter.Box, Filter.Box, 0);
texture = Texture.FromStream(General.Map.Graphics.Device, memstream, (int)memstream.Length,
img.Size.Width, img.Size.Height, mipmaplevels, Usage.None, Format.Unknown,
Pool.Managed, Filter.Box, Filter.Box, 0);
memstream.Dispose();
}
}
@ -232,6 +265,88 @@ namespace CodeImp.DoomBuilder.Data
}
}
// This draws a preview
public virtual void DrawPreviewCentered(Graphics target, Rectangle targetview)
{
lock(this)
{
// Preview ready?
if(previewstate == ImageLoadState.Ready)
{
// Draw preview
General.Map.Data.Previews.DrawPreviewCentered(previewindex, target, targetview);
}
// Loading failed?
else if(loadfailed)
{
// Draw error bitmap
RectangleF targetpos = General.MakeZoomedRect(Properties.Resources.Failed.Size, targetview);
target.DrawImage(Properties.Resources.Hourglass, targetpos.Location);
}
else
{
// Draw loading bitmap
RectangleF targetpos = General.MakeZoomedRect(Properties.Resources.Hourglass.Size, targetview);
target.DrawImage(Properties.Resources.Hourglass, targetpos.Location);
}
}
}
// This draws a preview
public virtual void DrawPreview(Graphics target, Point targetpos)
{
lock(this)
{
// Preview ready?
if(previewstate == ImageLoadState.Ready)
{
// Draw preview
General.Map.Data.Previews.DrawPreview(previewindex, target, targetpos);
}
// Loading failed?
else if(loadfailed)
{
// Draw error bitmap
target.DrawImageUnscaled(Properties.Resources.Failed, targetpos);
}
else
{
// Draw loading bitmap
target.DrawImageUnscaled(Properties.Resources.Hourglass, targetpos);
}
}
}
// This returns a preview image
public virtual Image GetPreview()
{
lock(this)
{
// Preview ready?
if(previewstate == ImageLoadState.Ready)
{
// Make a bitmap and return it
Bitmap bmp = new Bitmap(PreviewManager.IMAGE_WIDTH, PreviewManager.IMAGE_HEIGHT);
Graphics g = Graphics.FromImage(bmp);
g.Clear(Color.Transparent);
General.Map.Data.Previews.DrawPreview(previewindex, g, new Point(0, 0));
g.Dispose();
return bmp;
}
// Loading failed?
else if(loadfailed)
{
// Return error bitmap
return Properties.Resources.Failed;
}
else
{
// Return loading bitmap
return Properties.Resources.Hourglass;
}
}
}
#endregion
}
}

View file

@ -33,7 +33,7 @@ using System.Windows.Forms;
namespace CodeImp.DoomBuilder.Data
{
internal enum ImageLoadState : int
public enum ImageLoadState : int
{
None,
Loading,

View file

@ -53,7 +53,6 @@ namespace CodeImp.DoomBuilder.Data
// Dont do anything
public override void LoadImage() { bitmap = CodeImp.DoomBuilder.Properties.Resources.UnknownImage; }
internal override void CreatePixelData() { }
internal override void CreateTexture() { }
#endregion

View file

@ -26,25 +26,26 @@ using System.Drawing.Imaging;
using CodeImp.DoomBuilder.Rendering;
using CodeImp.DoomBuilder.IO;
using System.IO;
using System.Drawing.Drawing2D;
#endregion
namespace CodeImp.DoomBuilder.Data
{
internal class PreviewManager : IDisposable
public class PreviewManager
{
#region ================== Constants
// Image format
private const PixelFormat IMAGE_FORMAT = PixelFormat.Format16bppArgb1555;
private const PixelFormat IMAGE_FORMAT = PixelFormat.Format32bppArgb;
// Dimensions of a single preview image
private const int IMAGE_WIDTH = 64;
private const int IMAGE_HEIGHT = 64;
internal const int IMAGE_WIDTH = 64;
internal const int IMAGE_HEIGHT = 64;
// How many previews on a single atlas?
private const int PREVIEWS_X = 8;
private const int PREVIEWS_Y = 8;
private const int PREVIEWS_X = 16;
private const int PREVIEWS_Y = 16;
#endregion
@ -56,6 +57,9 @@ namespace CodeImp.DoomBuilder.Data
// Next preview index
private int nextpreviewindex;
// Processing
private Queue<ImageData> imageque;
// Disposing
private bool isdisposed = false;
@ -63,18 +67,32 @@ namespace CodeImp.DoomBuilder.Data
#region ================== Properties
// Constants
public int ImageWidth { get { return IMAGE_WIDTH; } }
public int ImageHeight { get { return IMAGE_HEIGHT; } }
// Disposing
public bool IsDisposed { get { return isdisposed; } }
internal bool IsDisposed { get { return isdisposed; } }
// Loading
internal bool IsLoading
{
get
{
return (imageque.Count > 0);
}
}
#endregion
#region ================== Constructor / Disposer
// Constructor
public PreviewManager()
internal PreviewManager()
{
// Initialize
atlases = new List<Bitmap>();
imageque = new Queue<ImageData>();
nextpreviewindex = 0;
// We have no destructor
@ -82,7 +100,7 @@ namespace CodeImp.DoomBuilder.Data
}
// Disposer
public void Dispose()
internal void Dispose()
{
// Not already disposed?
if(!isdisposed)
@ -98,7 +116,7 @@ namespace CodeImp.DoomBuilder.Data
#endregion
#region ================== Calculations
#region ================== Private Methods
// Returns atlas index for the given preview index
private int GetAtlasIndex(int previewindex)
@ -120,24 +138,109 @@ namespace CodeImp.DoomBuilder.Data
return localindex / PREVIEWS_X;
}
#endregion
#region ================== Loading
// This makes a new atlas
private void MakeNewAtlas()
{
Bitmap b = new Bitmap(IMAGE_WIDTH * PREVIEWS_X, IMAGE_HEIGHT * PREVIEWS_Y, IMAGE_FORMAT);
atlases.Add(b);
lock(atlases)
{
Bitmap b = new Bitmap(IMAGE_WIDTH * PREVIEWS_X, IMAGE_HEIGHT * PREVIEWS_Y, IMAGE_FORMAT);
Graphics g = Graphics.FromImage(b);
g.Clear(Color.Transparent);
g.Dispose();
atlases.Add(b);
}
}
// This makes a preview for the given image and updates the image settings
private void MakeImagePreview(Image img)
private void MakeImagePreview(ImageData img)
{
// Do we have to make a new atlas?
if(GetAtlasIndex(nextpreviewindex) > (atlases.Count - 1)) MakeNewAtlas();
Bitmap atlas;
// Numbers
int atlasindex = GetAtlasIndex(nextpreviewindex);
int localx = GetLocalXIndex(nextpreviewindex);
int localy = GetLocalYIndex(nextpreviewindex);
lock(atlases)
{
// Do we have to make a new atlas?
if(atlasindex > (atlases.Count - 1)) MakeNewAtlas();
// Get the atlas we need
atlas = atlases[atlasindex];
}
lock(img)
{
// Load image if needed
if(!img.IsImageLoaded) img.LoadImage();
lock(atlas)
{
// Draw image onto atlas
Graphics g = Graphics.FromImage(atlas);
g.PageUnit = GraphicsUnit.Pixel;
g.CompositingQuality = CompositingQuality.HighQuality;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.SmoothingMode = SmoothingMode.HighQuality;
g.PixelOffsetMode = PixelOffsetMode.None;
Rectangle atlasrect = new Rectangle(localx * IMAGE_WIDTH, localy * IMAGE_HEIGHT, IMAGE_WIDTH, IMAGE_HEIGHT);
RectangleF imgrect = General.MakeZoomedRect(new Size(img.Width, img.Height), atlasrect);
g.DrawImage(img.Bitmap, imgrect);
g.Dispose();
}
// Unload image if no longer needed
if(!img.IsReferenced) img.UnloadImage();
// Set numbers
img.PreviewIndex = nextpreviewindex;
img.PreviewState = ImageLoadState.Ready;
nextpreviewindex++;
}
}
#endregion
#region ================== Public Methods
// This draws a preview centered in a target
internal void DrawPreview(int previewindex, Graphics target, Point targetpos)
{
Bitmap atlas;
// Get the atlas we need
lock(atlases) { atlas = atlases[GetAtlasIndex(previewindex)]; }
// Draw from atlas to target
lock(atlas)
{
RectangleF trect = new RectangleF((float)targetpos.X, (float)targetpos.Y,
(float)IMAGE_WIDTH, (float)IMAGE_HEIGHT);
RectangleF srect = new RectangleF((float)GetLocalXIndex(previewindex) * IMAGE_WIDTH,
(float)GetLocalYIndex(previewindex) * IMAGE_HEIGHT,
(float)IMAGE_WIDTH, (float)IMAGE_HEIGHT);
target.DrawImage(atlas, trect, srect, GraphicsUnit.Pixel);
}
}
// This draws a preview centered in a target
internal void DrawPreviewCentered(int previewindex, Graphics target, Rectangle targetview)
{
Bitmap atlas;
// Get the atlas we need
lock(atlases) { atlas = atlases[GetAtlasIndex(previewindex)]; }
// Draw from atlas to target
lock(atlas)
{
RectangleF trect = General.MakeZoomedRect(new Size(64, 64), targetview);
RectangleF srect = new RectangleF((float)GetLocalXIndex(previewindex) * IMAGE_WIDTH,
(float)GetLocalYIndex(previewindex) * IMAGE_HEIGHT,
(float)IMAGE_WIDTH, (float)IMAGE_HEIGHT);
target.DrawImage(atlas, trect, srect, GraphicsUnit.Pixel);
}
}
// Background loading
@ -145,9 +248,54 @@ namespace CodeImp.DoomBuilder.Data
// thread will not wait too long before calling again
internal bool BackgroundLoad()
{
// Get next item
ImageData image = null;
lock(imageque)
{
// Fetch next image to process
if(imageque.Count > 0) image = imageque.Dequeue();
}
// Any image to process?
if(image != null)
{
// Make image preview?
if(!image.IsPreviewLoaded) MakeImagePreview(image);
}
return (image != null);
}
// This adds an image for preview creation
internal void AddImage(ImageData image)
{
lock(imageque)
{
// Add to list
image.PreviewState = ImageLoadState.Loading;
imageque.Enqueue(image);
}
}
#if DEBUG
internal void DumpAtlases()
{
lock(atlases)
{
int index = 0;
foreach(Bitmap a in atlases)
{
lock(a)
{
string file = Path.Combine(General.AppPath, "atlas" + index++ + ".png");
a.Save(file, ImageFormat.Png);
}
}
}
}
#endif
#endregion
}
}

View file

@ -75,7 +75,7 @@ namespace CodeImp.DoomBuilder.Data
byte[] membytes;
// Checks
if(this.IsLoaded) return;
if(this.IsImageLoaded) return;
lock(this)
{
@ -102,6 +102,9 @@ namespace CodeImp.DoomBuilder.Data
mem.Seek(0, SeekOrigin.Begin);
bitmap = reader.ReadAsBitmap(mem);
if(bitmap == null) return;
// Done
mem.Dispose();
}
// Pass on to base

View file

@ -58,7 +58,7 @@ namespace CodeImp.DoomBuilder.Data
byte[] membytes;
// Leave when already loaded
if(this.IsLoaded) return;
if(this.IsImageLoaded) return;
lock(this)
{
@ -87,6 +87,9 @@ namespace CodeImp.DoomBuilder.Data
bitmap = reader.ReadAsBitmap(mem);
if(bitmap == null) return;
// Done
mem.Dispose();
// Get width and height from image
width = bitmap.Size.Width;
height = bitmap.Size.Height;

View file

@ -81,10 +81,9 @@ namespace CodeImp.DoomBuilder.Data
PixelColor* pixels;
Stream patchdata;
byte[] membytes;
bool failed = false;
// Checks
if(this.IsLoaded) return;
if(this.IsImageLoaded) return;
if((width == 0) || (height == 0)) return;
lock(this)
@ -125,14 +124,23 @@ namespace CodeImp.DoomBuilder.Data
{
// 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;
loadfailed = true;
}
else
{
// Draw the patch
mem.Seek(0, SeekOrigin.Begin);
reader.DrawToPixelData(mem, pixels, width, height, p.x, p.y);
try { reader.DrawToPixelData(mem, pixels, width, height, p.x, p.y); }
catch(InvalidDataException)
{
// Data cannot be read!
General.WriteLogLine("WARNING: Patch lump '" + p.lumpname + "' data format could not be read, while loading texture '" + this.Name + "'!");
loadfailed = true;
}
}
// Done
mem.Dispose();
}
else
{
@ -144,11 +152,11 @@ namespace CodeImp.DoomBuilder.Data
// Done
bitmap.UnlockBits(bitmapdata);
// When failed, use the error picture
if(failed)
// Dispose bitmap if load failed
if(loadfailed && (bitmap != null))
{
bitmap.Dispose();
bitmap = UnknownImageReader.ReadAsBitmap();
bitmap = null;
}
// Pass on to base

View file

@ -38,6 +38,7 @@ using System.Drawing;
using CodeImp.DoomBuilder.Plugins;
using CodeImp.DoomBuilder.Types;
using System.Collections.ObjectModel;
using System.Threading;
#endregion
@ -66,26 +67,6 @@ namespace CodeImp.DoomBuilder
#region ================== Constants
// Memory APIs
internal const uint MEM_COMMIT = 0x1000;
internal const uint MEM_RESERVE = 0x2000;
internal const uint MEM_DECOMMIT = 0x4000;
internal const uint MEM_RELEASE = 0x8000;
internal const uint MEM_RESET = 0x80000;
internal const uint MEM_TOP_DOWN = 0x100000;
internal const uint MEM_PHYSICAL = 0x400000;
internal const uint PAGE_NOACCESS = 0x01;
internal const uint PAGE_READONLY = 0x02;
internal const uint PAGE_READWRITE = 0x04;
internal const uint PAGE_WRITECOPY = 0x08;
internal const uint PAGE_EXECUTE = 0x10;
internal const uint PAGE_EXECUTE_READ = 0x20;
internal const uint PAGE_EXECUTE_READWRITE = 0x40;
internal const uint PAGE_EXECUTE_WRITECOPY = 0x80;
internal const uint PAGE_GUARD = 0x100;
internal const uint PAGE_NOCACHE = 0x200;
internal const uint PAGE_WRITECOMBINE = 0x400;
// SendMessage API
internal const int CB_SETITEMHEIGHT = 0x153;
@ -461,6 +442,9 @@ namespace CodeImp.DoomBuilder
// Hook to DLL loading failure event
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
// Set current thread name
Thread.CurrentThread.Name = "Main Application";
// Get a reference to this assembly
thisasm = Assembly.GetExecutingAssembly();
thisversion = thisasm.GetName().Version;

View file

@ -330,6 +330,9 @@ namespace CodeImp.DoomBuilder
maplocation = new DataLocation(DataLocation.RESOURCE_WAD, filepathname, false, false);
data.Load(configinfo.Resources, options.Resources, maplocation);
// Update the used textures
General.Map.Data.UpdateUsedTextures();
// Bind any methods
General.Actions.BindMethods(this);
@ -1004,6 +1007,7 @@ namespace CodeImp.DoomBuilder
config = null;
configinfo = null;
GC.Collect();
GC.WaitForPendingFinalizers();
// Reload game configuration
General.WriteLogLine("Reloading game configuration...");
@ -1017,6 +1021,9 @@ namespace CodeImp.DoomBuilder
maplocation = new DataLocation(DataLocation.RESOURCE_WAD, filepathname, false, false);
data.Load(configinfo.Resources, options.Resources, maplocation);
// Update the used textures
General.Map.Data.UpdateUsedTextures();
// Apply new settings to map elements
map.UpdateConfiguration();

View file

@ -75,33 +75,40 @@ namespace CodeImp.DoomBuilder.IO
// Get bitmap
bmp = ReadAsBitmap(stream);
width = bmp.Size.Width;
height = bmp.Size.Height;
// Lock bitmap pixels
bmpdata = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
pixels = (PixelColor*)bmpdata.Scan0.ToPointer();
// Go for all pixels in the original image
for(ox = 0; ox < width; ox++)
if(bmp != null)
{
for(oy = 0; oy < height; oy++)
width = bmp.Size.Width;
height = bmp.Size.Height;
// Lock bitmap pixels
bmpdata = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
pixels = (PixelColor*)bmpdata.Scan0.ToPointer();
// Go for all pixels in the original image
for(ox = 0; ox < width; ox++)
{
// Copy this pixel?
if(pixels[oy * width + ox].a > 0.5f)
for(oy = 0; oy < height; oy++)
{
// Calculate target pixel and copy when within bounds
tx = x + ox;
ty = y + oy;
if((tx >= 0) && (tx < targetwidth) && (ty >= 0) && (ty < targetheight))
target[ty * targetwidth + tx] = pixels[oy * width + ox];
// Copy this pixel?
if(pixels[oy * width + ox].a > 0.5f)
{
// Calculate target pixel and copy when within bounds
tx = x + ox;
ty = y + oy;
if((tx >= 0) && (tx < targetwidth) && (ty >= 0) && (ty < targetheight))
target[ty * targetwidth + tx] = pixels[oy * width + ox];
}
}
}
}
// Done
bmp.UnlockBits(bmpdata);
bmp.Dispose();
// Done
bmp.UnlockBits(bmpdata);
bmp.Dispose();
}
else
{
throw new InvalidDataException();
}
}
#endregion

View file

@ -51,13 +51,13 @@ namespace CodeImp.DoomBuilder.IO
// This reads the image and returns a Bitmap
public Bitmap ReadAsBitmap(Stream stream)
{
return new Bitmap(CodeImp.DoomBuilder.Properties.Resources.UnknownImage);
return new Bitmap(CodeImp.DoomBuilder.Properties.Resources.Failed);
}
// This reads the image and returns a Bitmap
public static Bitmap ReadAsBitmap()
{
return new Bitmap(CodeImp.DoomBuilder.Properties.Resources.UnknownImage);
return new Bitmap(CodeImp.DoomBuilder.Properties.Resources.Failed);
}
// This draws the picture to the given pixel color data

View file

@ -81,6 +81,13 @@ namespace CodeImp.DoomBuilder.Properties {
}
}
internal static System.Drawing.Bitmap Failed {
get {
object obj = ResourceManager.GetObject("Failed", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
internal static System.Drawing.Bitmap File {
get {
object obj = ResourceManager.GetObject("File", resourceCulture);

View file

@ -220,4 +220,7 @@
<data name="Monster2" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\Monster2.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="Failed" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\Failed.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
</root>

View file

@ -178,7 +178,7 @@ namespace CodeImp.DoomBuilder.Rendering
CreateAssistColors();
// Create color correction table
General.Colors.CreateCorrectionTable();
CreateCorrectionTable();
// We have no destructor
GC.SuppressFinalize(this);

View file

@ -32,22 +32,11 @@ namespace CodeImp.DoomBuilder.Rendering
{
public unsafe class PixelColorBlock
{
#region ================== API Declarations
[DllImport("kernel32.dll", SetLastError = true)]
private static unsafe extern void* VirtualAlloc(IntPtr lpAddress, UIntPtr dwSize, uint flAllocationType, uint flProtect);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static unsafe extern bool VirtualFree(void* lpAddress, UIntPtr dwSize, uint dwFreeType);
#endregion
#region ================== Variables
private int width;
private int height;
private uint memorysize;
private int memorysize;
private PixelColor* memory;
#endregion
@ -56,7 +45,7 @@ namespace CodeImp.DoomBuilder.Rendering
public int Width { get { return width; } }
public int Height { get { return height; } }
public uint Length { get { return memorysize; } }
public int Length { get { return memorysize; } }
public PixelColor this[int index] { get { return memory[index]; } set { memory[index] = value; } }
public PixelColor* Pointer { get { return memory; } }
@ -73,8 +62,8 @@ namespace CodeImp.DoomBuilder.Rendering
// Initialize
this.width = width;
this.height = height;
this.memorysize = (uint)width * (uint)height * (uint)sizeof(PixelColor);
this.memory = (PixelColor*)VirtualAlloc(IntPtr.Zero, new UIntPtr(memorysize), General.MEM_COMMIT, General.PAGE_READWRITE);
this.memorysize = width * height * sizeof(PixelColor);
this.memory = (PixelColor*)Marshal.AllocCoTaskMem(memorysize);
if(this.memory == (PixelColor*)0) throw new OutOfMemoryException();
GC.AddMemoryPressure(memorysize);
}
@ -83,7 +72,7 @@ namespace CodeImp.DoomBuilder.Rendering
~PixelColorBlock()
{
// Terminate
VirtualFree((void*)memory, new UIntPtr(memorysize), General.MEM_RELEASE);
Marshal.FreeCoTaskMem(new IntPtr(memory));
GC.RemoveMemoryPressure(memorysize);
memorysize = 0;
}

View file

@ -1080,7 +1080,7 @@ namespace CodeImp.DoomBuilder.Rendering
if(texture != null)
{
// Make sure the texture is loaded
if(!texture.IsLoaded) texture.LoadImage();
if(!texture.IsImageLoaded) texture.LoadImage();
if(texture.Texture == null) texture.CreateTexture();
t = texture.Texture;
}

View file

@ -136,9 +136,6 @@ namespace CodeImp.DoomBuilder.Rendering
// Make the billboard matrix
billboard = Matrix.RotationYawPitchRoll(0f, anglexy, anglez - Angle2D.PIHALF);
// Apply matrices
ApplyMatrices();
}
// This applies the matrices
@ -169,6 +166,9 @@ namespace CodeImp.DoomBuilder.Rendering
graphics.Device.SetRenderState(RenderState.DestinationBlend, Blend.InverseSourceAlpha);
graphics.Device.SetRenderState(RenderState.TextureFactor, -1);
// Matrices
ApplyMatrices();
// Ready
return true;
}
@ -233,23 +233,28 @@ namespace CodeImp.DoomBuilder.Rendering
// Go for all geometry in this sector
foreach(VisualGeometry g in s.GeometryList)
{
ImageData curtexture;
// What texture to use?
if((g.Texture != null) && g.Texture.IsImageLoaded && !g.Texture.IsDisposed)
curtexture = g.Texture;
else
curtexture = General.Map.Data.Hourglass3D;
// Change texture?
if(g.Texture != lasttexture)
if(curtexture != lasttexture)
{
// Now using this texture
lasttexture = g.Texture;
if(lasttexture != null)
{
// Load image and make texture
if(!lasttexture.IsLoaded) lasttexture.LoadImage();
if((lasttexture.Texture == null) || lasttexture.Texture.Disposed)
lasttexture.CreateTexture();
lasttexture = curtexture;
// Apply texture
graphics.Device.SetTexture(0, lasttexture.Texture);
graphics.Shaders.World3D.Texture1 = lasttexture.Texture;
graphics.Shaders.World3D.ApplySettings();
}
// Create Direct3D texture if still needed
if((curtexture.Texture == null) || curtexture.Texture.Disposed)
curtexture.CreateTexture();
// Apply texture
graphics.Device.SetTexture(0, curtexture.Texture);
graphics.Shaders.World3D.Texture1 = curtexture.Texture;
graphics.Shaders.World3D.ApplySettings();
}
// Render it!

View file

@ -139,7 +139,7 @@ namespace CodeImp.DoomBuilder.Rendering
geolist.Sort();
// Count the number of vertices there are
foreach(VisualGeometry g in geolist) numverts += g.Vertices.Length;
foreach(VisualGeometry g in geolist) if(g.Vertices != null) numverts += g.Vertices.Length;
// Any vertics?
if(numverts > 0)
@ -152,7 +152,7 @@ namespace CodeImp.DoomBuilder.Rendering
bufferstream = geobuffer.Lock(0, WorldVertex.Stride * numverts, LockFlags.Discard);
foreach(VisualGeometry g in geolist)
{
if(g.Vertices.Length > 0)
if((g.Vertices != null) && (g.Vertices.Length > 0))
{
bufferstream.WriteRange<WorldVertex>(g.Vertices);
g.VertexOffset = v;

BIN
Source/Resources/Failed.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 406 B

View file

@ -47,7 +47,7 @@ namespace CodeImp.DoomBuilder.Windows
// Constructor
public FlatBrowserForm()
{
Dictionary<long, long> useditems = new Dictionary<long,long>();
Cursor.Current = Cursors.WaitCursor;
// Initialize
InitializeComponent();
@ -57,43 +57,15 @@ namespace CodeImp.DoomBuilder.Windows
ListViewGroup used = browser.AddGroup("Used Flats");
ListViewGroup avail = browser.AddGroup("Available Flats");
// Go through the map to find the used flats
foreach(Sector s in General.Map.Map.Sectors)
{
// Add floor flat
if(!useditems.ContainsKey(s.LongFloorTexture)) useditems.Add(s.LongFloorTexture, 0);
// Add ceiling flat
if(!useditems.ContainsKey(s.LongCeilTexture)) useditems.Add(s.LongCeilTexture, 0);
}
// When mixing textures with flats, include textures as well
if(General.Map.Config.MixTexturesFlats)
{
// Go through the map to find the used textures
foreach(Sidedef sd in General.Map.Map.Sidedefs)
{
// Add high texture
if(sd.HighTexture.Length > 0)
if(!useditems.ContainsKey(sd.LongHighTexture)) useditems.Add(sd.LongHighTexture, 0);
// Add mid texture
if(sd.LowTexture.Length > 0)
if(!useditems.ContainsKey(sd.LongMiddleTexture)) useditems.Add(sd.LongMiddleTexture, 0);
// Add low texture
if(sd.MiddleTexture.Length > 0)
if(!useditems.ContainsKey(sd.LongLowTexture)) useditems.Add(sd.LongLowTexture, 0);
}
}
// Update the used textures
General.Map.Data.UpdateUsedTextures();
// Start adding
browser.BeginAdding();
// Add all used flats
foreach(ImageData img in General.Map.Data.Flats)
if(useditems.ContainsKey(img.LongName))
browser.Add(img.Name, img, img, used);
if(img.UsedInMap) browser.Add(img.Name, img, img, used);
// Add all available flats
foreach(ImageData img in General.Map.Data.Flats)
@ -136,6 +108,7 @@ namespace CodeImp.DoomBuilder.Windows
{
// Focus the textbox
browser.FocusTextbox();
Cursor.Current = Cursors.Default;
}
// Loading

View file

@ -93,7 +93,7 @@ namespace CodeImp.DoomBuilder.Windows
// Set this texture as background
backgroundname = result;
backgroundsource = GridSetup.SOURCE_TEXTURES;
General.DisplayZoomedImage(backgroundimage, General.Map.Data.GetTextureBitmap(result));
General.DisplayZoomedImage(backgroundimage, General.Map.Data.GetTextureImage(result).GetPreview());
}
}
@ -109,7 +109,7 @@ namespace CodeImp.DoomBuilder.Windows
// Set this flat as background
backgroundname = result;
backgroundsource = GridSetup.SOURCE_FLATS;
General.DisplayZoomedImage(backgroundimage, General.Map.Data.GetFlatBitmap(result));
General.DisplayZoomedImage(backgroundimage, General.Map.Data.GetFlatImage(result).GetPreview());
}
}

View file

@ -399,6 +399,9 @@ namespace CodeImp.DoomBuilder.Windows
fieldslist.Apply(l.Fields);
}
// Update the used textures
General.Map.Data.UpdateUsedTextures();
// Done
General.Map.IsChanged = true;
this.DialogResult = DialogResult.OK;

View file

@ -151,6 +151,9 @@ namespace CodeImp.DoomBuilder.Windows
fieldslist.Apply(s.Fields);
}
// Update the used textures
General.Map.Data.UpdateUsedTextures();
// Done
General.Map.IsChanged = true;
this.DialogResult = DialogResult.OK;

View file

@ -47,7 +47,7 @@ namespace CodeImp.DoomBuilder.Windows
// Constructor
public TextureBrowserForm()
{
Dictionary<long, long> useditems = new Dictionary<long,long>();
Cursor.Current = Cursors.WaitCursor;
// Initialize
InitializeComponent();
@ -57,35 +57,8 @@ namespace CodeImp.DoomBuilder.Windows
ListViewGroup used = browser.AddGroup("Used Textures");
ListViewGroup avail = browser.AddGroup("Available Textures");
// Go through the map to find the used textures
foreach(Sidedef sd in General.Map.Map.Sidedefs)
{
// Add high texture
if(sd.HighTexture.Length > 0)
if(!useditems.ContainsKey(sd.LongHighTexture)) useditems.Add(sd.LongHighTexture, 0);
// Add mid texture
if(sd.LowTexture.Length > 0)
if(!useditems.ContainsKey(sd.LongMiddleTexture)) useditems.Add(sd.LongMiddleTexture, 0);
// Add low texture
if(sd.MiddleTexture.Length > 0)
if(!useditems.ContainsKey(sd.LongLowTexture)) useditems.Add(sd.LongLowTexture, 0);
}
// When mixing textures with flats, include flats as well
if(General.Map.Config.MixTexturesFlats)
{
// Go through the map to find the used flats
foreach(Sector s in General.Map.Map.Sectors)
{
// Add floor flat
if(!useditems.ContainsKey(s.LongFloorTexture)) useditems.Add(s.LongFloorTexture, 0);
// Add ceil flat
if(!useditems.ContainsKey(s.LongCeilTexture)) useditems.Add(s.LongCeilTexture, 0);
}
}
// Update the used textures
General.Map.Data.UpdateUsedTextures();
// Start adding
browser.BeginAdding();
@ -94,17 +67,12 @@ namespace CodeImp.DoomBuilder.Windows
foreach(ImageData img in General.Map.Data.Textures)
{
browser.Add(img.Name, img, img, avail);
img.Temporary = true;
}
// Add all used textures and mark the images for permanent loading
foreach(ImageData img in General.Map.Data.Textures)
{
if(useditems.ContainsKey(img.LongName))
{
browser.Add(img.Name, img, img, used);
img.Temporary = false;
}
if(img.UsedInMap) browser.Add(img.Name, img, img, used);
}
// Done adding
@ -144,6 +112,7 @@ namespace CodeImp.DoomBuilder.Windows
{
// Focus the textbox
browser.FocusTextbox();
Cursor.Current = Cursors.Default;
}
// Loading

View file

@ -310,7 +310,7 @@ namespace CodeImp.DoomBuilder.Windows
}
// Show image
General.DisplayZoomedImage(spritetex, General.Map.Data.GetSpriteBitmap(ti.Sprite));
General.DisplayZoomedImage(spritetex, General.Map.Data.GetSpriteImage(ti.Sprite).GetPreview());
}
}