2009-04-19 18:07:22 +00:00
#region = = = = = = = = = = = = = = = = = = Copyright ( c ) 2007 Pascal vd Heiden
/ *
* Copyright ( c ) 2007 Pascal vd Heiden , www . codeimp . com
* This program is released under GNU General Public License
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* /
#endregion
#region = = = = = = = = = = = = = = = = = = Namespaces
using System ;
using System.Collections.Generic ;
using System.IO ;
2014-03-03 13:40:29 +00:00
using System.Windows.Forms ;
2009-04-19 18:07:22 +00:00
using CodeImp.DoomBuilder.IO ;
using CodeImp.DoomBuilder.Config ;
using System.Threading ;
using CodeImp.DoomBuilder.Map ;
using CodeImp.DoomBuilder.Windows ;
using CodeImp.DoomBuilder.ZDoom ;
2012-05-21 23:51:32 +00:00
using CodeImp.DoomBuilder.GZBuilder.Data ;
using CodeImp.DoomBuilder.GZBuilder.GZDoom ;
using CodeImp.DoomBuilder.GZBuilder.MD3 ;
2009-04-19 18:07:22 +00:00
#endregion
namespace CodeImp.DoomBuilder.Data
{
public sealed class DataManager
{
#region = = = = = = = = = = = = = = = = = = Constants
public const string INTERNAL_PREFIX = "internal:" ;
2014-11-25 11:52:01 +00:00
public const int CLASIC_IMAGE_NAME_LENGTH = 8 ; //mxd
2009-04-19 18:07:22 +00:00
#endregion
#region = = = = = = = = = = = = = = = = = = Variables
// Data containers
private List < DataReader > containers ;
private DataReader currentreader ;
// Palette
private Playpal palette ;
// Textures, Flats and Sprites
private Dictionary < long , ImageData > textures ;
2014-11-25 11:52:01 +00:00
private Dictionary < long , long > texturenamesshorttofull ; //mxd
2009-04-19 18:07:22 +00:00
private List < string > texturenames ;
private Dictionary < long , ImageData > flats ;
2014-11-25 11:52:01 +00:00
private Dictionary < long , long > flatnamesshorttofull ; //mxd
2009-04-19 18:07:22 +00:00
private List < string > flatnames ;
private Dictionary < long , ImageData > sprites ;
private List < MatchingTextureSet > texturesets ;
private List < ResourceTextureSet > resourcetextures ;
private AllTextureSet alltextures ;
2012-04-17 19:13:47 +00:00
2013-09-11 09:47:53 +00:00
//mxd
2015-04-14 11:33:57 +00:00
private Dictionary < int , ModelData > modeldefentries ; //Thing.Type, Model entry
private readonly Dictionary < int , DynamicLightData > gldefsentries ; //Thing.Type, Light entry
private MapInfo mapinfo ;
2015-01-25 23:22:42 +00:00
private Dictionary < string , KeyValuePair < int , int > > reverbs ; //<name, <arg1, arg2>
2015-04-14 11:33:57 +00:00
private Dictionary < long , GlowingFlatData > glowingflats ; // Texture name hash, Glowing Flat Data
2015-05-28 13:45:01 +00:00
private List < string > soundsequences ;
2009-04-19 18:07:22 +00:00
// Background loading
private Queue < ImageData > imageque ;
private Thread backgroundloader ;
private volatile bool updatedusedtextures ;
private bool notifiedbusy ;
// Image previews
private PreviewManager previews ;
// Special images
private ImageData missingtexture3d ;
private ImageData unknowntexture3d ;
2014-01-13 08:06:56 +00:00
private UnknownImage unknownimage ; //mxd
2009-04-19 18:07:22 +00:00
private ImageData hourglass3d ;
private ImageData crosshair ;
private ImageData crosshairbusy ;
private Dictionary < string , ImageData > internalsprites ;
2009-06-04 20:21:31 +00:00
private ImageData whitetexture ;
2015-07-14 23:34:31 +00:00
//mxd. Comment icons
private ImageData [ ] commenttextures ;
2009-04-19 18:07:22 +00:00
// Used images
private Dictionary < long , long > usedimages ;
// Things combined with things created from Decorate
2009-08-15 08:41:43 +00:00
private DecorateParser decorate ;
2009-04-19 18:07:22 +00:00
private List < ThingCategory > thingcategories ;
private Dictionary < int , ThingTypeInfo > thingtypes ;
// Timing
2012-07-12 22:34:12 +00:00
private float loadstarttime ;
private float loadfinishtime ;
2009-04-19 18:07:22 +00:00
// Disposing
2014-02-21 14:42:12 +00:00
private bool isdisposed ;
2009-04-19 18:07:22 +00:00
#endregion
#region = = = = = = = = = = = = = = = = = = Properties
2013-09-11 09:47:53 +00:00
//mxd
2015-04-14 11:33:57 +00:00
internal Dictionary < int , ModelData > ModeldefEntries { get { return modeldefentries ; } }
internal Dictionary < int , DynamicLightData > GldefsEntries { get { return gldefsentries ; } }
public MapInfo MapInfo { get { return mapinfo ; } }
2015-01-25 23:22:42 +00:00
public Dictionary < string , KeyValuePair < int , int > > Reverbs { get { return reverbs ; } }
2015-04-14 11:33:57 +00:00
public Dictionary < long , GlowingFlatData > GlowingFlats { get { return glowingflats ; } }
2015-05-28 13:45:01 +00:00
public List < string > SoundSequences { get { return soundsequences ; } }
2012-04-17 19:13:47 +00:00
2009-04-19 18:07:22 +00:00
public Playpal Palette { get { return palette ; } }
public PreviewManager Previews { get { return previews ; } }
public ICollection < ImageData > Textures { get { return textures . Values ; } }
2013-12-03 10:50:33 +00:00
public ICollection < ImageData > Flats { get { return flats . Values ; } }
2009-04-19 18:07:22 +00:00
public List < string > TextureNames { get { return texturenames ; } }
2013-12-03 10:50:33 +00:00
public List < string > FlatNames { get { return flatnames ; } }
2009-04-19 18:07:22 +00:00
public bool IsDisposed { get { return isdisposed ; } }
public ImageData MissingTexture3D { get { return missingtexture3d ; } }
public ImageData UnknownTexture3D { get { return unknowntexture3d ; } }
public ImageData Hourglass3D { get { return hourglass3d ; } }
public ImageData Crosshair3D { get { return crosshair ; } }
public ImageData CrosshairBusy3D { get { return crosshairbusy ; } }
2009-06-04 20:21:31 +00:00
public ImageData WhiteTexture { get { return whitetexture ; } }
2015-07-14 23:34:31 +00:00
public ImageData [ ] CommentTextures { get { return commenttextures ; } } //mxd
2009-04-19 18:07:22 +00:00
public List < ThingCategory > ThingCategories { get { return thingcategories ; } }
public ICollection < ThingTypeInfo > ThingTypes { get { return thingtypes . Values ; } }
2009-08-15 08:41:43 +00:00
public DecorateParser Decorate { get { return decorate ; } }
2009-04-19 18:07:22 +00:00
internal ICollection < MatchingTextureSet > TextureSets { get { return texturesets ; } }
internal ICollection < ResourceTextureSet > ResourceTextureSets { get { return resourcetextures ; } }
internal AllTextureSet AllTextureSet { get { return alltextures ; } }
public bool IsLoading
{
get
{
if ( imageque ! = null )
return ( backgroundloader ! = null ) & & backgroundloader . IsAlive & & ( ( imageque . Count > 0 ) | | previews . IsLoading ) ;
2013-07-29 08:50:50 +00:00
return false ;
2009-04-19 18:07:22 +00:00
}
}
#endregion
#region = = = = = = = = = = = = = = = = = = Constructor / Disposer
// Constructor
internal DataManager ( )
{
// We have no destructor
GC . SuppressFinalize ( this ) ;
2013-07-29 08:50:50 +00:00
//mxd.
2015-04-14 11:33:57 +00:00
modeldefentries = new Dictionary < int , ModelData > ( ) ;
gldefsentries = new Dictionary < int , DynamicLightData > ( ) ;
2015-01-25 23:22:42 +00:00
reverbs = new Dictionary < string , KeyValuePair < int , int > > ( ) ;
2015-04-14 11:33:57 +00:00
glowingflats = new Dictionary < long , GlowingFlatData > ( ) ;
2015-05-28 13:45:01 +00:00
soundsequences = new List < string > ( ) ;
2013-07-29 08:50:50 +00:00
2009-04-19 18:07:22 +00:00
// Load special images
2009-08-02 18:21:53 +00:00
missingtexture3d = new ResourceImage ( "CodeImp.DoomBuilder.Resources.MissingTexture3D.png" ) ;
2009-04-19 18:07:22 +00:00
missingtexture3d . LoadImage ( ) ;
2009-08-02 18:21:53 +00:00
unknowntexture3d = new ResourceImage ( "CodeImp.DoomBuilder.Resources.UnknownTexture3D.png" ) ;
2009-04-19 18:07:22 +00:00
unknowntexture3d . LoadImage ( ) ;
2009-08-02 18:21:53 +00:00
hourglass3d = new ResourceImage ( "CodeImp.DoomBuilder.Resources.Hourglass3D.png" ) ;
2009-04-19 18:07:22 +00:00
hourglass3d . LoadImage ( ) ;
2009-08-02 18:21:53 +00:00
crosshair = new ResourceImage ( "CodeImp.DoomBuilder.Resources.Crosshair.png" ) ;
2009-04-19 18:07:22 +00:00
crosshair . LoadImage ( ) ;
2009-08-02 18:21:53 +00:00
crosshairbusy = new ResourceImage ( "CodeImp.DoomBuilder.Resources.CrosshairBusy.png" ) ;
2009-04-19 18:07:22 +00:00
crosshairbusy . LoadImage ( ) ;
2009-08-02 18:21:53 +00:00
whitetexture = new ResourceImage ( "CodeImp.DoomBuilder.Resources.White.png" ) ;
2009-06-04 20:21:31 +00:00
whitetexture . UseColorCorrection = false ;
whitetexture . LoadImage ( ) ;
whitetexture . CreateTexture ( ) ;
2014-01-13 08:06:56 +00:00
unknownimage = new UnknownImage ( Properties . Resources . UnknownImage ) ; //mxd. There should be only one!
2015-07-14 23:34:31 +00:00
//mxd. Create comment icons
commenttextures = new ImageData [ ]
{
new ResourceImage ( "CodeImp.DoomBuilder.Resources.CommentRegular.png" ) ,
new ResourceImage ( "CodeImp.DoomBuilder.Resources.CommentInfo.png" ) ,
new ResourceImage ( "CodeImp.DoomBuilder.Resources.CommentQuestion.png" ) ,
new ResourceImage ( "CodeImp.DoomBuilder.Resources.CommentProblem.png" ) ,
new ResourceImage ( "CodeImp.DoomBuilder.Resources.CommentSmile.png" ) ,
} ;
//mxd. Load comment icons
foreach ( ImageData data in commenttextures )
{
data . LoadImage ( ) ;
data . CreateTexture ( ) ;
}
2009-04-19 18:07:22 +00:00
}
2009-06-04 20:21:31 +00:00
2009-04-19 18:07:22 +00:00
// Disposer
internal void Dispose ( )
{
// Not already disposed?
if ( ! isdisposed )
{
// Clean up
Unload ( ) ;
missingtexture3d . Dispose ( ) ;
missingtexture3d = null ;
unknowntexture3d . Dispose ( ) ;
unknowntexture3d = null ;
hourglass3d . Dispose ( ) ;
hourglass3d = null ;
crosshair . Dispose ( ) ;
crosshair = null ;
crosshairbusy . Dispose ( ) ;
crosshairbusy = null ;
2009-06-04 20:21:31 +00:00
whitetexture . Dispose ( ) ;
whitetexture = null ;
2014-01-13 08:06:56 +00:00
unknownimage . Dispose ( ) ; //mxd
unknownimage = null ; //mxd
2015-07-14 23:34:31 +00:00
foreach ( ImageData data in commenttextures ) data . Dispose ( ) ; //mxd
2015-04-14 11:33:57 +00:00
modeldefentries = null ; //mxd
mapinfo = null ;
2009-04-19 18:07:22 +00:00
// Done
isdisposed = true ;
}
}
#endregion
#region = = = = = = = = = = = = = = = = = = Loading / Unloading
// This loads all data resources
internal void Load ( DataLocationList configlist , DataLocationList maplist , DataLocation maplocation )
{
DataLocationList all = DataLocationList . Combined ( configlist , maplist ) ;
all . Add ( maplocation ) ;
Load ( all ) ;
}
// This loads all data resources
internal void Load ( DataLocationList configlist , DataLocationList maplist )
{
DataLocationList all = DataLocationList . Combined ( configlist , maplist ) ;
Load ( all ) ;
}
// This loads all data resources
internal void Load ( DataLocationList locations )
{
2009-05-12 09:50:08 +00:00
int texcount , flatcount , spritecount , thingcount , colormapcount ;
2009-04-19 18:07:22 +00:00
Dictionary < long , ImageData > texturesonly = new Dictionary < long , ImageData > ( ) ;
2009-05-12 09:50:08 +00:00
Dictionary < long , ImageData > colormapsonly = new Dictionary < long , ImageData > ( ) ;
2009-04-19 18:07:22 +00:00
Dictionary < long , ImageData > flatsonly = new Dictionary < long , ImageData > ( ) ;
DataReader c ;
// Create collections
containers = new List < DataReader > ( ) ;
textures = new Dictionary < long , ImageData > ( ) ;
flats = new Dictionary < long , ImageData > ( ) ;
sprites = new Dictionary < long , ImageData > ( ) ;
texturenames = new List < string > ( ) ;
flatnames = new List < string > ( ) ;
2014-11-25 11:52:01 +00:00
texturenamesshorttofull = new Dictionary < long , long > ( ) ; //mxd
flatnamesshorttofull = new Dictionary < long , long > ( ) ; //mxd
2009-04-19 18:07:22 +00:00
imageque = new Queue < ImageData > ( ) ;
previews = new PreviewManager ( ) ;
texturesets = new List < MatchingTextureSet > ( ) ;
usedimages = new Dictionary < long , long > ( ) ;
2014-02-26 14:11:06 +00:00
internalsprites = new Dictionary < string , ImageData > ( StringComparer . Ordinal ) ;
2009-04-19 18:07:22 +00:00
thingcategories = General . Map . Config . GetThingCategories ( ) ;
thingtypes = General . Map . Config . GetThingTypes ( ) ;
// Load texture sets
foreach ( DefinedTextureSet ts in General . Map . ConfigSettings . TextureSets )
texturesets . Add ( new MatchingTextureSet ( ts ) ) ;
// Sort the texture sets
texturesets . Sort ( ) ;
// Special textures sets
alltextures = new AllTextureSet ( ) ;
resourcetextures = new List < ResourceTextureSet > ( ) ;
// Go for all locations
foreach ( DataLocation dl in locations )
{
// Nothing chosen yet
c = null ;
// TODO: Make this work more elegant using reflection.
// Make DataLocation.type of type Type and assign the
// types of the desired reader classes.
try
{
// Choose container type
switch ( dl . type )
{
// WAD file container
case DataLocation . RESOURCE_WAD :
c = new WADReader ( dl ) ;
break ;
// Directory container
case DataLocation . RESOURCE_DIRECTORY :
c = new DirectoryReader ( dl ) ;
break ;
// PK3 file container
case DataLocation . RESOURCE_PK3 :
c = new PK3Reader ( dl ) ;
break ;
}
}
catch ( Exception e )
{
// Unable to load resource
2010-10-03 16:54:38 +00:00
General . ErrorLogger . Add ( ErrorType . Error , "Unable to load resources from location \"" + dl . location + "\". Please make sure the location is accessible and not in use by another program. The resources will now be loaded with this location excluded. You may reload the resources to try again.\n" + e . GetType ( ) . Name + " when creating data reader: " + e . Message ) ;
2009-04-19 18:07:22 +00:00
General . WriteLogLine ( e . StackTrace ) ;
continue ;
}
// Add container
if ( c ! = null )
{
containers . Add ( c ) ;
resourcetextures . Add ( c . TextureSet ) ;
}
}
// Load stuff
LoadPalette ( ) ;
2014-12-03 09:06:05 +00:00
texcount = LoadTextures ( texturesonly , texturenamesshorttofull ) ;
flatcount = LoadFlats ( flatsonly , flatnamesshorttofull ) ;
2009-05-12 09:50:08 +00:00
colormapcount = LoadColormaps ( colormapsonly ) ;
2010-08-18 09:07:54 +00:00
LoadSprites ( ) ;
2015-04-14 11:33:57 +00:00
//mxd. Load MAPINFO. Should happen before parisng DECORATE
Dictionary < int , string > spawnnums ;
Dictionary < int , string > doomednums ;
LoadMapInfo ( out spawnnums , out doomednums ) ;
thingcount = LoadDecorateThings ( spawnnums , doomednums ) ;
2010-08-18 09:07:54 +00:00
spritecount = LoadThingSprites ( ) ;
2009-04-19 18:07:22 +00:00
LoadInternalSprites ( ) ;
2012-05-21 23:51:32 +00:00
2015-01-25 23:22:42 +00:00
//mxd. Load more stuff
LoadReverbs ( ) ;
2015-05-28 13:45:01 +00:00
LoadSndSeq ( ) ;
2014-12-03 23:15:26 +00:00
LoadVoxels ( ) ;
2015-04-14 11:33:57 +00:00
Dictionary < string , List < int > > actorsbyclass = CreateActorsByClassList ( ) ;
LoadModeldefs ( actorsbyclass ) ;
Model rendering (all modes): UDMF scale, pitch and roll are now displayed.
Thing Edit Form, UDMF: added controls for setting pitch, roll, scale, render style, fill color, alpha, health and score.
Visual mode, UDMF: UDMF scale is now applied when rendering sprites.
Added Thing Statistics form (Edit -> View Thing Types...), which shows all loaded thing types with some additional info.
Visual mode: sprites with negative ScaleX and positive ScaleY were not rendered properly.
Classic modes: display was not updated after loading a sprite.
Current testing engine change was not saved on closing the program when no other game configuration settings were changed.
2014-04-30 10:01:22 +00:00
foreach ( Thing t in General . Map . Map . Things ) t . UpdateCache ( ) ;
2013-09-11 09:47:53 +00:00
General . MainWindow . DisplayReady ( ) ;
2009-05-12 09:50:08 +00:00
// Process colormaps (we just put them in as textures)
foreach ( KeyValuePair < long , ImageData > t in colormapsonly )
{
textures . Add ( t . Key , t . Value ) ;
texturenames . Add ( t . Value . Name ) ;
}
2009-04-19 18:07:22 +00:00
// Process textures
foreach ( KeyValuePair < long , ImageData > t in texturesonly )
{
2009-05-14 21:36:25 +00:00
if ( ! textures . ContainsKey ( t . Key ) )
{
textures . Add ( t . Key , t . Value ) ;
texturenames . Add ( t . Value . Name ) ;
}
2009-04-19 18:07:22 +00:00
}
2013-12-03 10:50:33 +00:00
// Process flats
foreach ( KeyValuePair < long , ImageData > f in flatsonly )
{
flats . Add ( f . Key , f . Value ) ;
flatnames . Add ( f . Value . Name ) ;
}
2009-04-19 18:07:22 +00:00
// Mixed textures and flats?
2014-12-03 09:06:05 +00:00
if ( General . Map . Config . MixTexturesFlats )
{
2013-12-03 10:50:33 +00:00
// Add textures to flats
foreach ( KeyValuePair < long , ImageData > t in texturesonly )
{
if ( ! flats . ContainsKey ( t . Key ) )
{
flats . Add ( t . Key , t . Value ) ;
flatnames . Add ( t . Value . Name ) ;
}
2014-07-07 14:48:29 +00:00
else if ( t . Value is HighResImage | | t . Value is SimpleTextureImage ) //mxd. Textures defined in TEXTURES or placed between TX_START and TX_END markers override "regular" flats in ZDoom
2014-07-07 08:42:46 +00:00
{
2014-12-03 09:06:05 +00:00
//TODO: check this!
2014-07-07 08:42:46 +00:00
flats [ t . Key ] = t . Value ;
}
2013-12-03 10:50:33 +00:00
}
2014-12-03 09:06:05 +00:00
//mxd
foreach ( KeyValuePair < long , long > t in texturenamesshorttofull )
{
if ( ! flatnamesshorttofull . ContainsKey ( t . Key ) )
{
flatnamesshorttofull . Add ( t . Key , t . Value ) ;
}
}
2009-04-19 18:07:22 +00:00
// Add flats to textures
2013-12-03 10:50:33 +00:00
foreach ( KeyValuePair < long , ImageData > f in flatsonly )
{
if ( ! textures . ContainsKey ( f . Key ) )
{
2009-04-19 18:07:22 +00:00
textures . Add ( f . Key , f . Value ) ;
texturenames . Add ( f . Value . Name ) ;
}
}
2010-08-12 19:59:06 +00:00
2014-12-03 09:06:05 +00:00
//mxd
foreach ( KeyValuePair < long , long > t in flatnamesshorttofull )
{
if ( ! texturenamesshorttofull . ContainsKey ( t . Key ) )
{
texturenamesshorttofull . Add ( t . Key , t . Value ) ;
}
}
2010-08-12 19:59:06 +00:00
// Do the same on the data readers
2013-12-02 15:02:01 +00:00
foreach ( DataReader dr in containers )
2010-08-12 19:59:06 +00:00
dr . TextureSet . MixTexturesAndFlats ( ) ;
2009-04-19 18:07:22 +00:00
}
2015-04-14 11:33:57 +00:00
//mxd. Should be done after loading textures...
LoadGldefs ( actorsbyclass ) ;
2009-04-19 18:07:22 +00:00
// Sort names
texturenames . Sort ( ) ;
flatnames . Sort ( ) ;
// Sort things
foreach ( ThingCategory tc in thingcategories ) tc . SortIfNeeded ( ) ;
// Update the used textures
General . Map . Data . UpdateUsedTextures ( ) ;
// Add texture names to texture sets
foreach ( KeyValuePair < long , ImageData > img in textures )
{
2013-07-29 08:50:50 +00:00
// Add to all sets
2009-04-19 18:07:22 +00:00
foreach ( MatchingTextureSet ms in texturesets )
2013-07-29 08:50:50 +00:00
ms . AddTexture ( img . Value ) ;
2009-04-19 18:07:22 +00:00
// Add to all
alltextures . AddTexture ( img . Value ) ;
}
// Add flat names to texture sets
foreach ( KeyValuePair < long , ImageData > img in flats )
{
2013-07-29 08:50:50 +00:00
// Add to all sets
2009-04-19 18:07:22 +00:00
foreach ( MatchingTextureSet ms in texturesets )
2013-07-29 08:50:50 +00:00
ms . AddFlat ( img . Value ) ;
2009-04-19 18:07:22 +00:00
// Add to all
alltextures . AddFlat ( img . Value ) ;
}
// Start background loading
StartBackgroundLoader ( ) ;
// Output info
2015-04-14 11:33:57 +00:00
General . WriteLogLine ( "Loaded " + texcount + " textures, " + flatcount + " flats, " +
colormapcount + " colormaps, " + spritecount + " sprites, " +
thingcount + " decorate things, " + modeldefentries . Count + " model/voxel deinitions, " +
gldefsentries . Count + " dynamic light definitions, " +
glowingflats . Count + " glowing flat definitions, " + reverbs . Count + " sound environment definitions" ) ;
2009-04-19 18:07:22 +00:00
}
// This unloads all data
2014-12-03 09:06:05 +00:00
private void Unload ( )
2009-04-19 18:07:22 +00:00
{
// Stop background loader
StopBackgroundLoader ( ) ;
// Dispose preview manager
previews . Dispose ( ) ;
previews = null ;
2010-08-19 15:06:15 +00:00
// Dispose decorate
decorate . Dispose ( ) ;
2009-04-19 18:07:22 +00:00
// Dispose resources
foreach ( KeyValuePair < long , ImageData > i in textures ) i . Value . Dispose ( ) ;
foreach ( KeyValuePair < long , ImageData > i in flats ) i . Value . Dispose ( ) ;
foreach ( KeyValuePair < long , ImageData > i in sprites ) i . Value . Dispose ( ) ;
palette = null ;
2012-05-21 23:51:32 +00:00
2013-09-11 09:47:53 +00:00
//mxd
2015-04-14 11:33:57 +00:00
if ( modeldefentries ! = null )
2014-12-03 23:15:26 +00:00
{
2015-04-14 11:33:57 +00:00
foreach ( KeyValuePair < int , ModelData > group in modeldefentries )
2013-09-11 09:47:53 +00:00
group . Value . Dispose ( ) ;
}
2009-04-19 18:07:22 +00:00
// Dispose containers
foreach ( DataReader c in containers ) c . Dispose ( ) ;
containers . Clear ( ) ;
// Trash collections
2010-08-19 15:06:15 +00:00
decorate = null ;
2009-04-19 18:07:22 +00:00
containers = null ;
textures = null ;
flats = null ;
sprites = null ;
texturenames = null ;
flatnames = null ;
imageque = null ;
internalsprites = null ;
}
#endregion
#region = = = = = = = = = = = = = = = = = = Suspend / Resume
// This suspends data resources
internal void Suspend ( )
{
// Stop background loader
StopBackgroundLoader ( ) ;
// Go for all containers
foreach ( DataReader d in containers )
{
// Suspend
General . WriteLogLine ( "Suspended data resource '" + d . Location . location + "'" ) ;
d . Suspend ( ) ;
}
}
// This resumes data resources
internal void Resume ( )
{
// Go for all containers
foreach ( DataReader d in containers )
{
try
{
// Resume
General . WriteLogLine ( "Resumed data resource '" + d . Location . location + "'" ) ;
d . Resume ( ) ;
}
catch ( Exception e )
{
// Unable to load resource
2009-05-10 16:02:08 +00:00
General . ErrorLogger . Add ( ErrorType . Error , "Unable to load resources from location \"" + d . Location . location + "\". Please make sure the location is accessible and not in use by another program. The resources will now be loaded with this location excluded. You may reload the resources to try again.\n" + e . GetType ( ) . Name + " when resuming data reader: " + e . Message + ")" ) ;
2009-04-19 18:07:22 +00:00
General . WriteLogLine ( e . StackTrace ) ;
}
}
// Start background loading
StartBackgroundLoader ( ) ;
}
#endregion
#region = = = = = = = = = = = = = = = = = = Background Loading
// This starts background loading
private void StartBackgroundLoader ( )
{
// Timing
2014-05-20 09:09:28 +00:00
loadstarttime = Clock . CurrentTime ;
2009-04-19 18:07:22 +00:00
loadfinishtime = 0 ;
// 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..." ) ;
2014-01-30 14:52:08 +00:00
backgroundloader = new Thread ( BackgroundLoad ) ;
2009-04-19 18:07:22 +00:00
backgroundloader . Name = "Background Loader" ;
backgroundloader . Priority = ThreadPriority . Lowest ;
backgroundloader . IsBackground = true ;
backgroundloader . Start ( ) ;
}
// This stops background loading
private void StopBackgroundLoader ( )
{
ImageData img ;
General . WriteLogLine ( "Stopping background resource loading..." ) ;
if ( backgroundloader ! = null )
{
// Stop the thread and wait for it to end
backgroundloader . Interrupt ( ) ;
backgroundloader . Join ( ) ;
// Reset load states on all images in the list
while ( imageque . Count > 0 )
{
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 ;
}
}
// Done
notifiedbusy = false ;
backgroundloader = null ;
General . SendMessage ( General . MainWindow . Handle , ( int ) MainForm . ThreadMessages . UpdateStatus , 0 , 0 ) ;
}
}
// The background loader
private void BackgroundLoad ( )
{
try
{
do
{
// Do we have to update the used-in-map status?
if ( updatedusedtextures ) BackgroundUpdateUsedTextures ( ) ;
// 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 )
{
// Load this image?
if ( image . IsReferenced & & ( image . ImageState ! = ImageLoadState . Ready ) )
{
image . LoadImage ( ) ;
}
// Unload this image?
Model rendering (all modes): UDMF scale, pitch and roll are now displayed.
Thing Edit Form, UDMF: added controls for setting pitch, roll, scale, render style, fill color, alpha, health and score.
Visual mode, UDMF: UDMF scale is now applied when rendering sprites.
Added Thing Statistics form (Edit -> View Thing Types...), which shows all loaded thing types with some additional info.
Visual mode: sprites with negative ScaleX and positive ScaleY were not rendered properly.
Classic modes: display was not updated after loading a sprite.
Current testing engine change was not saved on closing the program when no other game configuration settings were changed.
2014-04-30 10:01:22 +00:00
else if ( ! image . IsReferenced & & image . AllowUnload & & ( image . ImageState ! = ImageLoadState . None ) )
2009-04-19 18:07:22 +00:00
{
// Still unreferenced?
image . UnloadImage ( ) ;
}
}
// Doing something?
if ( image ! = null )
{
// Wait a bit and update icon
if ( ! notifiedbusy )
{
notifiedbusy = true ;
General . SendMessage ( General . MainWindow . Handle , ( int ) MainForm . ThreadMessages . UpdateStatus , 0 , 0 ) ;
}
Thread . Sleep ( 0 ) ;
}
else
{
// Process previews only when we don't have images to process
// because these are lower priority than the actual images
if ( previews . BackgroundLoad ( ) )
{
// Wait a bit and update icon
if ( ! notifiedbusy )
{
notifiedbusy = true ;
General . SendMessage ( General . MainWindow . Handle , ( int ) MainForm . ThreadMessages . UpdateStatus , 0 , 0 ) ;
}
Thread . Sleep ( 0 ) ;
}
else
{
if ( notifiedbusy )
{
notifiedbusy = false ;
General . SendMessage ( General . MainWindow . Handle , ( int ) MainForm . ThreadMessages . UpdateStatus , 0 , 0 ) ;
}
// Timing
if ( loadfinishtime = = 0 )
{
2014-10-15 08:36:17 +00:00
//mxd. Release PK3 files
foreach ( DataReader reader in containers )
{
if ( reader is PK3Reader ) ( reader as PK3Reader ) . BathMode = false ;
}
2014-05-20 09:09:28 +00:00
loadfinishtime = Clock . CurrentTime ;
2012-07-12 22:34:12 +00:00
float deltatimesec = ( loadfinishtime - loadstarttime ) / 1000.0f ;
2009-04-19 18:07:22 +00:00
General . WriteLogLine ( "Resources loading took " + deltatimesec . ToString ( "########0.00" ) + " seconds" ) ;
}
// Wait longer to release CPU resources
Thread . Sleep ( 50 ) ;
}
}
}
while ( true ) ;
}
catch ( ThreadInterruptedException )
{
return ;
}
}
// This adds an image for background loading or unloading
internal void ProcessImage ( ImageData img )
{
// Load this image?
if ( ( img . ImageState = = ImageLoadState . None ) & & img . IsReferenced )
{
// Add for loading
img . ImageState = ImageLoadState . Loading ;
lock ( imageque ) { imageque . Enqueue ( img ) ; }
}
// Unload this image?
2010-08-11 20:32:14 +00:00
if ( ( img . ImageState = = ImageLoadState . Ready ) & & ! img . IsReferenced & & img . AllowUnload )
2009-04-19 18:07:22 +00:00
{
// Add for unloading
img . ImageState = ImageLoadState . Unloading ;
lock ( imageque ) { imageque . Enqueue ( img ) ; }
}
// Update icon
General . SendMessage ( General . MainWindow . Handle , ( int ) MainForm . ThreadMessages . UpdateStatus , 0 , 0 ) ;
}
2013-07-29 08:50:50 +00:00
//mxd. This loads a model
2014-12-03 09:06:05 +00:00
internal bool ProcessModel ( int type )
{
2015-04-14 11:33:57 +00:00
if ( modeldefentries [ type ] . LoadState ! = ModelLoadState . None ) return true ;
2013-07-29 08:50:50 +00:00
//create models
2015-04-14 11:33:57 +00:00
ModelReader . Load ( modeldefentries [ type ] , containers , General . Map . Graphics . Device ) ;
2013-07-29 08:50:50 +00:00
2015-04-14 11:33:57 +00:00
if ( modeldefentries [ type ] . Model ! = null )
2014-12-03 09:06:05 +00:00
{
2015-04-14 11:33:57 +00:00
modeldefentries [ type ] . LoadState = ModelLoadState . Ready ;
2013-07-30 09:25:27 +00:00
return true ;
2013-07-29 08:50:50 +00:00
}
2013-07-30 09:25:27 +00:00
2015-04-14 11:33:57 +00:00
modeldefentries . Remove ( type ) ;
2013-07-30 09:25:27 +00:00
return false ;
2013-07-29 08:50:50 +00:00
}
2009-04-19 18:07:22 +00:00
// This updates the used-in-map status on all textures and flats
private void BackgroundUpdateUsedTextures ( )
{
lock ( usedimages )
{
// Set used on all textures
foreach ( KeyValuePair < long , ImageData > i in textures )
{
i . Value . SetUsedInMap ( usedimages . ContainsKey ( i . Key ) ) ;
if ( i . Value . IsImageLoaded ! = i . Value . IsReferenced ) ProcessImage ( i . Value ) ;
}
// Set used on all flats
2014-12-03 09:06:05 +00:00
foreach ( KeyValuePair < long , ImageData > i in flats )
{
2013-12-02 15:02:01 +00:00
i . Value . SetUsedInMap ( usedimages . ContainsKey ( i . Key ) ) ;
if ( i . Value . IsImageLoaded ! = i . Value . IsReferenced ) ProcessImage ( i . Value ) ;
2009-04-19 18:07:22 +00:00
}
// Done
updatedusedtextures = false ;
}
}
#endregion
#region = = = = = = = = = = = = = = = = = = Palette
// This loads the PLAYPAL palette
private void LoadPalette ( )
{
// Go for all opened containers
for ( int i = containers . Count - 1 ; i > = 0 ; i - - )
{
// Load palette
palette = containers [ i ] . LoadPalette ( ) ;
if ( palette ! = null ) break ;
}
// Make empty palette when still no palette found
if ( palette = = null )
{
2009-05-10 16:02:08 +00:00
General . ErrorLogger . Add ( ErrorType . Warning , "None of the loaded resources define a color palette. Did you forget to configure an IWAD for this game configuration?" ) ;
2009-04-19 18:07:22 +00:00
palette = new Playpal ( ) ;
}
}
#endregion
2009-05-12 09:50:08 +00:00
#region = = = = = = = = = = = = = = = = = = Colormaps
// This loads the colormaps
private int LoadColormaps ( Dictionary < long , ImageData > list )
{
ICollection < ImageData > images ;
int counter = 0 ;
// Go for all opened containers
foreach ( DataReader dr in containers )
{
// Load colormaps
images = dr . LoadColormaps ( ) ;
if ( images ! = null )
{
// Go for all colormaps
foreach ( ImageData img in images )
{
// Add or replace in flats list
list . Remove ( img . LongName ) ;
list . Add ( img . LongName , img ) ;
counter + + ;
// Add to preview manager
previews . AddImage ( img ) ;
}
}
}
// Output info
return counter ;
}
// This returns a specific colormap stream
internal Stream GetColormapData ( string pname )
{
Stream colormap ;
// Go for all opened containers
for ( int i = containers . Count - 1 ; i > = 0 ; i - - )
{
// This contain provides this flat?
colormap = containers [ i ] . GetColormapData ( pname ) ;
if ( colormap ! = null ) return colormap ;
}
// No such patch found
return null ;
}
#endregion
2009-04-19 18:07:22 +00:00
#region = = = = = = = = = = = = = = = = = = Textures
2009-05-12 09:50:08 +00:00
2009-04-19 18:07:22 +00:00
// This loads the textures
2014-12-03 09:06:05 +00:00
private int LoadTextures ( Dictionary < long , ImageData > list , Dictionary < long , long > nametranslation )
2009-04-19 18:07:22 +00:00
{
ICollection < ImageData > images ;
PatchNames pnames = new PatchNames ( ) ;
PatchNames newpnames ;
int counter = 0 ;
// Go for all opened containers
foreach ( DataReader dr in containers )
{
// Load PNAMES info
// Note that pnames is NOT set to null in the loop
// because if a container has no pnames, the pnames
// of the previous (higher) container should be used.
newpnames = dr . LoadPatchNames ( ) ;
if ( newpnames ! = null ) pnames = newpnames ;
// Load textures
images = dr . LoadTextures ( pnames ) ;
if ( images ! = null )
{
// Go for all textures
foreach ( ImageData img in images )
{
// Add or replace in textures list
list . Remove ( img . LongName ) ;
list . Add ( img . LongName , img ) ;
counter + + ;
2014-12-03 09:06:05 +00:00
//mxd. Also add as short name when texture name is longer than 8 chars
// Or remove when a wad image with short name overrides previously added
// resource image with long name
if ( img . HasLongName )
{
long longshortname = Lump . MakeLongName ( Path . GetFileNameWithoutExtension ( img . Name ) , false ) ;
nametranslation . Remove ( longshortname ) ;
nametranslation . Add ( longshortname , img . LongName ) ;
}
else if ( img is TextureImage & & nametranslation . ContainsKey ( img . LongName ) )
{
nametranslation . Remove ( img . LongName ) ;
}
2009-04-19 18:07:22 +00:00
// Add to preview manager
previews . AddImage ( img ) ;
}
}
}
// Output info
return counter ;
}
// This returns a specific patch stream
2014-11-25 11:52:01 +00:00
internal Stream GetPatchData ( string pname , bool longname )
2009-04-19 18:07:22 +00:00
{
Stream patch ;
// Go for all opened containers
2013-07-29 08:50:50 +00:00
for ( int i = containers . Count - 1 ; i > - 1 ; i - - )
2009-04-19 18:07:22 +00:00
{
// This contain provides this patch?
2014-11-25 11:52:01 +00:00
patch = containers [ i ] . GetPatchData ( pname , longname ) ;
2009-04-19 18:07:22 +00:00
if ( patch ! = null ) return patch ;
}
// No such patch found
return null ;
}
// This returns a specific texture stream
2014-11-25 11:52:01 +00:00
internal Stream GetTextureData ( string pname , bool longname )
2009-04-19 18:07:22 +00:00
{
Stream patch ;
// Go for all opened containers
for ( int i = containers . Count - 1 ; i > = 0 ; i - - )
{
// This contain provides this patch?
2014-11-25 11:52:01 +00:00
patch = containers [ i ] . GetTextureData ( pname , longname ) ;
2009-04-19 18:07:22 +00:00
if ( patch ! = null ) return patch ;
}
// No such patch found
return null ;
}
2010-08-12 09:01:22 +00:00
// This checks if a given texture is known
public bool GetTextureExists ( string name )
{
2015-01-16 13:14:57 +00:00
return GetTextureExists ( Lump . MakeLongName ( name ) ) ; //mxd
2010-08-12 09:01:22 +00:00
}
// This checks if a given texture is known
public bool GetTextureExists ( long longname )
{
2014-12-03 09:06:05 +00:00
return textures . ContainsKey ( longname ) | | texturenamesshorttofull . ContainsKey ( longname ) ;
2010-08-12 09:01:22 +00:00
}
2009-04-19 18:07:22 +00:00
// This returns an image by string
public ImageData GetTextureImage ( string name )
{
// Get the long name
long longname = Lump . MakeLongName ( name ) ;
return GetTextureImage ( longname ) ;
}
2010-08-12 09:01:22 +00:00
2009-04-19 18:07:22 +00:00
// This returns an image by long
public ImageData GetTextureImage ( long longname )
{
// Does this texture exist?
2015-01-23 21:51:11 +00:00
if ( textures . ContainsKey ( longname ) & & textures [ longname ] is HighResImage ) return textures [ longname ] ; //TEXTURES textures should still override regular ones...
2014-12-03 09:06:05 +00:00
if ( texturenamesshorttofull . ContainsKey ( longname ) ) return textures [ texturenamesshorttofull [ longname ] ] ; //mxd
if ( textures . ContainsKey ( longname ) ) return textures [ longname ] ;
2013-07-23 14:25:03 +00:00
// Return null image
2014-01-13 08:06:56 +00:00
return unknownimage ; //mxd
2009-04-19 18:07:22 +00:00
}
2014-11-25 11:52:01 +00:00
//mxd
public string GetFullTextureName ( string name )
{
if ( Path . GetFileNameWithoutExtension ( name ) = = name & & name . Length > CLASIC_IMAGE_NAME_LENGTH )
name = name . Substring ( 0 , CLASIC_IMAGE_NAME_LENGTH ) ;
long hash = MurmurHash2 . Hash ( name . Trim ( ) . ToUpperInvariant ( ) ) ;
2014-12-03 09:06:05 +00:00
2015-01-23 21:51:11 +00:00
if ( textures . ContainsKey ( hash ) & & textures [ hash ] is HighResImage ) return textures [ hash ] . Name ; //TEXTURES textures should still override regular ones...
2014-11-25 11:52:01 +00:00
if ( texturenamesshorttofull . ContainsKey ( hash ) ) return textures [ texturenamesshorttofull [ hash ] ] . Name ;
2014-12-03 09:06:05 +00:00
if ( textures . ContainsKey ( hash ) ) return textures [ hash ] . Name ;
2014-11-25 11:52:01 +00:00
return name ;
}
2014-12-03 09:06:05 +00:00
//mxd
internal long GetFullLongTextureName ( long hash )
{
2015-01-23 21:51:11 +00:00
if ( textures . ContainsKey ( hash ) & & textures [ hash ] is HighResImage ) return hash ; //TEXTURES textures should still override regular ones...
2014-12-03 09:06:05 +00:00
return ( General . Map . Config . UseLongTextureNames & & texturenamesshorttofull . ContainsKey ( hash ) ? texturenamesshorttofull [ hash ] : hash ) ;
}
2009-04-19 18:07:22 +00:00
#endregion
#region = = = = = = = = = = = = = = = = = = Flats
// This loads the flats
2014-12-03 09:06:05 +00:00
private int LoadFlats ( Dictionary < long , ImageData > list , Dictionary < long , long > nametranslation )
2009-04-19 18:07:22 +00:00
{
ICollection < ImageData > images ;
int counter = 0 ;
// Go for all opened containers
foreach ( DataReader dr in containers )
{
// Load flats
images = dr . LoadFlats ( ) ;
if ( images ! = null )
{
// Go for all flats
foreach ( ImageData img in images )
{
// Add or replace in flats list
list . Remove ( img . LongName ) ;
list . Add ( img . LongName , img ) ;
counter + + ;
2014-12-03 09:06:05 +00:00
//mxd. Also add as short name when texture name is longer than 8 chars
// Or remove when a wad image with short name overrides previously added
// resource image with long name
if ( img . HasLongName )
{
long longshortname = Lump . MakeLongName ( Path . GetFileNameWithoutExtension ( img . Name ) , false ) ;
nametranslation . Remove ( longshortname ) ;
nametranslation . Add ( longshortname , img . LongName ) ;
}
else if ( img is FlatImage & & nametranslation . ContainsKey ( img . LongName ) )
{
nametranslation . Remove ( img . LongName ) ;
}
2009-04-19 18:07:22 +00:00
// Add to preview manager
previews . AddImage ( img ) ;
}
}
}
// Output info
return counter ;
}
// This returns a specific flat stream
2014-11-25 11:52:01 +00:00
internal Stream GetFlatData ( string pname , bool longname )
2009-04-19 18:07:22 +00:00
{
Stream flat ;
// Go for all opened containers
for ( int i = containers . Count - 1 ; i > = 0 ; i - - )
{
// This contain provides this flat?
2014-11-25 11:52:01 +00:00
flat = containers [ i ] . GetFlatData ( pname , longname ) ;
2009-04-19 18:07:22 +00:00
if ( flat ! = null ) return flat ;
}
// No such patch found
return null ;
}
2010-08-12 09:01:22 +00:00
// This checks if a flat is known
public bool GetFlatExists ( string name )
{
2015-01-16 13:14:57 +00:00
return GetFlatExists ( Lump . MakeLongName ( name ) ) ; //mxd
2010-08-12 09:01:22 +00:00
}
// This checks if a flat is known
public bool GetFlatExists ( long longname )
{
2014-12-03 09:06:05 +00:00
return flats . ContainsKey ( longname ) | | flatnamesshorttofull . ContainsKey ( longname ) ;
2010-08-12 09:01:22 +00:00
}
2009-04-19 18:07:22 +00:00
// This returns an image by string
public ImageData GetFlatImage ( string name )
{
// Get the long name
long longname = Lump . MakeLongName ( name ) ;
return GetFlatImage ( longname ) ;
}
// This returns an image by long
public ImageData GetFlatImage ( long longname )
{
2013-12-02 15:02:01 +00:00
// Does this flat exist?
2015-01-23 21:51:11 +00:00
if ( flats . ContainsKey ( longname ) & & flats [ longname ] is HighResImage ) return flats [ longname ] ; //TEXTURES flats should still override regular ones...
2014-12-03 09:06:05 +00:00
if ( flatnamesshorttofull . ContainsKey ( longname ) ) return flats [ flatnamesshorttofull [ longname ] ] ; //mxd
2013-12-02 15:02:01 +00:00
if ( flats . ContainsKey ( longname ) ) return flats [ longname ] ;
2013-12-03 10:50:33 +00:00
2013-07-29 08:50:50 +00:00
// Return null image
2014-01-13 08:06:56 +00:00
return unknownimage ; //mxd
2009-04-19 18:07:22 +00:00
}
2010-08-14 09:30:54 +00:00
// This returns an image by long and doesn't check if it exists
2015-01-23 21:51:11 +00:00
/ * public ImageData GetFlatImageKnown ( long longname )
2010-08-14 09:30:54 +00:00
{
// Return flat
2014-12-03 09:06:05 +00:00
return flatnamesshorttofull . ContainsKey ( longname ) ? flats [ flatnamesshorttofull [ longname ] ] : flats [ longname ] ; //mxd
2015-01-23 21:51:11 +00:00
} * /
2014-11-25 11:52:01 +00:00
//mxd. Gets full flat name by short flat name
public string GetFullFlatName ( string name )
{
if ( Path . GetFileNameWithoutExtension ( name ) = = name & & name . Length > CLASIC_IMAGE_NAME_LENGTH )
name = name . Substring ( 0 , CLASIC_IMAGE_NAME_LENGTH ) ;
long hash = MurmurHash2 . Hash ( name . ToUpperInvariant ( ) ) ;
2014-12-03 09:06:05 +00:00
2015-01-23 21:51:11 +00:00
if ( flats . ContainsKey ( hash ) & & flats [ hash ] is HighResImage ) return flats [ hash ] . Name ; //TEXTURES flats should still override regular ones...
2014-11-25 11:52:01 +00:00
if ( flatnamesshorttofull . ContainsKey ( hash ) ) return flats [ flatnamesshorttofull [ hash ] ] . Name ;
2014-12-03 09:06:05 +00:00
if ( flats . ContainsKey ( hash ) ) return flats [ hash ] . Name ;
2014-11-25 11:52:01 +00:00
return name ;
}
2014-12-03 09:06:05 +00:00
//mxd
internal long GetFullLongFlatName ( long hash )
{
2015-01-23 21:51:11 +00:00
if ( flats . ContainsKey ( hash ) & & flats [ hash ] is HighResImage ) return hash ; //TEXTURES flats should still override regular ones...
2014-12-03 09:06:05 +00:00
return ( General . Map . Config . UseLongTextureNames & & flatnamesshorttofull . ContainsKey ( hash ) ? flatnamesshorttofull [ hash ] : hash ) ;
}
2009-04-19 18:07:22 +00:00
#endregion
#region = = = = = = = = = = = = = = = = = = Sprites
2010-08-18 09:07:54 +00:00
// This loads the hard defined sprites (not all the lumps, we do that on a need-to-know basis, see LoadThingSprites)
2009-04-19 18:07:22 +00:00
private int LoadSprites ( )
2010-08-18 09:07:54 +00:00
{
ICollection < ImageData > images ;
int counter = 0 ;
// Load all defined sprites. Note that we do not use all sprites,
// so we don't add them for previews just yet.
foreach ( DataReader dr in containers )
{
// Load sprites
images = dr . LoadSprites ( ) ;
if ( images ! = null )
{
// Add or replace in sprites list
foreach ( ImageData img in images )
{
sprites [ img . LongName ] = img ;
counter + + ;
}
}
}
// Output info
return counter ;
}
// This loads the sprites that we really need for things
private int LoadThingSprites ( )
2009-04-19 18:07:22 +00:00
{
// Go for all things
foreach ( ThingTypeInfo ti in General . Map . Data . ThingTypes )
{
2010-08-18 09:07:54 +00:00
// Valid sprite name?
2014-11-25 11:52:01 +00:00
if ( ti . Sprite . Length = = 0 | | ti . Sprite . Length > CLASIC_IMAGE_NAME_LENGTH ) continue ; //mxd
2010-08-18 09:07:54 +00:00
2014-01-03 10:33:45 +00:00
ImageData image = null ;
// Sprite not in our collection yet?
if ( ! sprites . ContainsKey ( ti . SpriteLongName ) )
{
// Find sprite data
Stream spritedata = GetSpriteData ( ti . Sprite ) ;
if ( spritedata ! = null )
2010-08-18 09:07:54 +00:00
{
2014-01-03 10:33:45 +00:00
// Make new sprite image
image = new SpriteImage ( ti . Sprite ) ;
// Add to collection
sprites . Add ( ti . SpriteLongName , image ) ;
}
2014-12-03 09:06:05 +00:00
else //mxd
{
2014-01-03 10:33:45 +00:00
General . ErrorLogger . Add ( ErrorType . Error , "Missing sprite lump '" + ti . Sprite + "'. Forgot to include required resources?" ) ;
2010-08-18 09:07:54 +00:00
}
2014-01-03 10:33:45 +00:00
}
else
{
image = sprites [ ti . SpriteLongName ] ;
2009-04-19 18:07:22 +00:00
}
2014-01-03 10:33:45 +00:00
// Add to preview manager
if ( image ! = null ) previews . AddImage ( image ) ;
2009-04-19 18:07:22 +00:00
}
2010-08-18 09:07:54 +00:00
2009-04-19 18:07:22 +00:00
// Output info
return sprites . Count ;
}
2010-08-18 09:07:54 +00:00
2009-04-19 18:07:22 +00:00
// This returns a specific patch stream
internal Stream GetSpriteData ( string pname )
{
if ( ! string . IsNullOrEmpty ( pname ) )
{
// Go for all opened containers
for ( int i = containers . Count - 1 ; i > = 0 ; i - - )
{
// This contain provides this patch?
Stream spritedata = containers [ i ] . GetSpriteData ( pname ) ;
if ( spritedata ! = null ) return spritedata ;
}
}
// No such patch found
return null ;
}
// This tests if a given sprite can be found
internal bool GetSpriteExists ( string pname )
{
if ( ! string . IsNullOrEmpty ( pname ) )
{
2010-08-18 09:07:54 +00:00
long longname = Lump . MakeLongName ( pname ) ;
2015-01-23 21:51:11 +00:00
if ( sprites . ContainsKey ( longname ) ) return true ;
2010-08-18 09:07:54 +00:00
2009-04-19 18:07:22 +00:00
// Go for all opened containers
for ( int i = containers . Count - 1 ; i > = 0 ; i - - )
{
// This contain provides this patch?
if ( containers [ i ] . GetSpriteExists ( pname ) ) return true ;
}
}
// No such patch found
return false ;
}
// This loads the internal sprites
private void LoadInternalSprites ( )
{
// Add sprite icon files from directory
string [ ] files = Directory . GetFiles ( General . SpritesPath , "*.png" , SearchOption . TopDirectoryOnly ) ;
foreach ( string spritefile in files )
{
2014-11-25 11:52:01 +00:00
ImageData img = new FileImage ( Path . GetFileNameWithoutExtension ( spritefile ) . ToLowerInvariant ( ) , spritefile ) ;
2009-04-19 18:07:22 +00:00
img . LoadImage ( ) ;
2010-08-11 20:32:14 +00:00
img . AllowUnload = false ;
2009-04-19 18:07:22 +00:00
internalsprites . Add ( img . Name , img ) ;
}
// Add some internal resources
if ( ! internalsprites . ContainsKey ( "nothing" ) )
{
2009-08-02 18:21:53 +00:00
ImageData img = new ResourceImage ( "CodeImp.DoomBuilder.Resources.Nothing.png" ) ;
2009-04-19 18:07:22 +00:00
img . LoadImage ( ) ;
2010-08-11 20:32:14 +00:00
img . AllowUnload = false ;
2009-04-19 18:07:22 +00:00
internalsprites . Add ( "nothing" , img ) ;
}
if ( ! internalsprites . ContainsKey ( "unknownthing" ) )
{
2009-08-02 18:21:53 +00:00
ImageData img = new ResourceImage ( "CodeImp.DoomBuilder.Resources.UnknownThing.png" ) ;
2009-04-19 18:07:22 +00:00
img . LoadImage ( ) ;
2010-08-11 20:32:14 +00:00
img . AllowUnload = false ;
2009-04-19 18:07:22 +00:00
internalsprites . Add ( "unknownthing" , img ) ;
2013-08-21 10:45:54 +00:00
}
//mxd
2014-05-19 13:33:38 +00:00
if ( ! internalsprites . ContainsKey ( "missingthing" ) )
{
2013-08-21 10:45:54 +00:00
ImageData img = new ResourceImage ( "CodeImp.DoomBuilder.Resources.MissingThing.png" ) ;
img . LoadImage ( ) ;
img . AllowUnload = false ;
internalsprites . Add ( "missingthing" , img ) ;
2009-04-19 18:07:22 +00:00
}
}
2013-08-21 10:45:54 +00:00
// This returns an image by name
2009-04-19 18:07:22 +00:00
public ImageData GetSpriteImage ( string name )
{
// Is this referring to an internal sprite image?
if ( ( name . Length > INTERNAL_PREFIX . Length ) & & name . ToLowerInvariant ( ) . StartsWith ( INTERNAL_PREFIX ) )
{
// Get the internal sprite
string internalname = name . Substring ( INTERNAL_PREFIX . Length ) . ToLowerInvariant ( ) ;
if ( internalsprites . ContainsKey ( internalname ) )
return internalsprites [ internalname ] ;
2013-08-21 10:45:54 +00:00
return internalsprites [ "unknownthing" ] ; //mxd
2009-04-19 18:07:22 +00:00
}
else
{
// Get the long name
long longname = Lump . MakeLongName ( name ) ;
// Sprite already loaded?
if ( sprites . ContainsKey ( longname ) )
{
// Return exiting sprite
return sprites [ longname ] ;
}
else
{
Stream spritedata = null ;
// Go for all opened containers
for ( int i = containers . Count - 1 ; i > = 0 ; i - - )
{
2013-08-21 10:45:54 +00:00
// This container provides this sprite?
2009-04-19 18:07:22 +00:00
spritedata = containers [ i ] . GetSpriteData ( name ) ;
if ( spritedata ! = null ) break ;
}
// Found anything?
if ( spritedata ! = null )
{
// Make new sprite image
SpriteImage image = new SpriteImage ( name ) ;
// Add to collection
sprites . Add ( longname , image ) ;
// Return result
return image ;
}
2013-08-21 10:45:54 +00:00
else //mxd
2009-04-19 18:07:22 +00:00
{
2013-08-21 10:45:54 +00:00
ImageData img = string . IsNullOrEmpty ( name ) ? internalsprites [ "unknownthing" ] : internalsprites [ "missingthing" ] ;
// Add to collection
sprites . Add ( longname , img ) ;
2013-09-03 09:34:28 +00:00
// Return image
2013-08-21 10:45:54 +00:00
return img ;
2009-04-19 18:07:22 +00:00
}
}
}
}
#endregion
#region = = = = = = = = = = = = = = = = = = Things
// This loads the things from Decorate
2015-04-14 11:33:57 +00:00
private int LoadDecorateThings ( Dictionary < int , string > spawnnumsoverride , Dictionary < int , string > doomednumsoverride )
2009-04-19 18:07:22 +00:00
{
int counter = 0 ;
2015-06-01 21:46:28 +00:00
char [ ] catsplitter = new [ ] { Path . AltDirectorySeparatorChar } ; //mxd
2009-04-19 18:07:22 +00:00
2009-08-15 08:41:43 +00:00
// Create new parser
decorate = new DecorateParser ( ) ;
decorate . OnInclude = LoadDecorateFromLocation ;
2009-04-19 18:07:22 +00:00
// Only load these when the game configuration supports the use of decorate
if ( ! string . IsNullOrEmpty ( General . Map . Config . DecorateGames ) )
{
// Go for all opened containers
foreach ( DataReader dr in containers )
{
// Load Decorate info cumulatively (the last Decorate is added to the previous)
// I'm not sure if this is the right thing to do though.
currentreader = dr ;
2014-10-23 12:48:31 +00:00
Dictionary < string , Stream > decostreams = dr . GetDecorateData ( "DECORATE" ) ;
foreach ( KeyValuePair < string , Stream > group in decostreams )
2009-04-19 18:07:22 +00:00
{
// Parse the data
2014-10-23 12:48:31 +00:00
group . Value . Seek ( 0 , SeekOrigin . Begin ) ;
decorate . Parse ( group . Value , group . Key , true ) ;
2009-04-19 18:07:22 +00:00
// Check for errors
2009-08-15 08:41:43 +00:00
if ( decorate . HasError )
2009-04-19 18:07:22 +00:00
{
2014-10-23 12:48:31 +00:00
General . ErrorLogger . Add ( ErrorType . Error , "DECORATE error in '" + decorate . ErrorSource
+ "', line " + decorate . ErrorLine + ". " + decorate . ErrorDescription + "." ) ;
2009-04-19 18:07:22 +00:00
break ;
}
}
}
currentreader = null ;
2009-08-15 08:41:43 +00:00
if ( ! decorate . HasError )
2009-04-19 18:07:22 +00:00
{
2015-04-14 11:33:57 +00:00
// Step 1. Go for all actors in the decorate to make things or update things
2009-08-15 08:41:43 +00:00
foreach ( ActorStructure actor in decorate . Actors )
2009-04-19 18:07:22 +00:00
{
// Check if we want to add this actor
if ( actor . DoomEdNum > 0 )
{
2015-06-08 14:37:20 +00:00
string catname = ZDTextParser . StripQuotes ( actor . GetPropertyAllValues ( "$category" ) ) ;
2015-06-01 21:46:28 +00:00
string [ ] catnames ; //mxd
if ( string . IsNullOrEmpty ( catname . Trim ( ) ) )
catnames = new [ ] { "decorate" } ;
else
catnames = catname . Split ( catsplitter , StringSplitOptions . RemoveEmptyEntries ) ; //mxd
2009-04-19 18:07:22 +00:00
// Check if we can find this thing in our existing collection
if ( thingtypes . ContainsKey ( actor . DoomEdNum ) )
{
// Update the thing
thingtypes [ actor . DoomEdNum ] . ModifyByDecorateActor ( actor ) ;
}
else
{
// Find the category to put the actor in
2015-06-01 21:46:28 +00:00
ThingCategory cat = GetThingCategory ( null , thingcategories , catnames ) ; //mxd
2009-04-19 18:07:22 +00:00
// Add new thing
ThingTypeInfo t = new ThingTypeInfo ( cat , actor ) ;
cat . AddThing ( t ) ;
thingtypes . Add ( t . Index , t ) ;
}
// Count
counter + + ;
2015-04-14 11:33:57 +00:00
}
}
//mxd. Step 2. Apply DoomEdNum MAPINFO overrides, remove actors disabled in MAPINFO
if ( doomednumsoverride . Count > 0 )
{
List < int > toremove = new List < int > ( ) ;
Dictionary < string , ThingTypeInfo > thingtypesbyclass = new Dictionary < string , ThingTypeInfo > ( ) ;
foreach ( KeyValuePair < int , ThingTypeInfo > group in thingtypes )
{
if ( string . IsNullOrEmpty ( group . Value . ClassName ) ) continue ;
thingtypesbyclass [ group . Value . ClassName . ToLowerInvariant ( ) ] = group . Value ;
}
foreach ( KeyValuePair < int , string > group in doomednumsoverride )
{
// Remove thing from the list?
if ( group . Value = = "none" )
{
toremove . Add ( group . Key ) ;
continue ;
}
// Skip if already added.
if ( thingtypes . ContainsKey ( group . Key ) & & thingtypes [ group . Key ] . ClassName . ToLowerInvariant ( ) = = group . Value )
{
continue ;
}
// Try to find the actor...
ActorStructure actor = null ;
2015-04-29 08:36:10 +00:00
//... in ActorsByClass
if ( decorate . ActorsByClass . ContainsKey ( group . Value ) )
2015-04-14 11:33:57 +00:00
{
2015-04-29 08:36:10 +00:00
actor = decorate . ActorsByClass [ group . Value ] ;
}
// Try finding in ArchivedActors
else if ( decorate . AllActorsByClass . ContainsKey ( group . Value ) )
{
actor = decorate . AllActorsByClass [ group . Value ] ;
2015-04-14 11:33:57 +00:00
}
if ( actor ! = null )
{
// Find the category to put the actor in
2015-06-08 14:37:20 +00:00
string catname = ZDTextParser . StripQuotes ( actor . GetPropertyAllValues ( "$category" ) ) ;
2015-06-01 21:46:28 +00:00
string [ ] catnames ; //mxd
if ( string . IsNullOrEmpty ( catname . Trim ( ) ) )
catnames = new [ ] { "decorate" } ;
else
catnames = catname . Split ( catsplitter , StringSplitOptions . RemoveEmptyEntries ) ; //mxd
ThingCategory cat = GetThingCategory ( null , thingcategories , catnames ) ; //mxd
2015-04-14 11:33:57 +00:00
// Add a new ThingTypeInfo, replacing already existing one if necessary
2015-04-29 08:36:10 +00:00
ThingTypeInfo info = new ThingTypeInfo ( cat , actor , group . Key ) ;
2015-04-14 11:33:57 +00:00
thingtypes [ group . Key ] = info ;
2015-04-29 08:36:10 +00:00
cat . AddThing ( info ) ;
2015-04-14 11:33:57 +00:00
}
// Check thingtypes...
else if ( thingtypesbyclass . ContainsKey ( group . Value ) )
{
ThingTypeInfo t = new ThingTypeInfo ( group . Key , thingtypesbyclass [ group . Value ] ) ;
// Add new thing, replacing already existing one if necessary
t . Category . AddThing ( t ) ;
thingtypes [ group . Key ] = t ;
}
// Loudly give up...
else
{
General . ErrorLogger . Add ( ErrorType . Warning , "Failed to apply MAPINFO DoomEdNum override '" + group . Key + " = " + group . Value + ": failed to find corresponding actor class..." ) ;
}
}
// Remove items
foreach ( int id in toremove )
{
if ( thingtypes . ContainsKey ( id ) )
{
thingtypes [ id ] . Category . RemoveThing ( thingtypes [ id ] ) ;
thingtypes . Remove ( id ) ;
}
}
}
//mxd. Step 3. Gather DECORATE SpawnIDs
Dictionary < int , EnumItem > configspawnnums = new Dictionary < int , EnumItem > ( ) ;
// Update or create the main enums list
if ( General . Map . Config . Enums . ContainsKey ( "spawnthing" ) )
{
foreach ( EnumItem item in General . Map . Config . Enums [ "spawnthing" ] )
configspawnnums . Add ( item . GetIntValue ( ) , item ) ;
}
bool spawnidschanged = false ;
if ( ! decorate . HasError )
{
foreach ( ActorStructure actor in decorate . Actors )
{
int spawnid = actor . GetPropertyValueInt ( "spawnid" , 0 ) ;
if ( spawnid ! = 0 )
{
configspawnnums [ spawnid ] = new EnumItem ( spawnid . ToString ( ) , ( actor . HasPropertyWithValue ( "$title" ) ? actor . GetPropertyAllValues ( "$title" ) : actor . ClassName ) ) ;
spawnidschanged = true ;
}
}
}
//mxd. Step 4. Update SpawnNums using MAPINFO overrides
if ( spawnnumsoverride . Count > 0 )
{
// Modify by MAPINFO data
foreach ( KeyValuePair < int , string > group in spawnnumsoverride )
{
configspawnnums [ group . Key ] = new EnumItem ( group . Key . ToString ( ) , ( thingtypes . ContainsKey ( group . Key ) ? thingtypes [ group . Key ] . Title : group . Value ) ) ;
}
spawnidschanged = true ;
}
if ( spawnidschanged )
{
// Update the main collection
EnumList newenums = new EnumList ( ) ;
newenums . AddRange ( configspawnnums . Values ) ;
newenums . Sort ( ) ;
General . Map . Config . Enums [ "spawnthing" ] = newenums ;
// Update all ArgumentInfos...
foreach ( ThingTypeInfo info in thingtypes . Values )
{
foreach ( ArgumentInfo ai in info . Args )
if ( ai . Enum . Name = = "spawnthing" ) ai . Enum = newenums ;
}
foreach ( LinedefActionInfo info in General . Map . Config . LinedefActions . Values )
{
foreach ( ArgumentInfo ai in info . Args )
if ( ai . Enum . Name = = "spawnthing" ) ai . Enum = newenums ;
2009-04-19 18:07:22 +00:00
}
}
}
}
// Output info
return counter ;
}
2015-04-14 11:33:57 +00:00
//mxd
2015-06-01 21:46:28 +00:00
private static ThingCategory GetThingCategory ( ThingCategory parent , List < ThingCategory > categories , string [ ] catnames )
2015-04-14 11:33:57 +00:00
{
// Find the category to put the actor in
ThingCategory cat = null ;
2015-06-01 21:46:28 +00:00
string catname = catnames [ 0 ] . ToLowerInvariant ( ) . Trim ( ) ;
if ( string . IsNullOrEmpty ( catname ) ) catname = "decorate" ;
// First search by Title...
foreach ( ThingCategory c in categories )
2015-04-14 11:33:57 +00:00
{
if ( c . Title . ToLowerInvariant ( ) = = catname ) cat = c ;
}
2015-06-08 14:37:20 +00:00
// Make full name
if ( parent ! = null ) catname = parent . Name . ToLowerInvariant ( ) + "." + catname ;
2015-06-01 22:10:15 +00:00
//...then - by Name
2015-04-14 11:33:57 +00:00
if ( cat = = null )
{
2015-06-01 21:46:28 +00:00
foreach ( ThingCategory c in categories )
2015-04-14 11:33:57 +00:00
{
if ( c . Name . ToLowerInvariant ( ) = = catname ) cat = c ;
}
}
// Make the category if needed
2015-06-01 21:46:28 +00:00
if ( cat = = null )
{
string cattitle = catnames [ 0 ] . Trim ( ) ;
if ( string . IsNullOrEmpty ( cattitle ) ) cattitle = "Decorate" ;
2015-06-01 22:10:15 +00:00
cat = new ThingCategory ( parent , catname , cattitle ) ;
2015-06-01 21:46:28 +00:00
categories . Add ( cat ) ; // ^.^
}
// Still have subcategories?
if ( catnames . Length > 1 )
2015-04-14 11:33:57 +00:00
{
2015-06-01 21:46:28 +00:00
string [ ] remainingnames = new string [ catnames . Length - 1 ] ;
Array . Copy ( catnames , 1 , remainingnames , 0 , remainingnames . Length ) ;
return GetThingCategory ( cat , cat . Children , remainingnames ) ;
2015-04-14 11:33:57 +00:00
}
return cat ;
}
2009-04-19 18:07:22 +00:00
// This loads Decorate data from a specific file or lump name
private void LoadDecorateFromLocation ( DecorateParser parser , string location )
{
//General.WriteLogLine("Including DECORATE resource '" + location + "'...");
2014-10-23 12:48:31 +00:00
Dictionary < string , Stream > decostreams = currentreader . GetDecorateData ( location ) ;
foreach ( KeyValuePair < string , Stream > group in decostreams )
2009-04-19 18:07:22 +00:00
{
// Parse this data
2014-10-23 12:48:31 +00:00
parser . Parse ( group . Value , Path . Combine ( currentreader . Location . location , group . Key ) ) ;
2009-04-19 18:07:22 +00:00
}
}
// This gets thing information by index
public ThingTypeInfo GetThingInfo ( int thingtype )
{
// Index in config?
if ( thingtypes . ContainsKey ( thingtype ) )
{
// Return from config
return thingtypes [ thingtype ] ;
}
2014-02-21 15:24:54 +00:00
// Create unknown thing info
return new ThingTypeInfo ( thingtype ) ;
2009-04-19 18:07:22 +00:00
}
// This gets thing information by index
// Returns null when thing type info could not be found
public ThingTypeInfo GetThingInfoEx ( int thingtype )
{
// Index in config?
if ( thingtypes . ContainsKey ( thingtype ) )
{
// Return from config
return thingtypes [ thingtype ] ;
}
2014-02-21 15:24:54 +00:00
// No such thing type known
return null ;
2009-04-19 18:07:22 +00:00
}
#endregion
2014-01-03 10:33:45 +00:00
#region = = = = = = = = = = = = = = = = = = mxd . Modeldef , Voxeldef , Gldefs , Mapinfo
2012-05-21 23:51:32 +00:00
2013-09-11 09:47:53 +00:00
//mxd. This creates <Actor Class, Thing.Type> dictionary. Should be called after all DECORATE actors are parsed
2015-04-14 11:33:57 +00:00
private Dictionary < string , List < int > > CreateActorsByClassList ( )
2014-12-03 23:15:26 +00:00
{
2015-04-14 11:33:57 +00:00
Dictionary < string , List < int > > actors = new Dictionary < string , List < int > > ( StringComparer . Ordinal ) ;
2012-05-21 23:51:32 +00:00
2013-09-11 09:47:53 +00:00
//read our new shiny ClassNames for default game things
2015-04-14 11:33:57 +00:00
foreach ( KeyValuePair < int , ThingTypeInfo > ti in thingtypes )
2014-12-03 23:15:26 +00:00
{
2015-04-14 11:33:57 +00:00
if ( ! string . IsNullOrEmpty ( ti . Value . ClassName ) )
{
string classname = ti . Value . ClassName . ToLowerInvariant ( ) ;
if ( ! actors . ContainsKey ( classname ) ) actors . Add ( classname , new List < int > ( ) ) ;
actors [ classname ] . Add ( ti . Key ) ;
}
2013-09-11 09:47:53 +00:00
}
2012-06-01 10:17:47 +00:00
2013-09-16 14:07:12 +00:00
if ( actors . Count = = 0 )
2014-10-15 08:36:17 +00:00
General . ErrorLogger . Add ( ErrorType . Warning , "Warning: unable to find any DECORATE actor definitions!" ) ;
2013-09-16 14:07:12 +00:00
2013-09-11 09:47:53 +00:00
return actors ;
}
2012-06-01 10:17:47 +00:00
2013-09-11 09:47:53 +00:00
//mxd
2014-12-03 23:15:26 +00:00
public void ReloadModeldef ( )
{
2015-04-14 11:33:57 +00:00
if ( modeldefentries ! = null )
2014-12-03 23:15:26 +00:00
{
2015-04-14 11:33:57 +00:00
foreach ( KeyValuePair < int , ModelData > group in modeldefentries )
2013-09-11 09:47:53 +00:00
group . Value . Dispose ( ) ;
}
2012-08-05 19:18:05 +00:00
2013-09-11 09:47:53 +00:00
General . MainWindow . DisplayStatus ( StatusType . Busy , "Reloading model definitions..." ) ;
2014-12-03 23:15:26 +00:00
LoadModeldefs ( CreateActorsByClassList ( ) ) ;
2013-07-29 08:50:50 +00:00
2014-03-03 13:40:29 +00:00
General . MainWindow . DisplayStatus ( StatusType . Busy , "Reloading voxel definitions..." ) ;
2014-12-03 23:15:26 +00:00
LoadVoxels ( ) ;
2014-03-03 13:40:29 +00:00
Model rendering (all modes): UDMF scale, pitch and roll are now displayed.
Thing Edit Form, UDMF: added controls for setting pitch, roll, scale, render style, fill color, alpha, health and score.
Visual mode, UDMF: UDMF scale is now applied when rendering sprites.
Added Thing Statistics form (Edit -> View Thing Types...), which shows all loaded thing types with some additional info.
Visual mode: sprites with negative ScaleX and positive ScaleY were not rendered properly.
Classic modes: display was not updated after loading a sprite.
Current testing engine change was not saved on closing the program when no other game configuration settings were changed.
2014-04-30 10:01:22 +00:00
foreach ( Thing t in General . Map . Map . Things ) t . UpdateCache ( ) ;
2012-06-01 10:17:47 +00:00
2013-09-11 09:47:53 +00:00
//rebuild geometry if in Visual mode
2014-12-03 23:15:26 +00:00
if ( General . Editing . Mode ! = null & & General . Editing . Mode . GetType ( ) . Name = = "BaseVisualMode" )
{
2013-09-11 09:47:53 +00:00
General . Editing . Mode . OnReloadResources ( ) ;
}
General . MainWindow . DisplayReady ( ) ;
}
//mxd
2014-12-03 23:15:26 +00:00
public void ReloadGldefs ( )
{
2013-09-11 09:47:53 +00:00
General . MainWindow . DisplayStatus ( StatusType . Busy , "Reloading GLDEFS..." ) ;
2014-03-03 13:40:29 +00:00
2014-12-03 23:15:26 +00:00
try
{
LoadGldefs ( CreateActorsByClassList ( ) ) ;
}
catch ( ArgumentNullException )
{
2014-03-03 13:40:29 +00:00
MessageBox . Show ( "GLDEFS reload failed. Try using 'Reload Resources' instead.\nCheck 'Errors and Warnings' window for more details." ) ;
General . MainWindow . DisplayReady ( ) ;
return ;
}
2013-09-11 09:47:53 +00:00
//rebuild geometry if in Visual mode
2014-12-03 23:15:26 +00:00
if ( General . Editing . Mode ! = null & & General . Editing . Mode . GetType ( ) . Name = = "BaseVisualMode" )
{
2013-09-11 09:47:53 +00:00
General . Editing . Mode . OnReloadResources ( ) ;
}
General . MainWindow . DisplayReady ( ) ;
}
//mxd. This parses modeldefs. Should be called after all DECORATE actors are parsed and actorsByClass dictionary created
2015-04-14 11:33:57 +00:00
private void LoadModeldefs ( Dictionary < string , List < int > > actorsByClass )
2014-12-03 23:15:26 +00:00
{
2013-09-11 09:47:53 +00:00
//if no actors defined in DECORATE or game config...
2015-04-14 11:33:57 +00:00
if ( actorsByClass . Count = = 0 ) return ;
2013-09-11 09:47:53 +00:00
2014-02-26 14:11:06 +00:00
Dictionary < string , ModelData > modelDefEntriesByName = new Dictionary < string , ModelData > ( StringComparer . Ordinal ) ;
2014-01-03 10:33:45 +00:00
ModeldefParser parser = new ModeldefParser ( ) ;
2013-09-11 09:47:53 +00:00
2014-12-03 23:15:26 +00:00
foreach ( DataReader dr in containers )
{
2013-09-11 09:47:53 +00:00
currentreader = dr ;
Dictionary < string , Stream > streams = dr . GetModeldefData ( ) ;
2014-12-03 23:15:26 +00:00
foreach ( KeyValuePair < string , Stream > group in streams )
{
2013-09-11 09:47:53 +00:00
// Parse the data
2014-12-03 23:15:26 +00:00
if ( parser . Parse ( group . Value , currentreader . Location . location + "\\" + group . Key ) )
{
foreach ( KeyValuePair < string , ModelData > g in parser . Entries )
{
if ( modelDefEntriesByName . ContainsKey ( g . Key ) )
{
2014-09-22 00:16:42 +00:00
General . ErrorLogger . Add ( ErrorType . Warning , "Model definition for actor '" + g . Key + "' is double-defined in '" + group . Key + "'" ) ;
modelDefEntriesByName [ g . Key ] = g . Value ;
2014-12-03 23:15:26 +00:00
}
else
{
2014-09-22 00:16:42 +00:00
modelDefEntriesByName . Add ( g . Key , g . Value ) ;
}
2013-09-11 09:47:53 +00:00
}
}
}
}
currentreader = null ;
2014-12-03 23:15:26 +00:00
foreach ( KeyValuePair < string , ModelData > e in modelDefEntriesByName )
{
2015-04-14 11:33:57 +00:00
if ( actorsByClass . ContainsKey ( e . Key ) )
{
foreach ( int i in actorsByClass [ e . Key ] ) modeldefentries [ i ] = modelDefEntriesByName [ e . Key ] ;
}
else if ( ! decorate . ActorsByClass . ContainsKey ( e . Key ) )
{
2013-09-11 09:47:53 +00:00
General . ErrorLogger . Add ( ErrorType . Warning , "Got MODELDEF override for class '" + e . Key + "', but haven't found such class in Decorate" ) ;
2015-04-14 11:33:57 +00:00
}
2013-09-11 09:47:53 +00:00
}
}
2012-06-01 10:17:47 +00:00
2014-01-03 10:33:45 +00:00
//mxd
2014-12-03 23:15:26 +00:00
private void LoadVoxels ( )
{
2014-01-03 10:33:45 +00:00
//Get names of all voxel models, which can be used "as is"
2014-02-26 14:11:06 +00:00
Dictionary < string , bool > voxelNames = new Dictionary < string , bool > ( StringComparer . Ordinal ) ;
2014-01-03 10:33:45 +00:00
2014-12-03 23:15:26 +00:00
foreach ( DataReader dr in containers )
{
2014-01-03 10:33:45 +00:00
currentreader = dr ;
string [ ] result = dr . GetVoxelNames ( ) ;
if ( result = = null ) continue ;
2014-12-03 23:15:26 +00:00
foreach ( string s in result )
{
2014-01-03 10:33:45 +00:00
if ( ! voxelNames . ContainsKey ( s ) ) voxelNames . Add ( s , false ) ;
}
}
2014-02-26 14:11:06 +00:00
Dictionary < string , List < int > > sprites = new Dictionary < string , List < int > > ( StringComparer . Ordinal ) ;
2014-01-03 10:33:45 +00:00
// Go for all things
2014-12-03 23:15:26 +00:00
foreach ( ThingTypeInfo ti in thingtypes . Values )
{
2014-01-03 10:33:45 +00:00
// Valid sprite name?
2014-02-21 14:42:12 +00:00
string sprite ;
2014-01-03 10:33:45 +00:00
2014-12-03 23:15:26 +00:00
if ( ti . Sprite . Length = = 0 | | ti . Sprite . Length > CLASIC_IMAGE_NAME_LENGTH )
{
2014-01-03 10:33:45 +00:00
if ( ti . Actor = = null ) continue ;
sprite = ti . Actor . FindSuitableVoxel ( voxelNames ) ;
2014-12-03 23:15:26 +00:00
}
else
{
2014-01-03 10:33:45 +00:00
sprite = ti . Sprite ;
}
if ( string . IsNullOrEmpty ( sprite ) ) continue ;
if ( ! sprites . ContainsKey ( sprite ) ) sprites . Add ( sprite , new List < int > ( ) ) ;
sprites [ sprite ] . Add ( ti . Index ) ;
}
VoxeldefParser parser = new VoxeldefParser ( ) ;
2014-02-26 14:11:06 +00:00
Dictionary < string , bool > processed = new Dictionary < string , bool > ( StringComparer . Ordinal ) ;
2014-01-03 10:33:45 +00:00
//parse VOXLEDEF
2014-12-03 23:15:26 +00:00
foreach ( DataReader dr in containers )
{
2014-01-03 10:33:45 +00:00
currentreader = dr ;
KeyValuePair < string , Stream > group = dr . GetVoxeldefData ( ) ;
2014-12-03 23:15:26 +00:00
if ( group . Value ! = null & & parser . Parse ( group . Value , group . Key ) )
{
foreach ( KeyValuePair < string , ModelData > entry in parser . Entries )
{
foreach ( KeyValuePair < string , List < int > > sc in sprites )
{
if ( sc . Key . Contains ( entry . Key ) )
{
2015-04-14 11:33:57 +00:00
foreach ( int id in sc . Value ) modeldefentries [ id ] = entry . Value ;
2014-01-03 10:33:45 +00:00
processed . Add ( entry . Key , false ) ;
}
}
}
}
}
currentreader = null ;
//get voxel models
2014-12-03 23:15:26 +00:00
foreach ( KeyValuePair < string , bool > group in voxelNames )
{
2014-01-03 10:33:45 +00:00
if ( processed . ContainsKey ( group . Key ) ) continue ;
2014-12-03 23:15:26 +00:00
foreach ( KeyValuePair < string , List < int > > sc in sprites )
{
if ( sc . Key . Contains ( group . Key ) )
{
2014-01-03 10:33:45 +00:00
//it's a model without a definition, and it corresponds to a sprite we can display, so let's add it
2014-02-26 14:11:06 +00:00
ModelData data = new ModelData { IsVoxel = true } ;
2014-01-03 10:33:45 +00:00
data . ModelNames . Add ( group . Key ) ;
2015-04-14 11:33:57 +00:00
foreach ( int id in sprites [ sc . Key ] ) modeldefentries [ id ] = data ;
2014-01-03 10:33:45 +00:00
}
}
}
}
2013-09-11 09:47:53 +00:00
//mxd. This parses gldefs. Should be called after all DECORATE actors are parsed and actorsByClass dictionary created
2015-04-14 11:33:57 +00:00
private void LoadGldefs ( Dictionary < string , List < int > > actorsByClass )
2014-12-03 23:15:26 +00:00
{
2013-09-11 09:47:53 +00:00
//if no actors defined in DECORATE or game config...
2015-04-14 11:33:57 +00:00
if ( actorsByClass . Count = = 0 ) return ;
2013-09-11 09:47:53 +00:00
2015-04-14 11:33:57 +00:00
GldefsParser parser = new GldefsParser { OnInclude = ParseFromLocation } ;
2013-09-11 09:47:53 +00:00
//load gldefs from resources
2014-12-03 23:15:26 +00:00
foreach ( DataReader dr in containers )
{
2013-09-11 09:47:53 +00:00
currentreader = dr ;
2015-01-20 12:20:35 +00:00
parser . ClearIncludesList ( ) ;
2013-09-11 09:47:53 +00:00
Dictionary < string , Stream > streams = dr . GetGldefsData ( General . Map . Config . GameType ) ;
foreach ( KeyValuePair < string , Stream > group in streams )
parser . Parse ( group . Value , group . Key ) ;
}
//create gldefsEntries dictionary
2014-12-03 23:15:26 +00:00
foreach ( KeyValuePair < string , string > e in parser . Objects ) //ClassName, Light name
{
2013-09-11 09:47:53 +00:00
//if we have decorate actor and light definition for given ClassName...
2014-12-03 23:15:26 +00:00
if ( actorsByClass . ContainsKey ( e . Key ) & & parser . LightsByName . ContainsKey ( e . Value ) )
{
2015-04-14 11:33:57 +00:00
foreach ( int i in actorsByClass [ e . Key ] )
{
if ( gldefsentries . ContainsKey ( i ) )
gldefsentries [ i ] = parser . LightsByName [ e . Value ] ;
else
gldefsentries . Add ( i , parser . LightsByName [ e . Value ] ) ;
}
2014-12-03 23:15:26 +00:00
}
2015-04-14 11:33:57 +00:00
else if ( ! decorate . AllActorsByClass . ContainsKey ( e . Key ) )
2014-12-03 23:15:26 +00:00
{
2013-09-11 09:47:53 +00:00
General . ErrorLogger . Add ( ErrorType . Warning , "Got GLDEFS light for class '" + e . Key + "', but haven't found such class in DECORATE" ) ;
}
}
2015-04-14 11:33:57 +00:00
// Grab them glowy flats!
glowingflats = parser . GlowingFlats ;
2013-09-11 09:47:53 +00:00
}
//mxd. This loads (Z)MAPINFO
2015-04-14 11:33:57 +00:00
private void LoadMapInfo ( out Dictionary < int , string > spawnnums , out Dictionary < int , string > doomednums )
2014-12-03 23:15:26 +00:00
{
2015-04-14 11:33:57 +00:00
MapinfoParser parser = new MapinfoParser { OnInclude = ParseFromLocation } ;
2013-09-11 09:47:53 +00:00
2014-12-03 23:15:26 +00:00
foreach ( DataReader dr in containers )
{
2013-09-11 09:47:53 +00:00
currentreader = dr ;
Dictionary < string , Stream > streams = dr . GetMapinfoData ( ) ;
2014-12-03 23:15:26 +00:00
foreach ( KeyValuePair < string , Stream > group in streams )
{
2013-09-11 09:47:53 +00:00
// Parse the data
parser . Parse ( group . Value , Path . Combine ( currentreader . Location . location , group . Key ) , General . Map . Options . LevelName ) ;
}
}
2015-04-14 11:33:57 +00:00
// Set the output values
spawnnums = parser . SpawnNums ;
doomednums = parser . DoomEdNums ;
// Store to our MapInfo property
2013-09-11 09:47:53 +00:00
currentreader = null ;
2015-04-14 11:33:57 +00:00
mapinfo = parser . MapInfo ? ? new MapInfo ( ) ;
2013-09-11 09:47:53 +00:00
}
2015-04-14 11:33:57 +00:00
private void ParseFromLocation ( ZDTextParser parser , string location )
2014-12-03 23:15:26 +00:00
{
2015-04-14 11:33:57 +00:00
if ( currentreader . IsSuspended ) throw new Exception ( "Data reader is suspended" ) ;
Stream s = currentreader . LoadFile ( location ) ;
if ( s ! = null ) parser . Parse ( s , location ) ;
2013-09-11 09:47:53 +00:00
}
2015-01-25 23:22:42 +00:00
//mxd. This loads REVERBS
private void LoadReverbs ( )
{
ReverbsParser parser = new ReverbsParser ( ) ;
reverbs . Clear ( ) ;
foreach ( DataReader dr in containers )
{
currentreader = dr ;
Dictionary < string , Stream > streams = dr . GetReverbsData ( ) ;
foreach ( KeyValuePair < string , Stream > group in streams )
{
// Parse the data
parser . Parse ( group . Value , group . Key ) ;
}
}
currentreader = null ;
reverbs = parser . GetReverbs ( ) ;
}
2015-05-28 13:45:01 +00:00
//mxd. This loads SNDSEQ
private void LoadSndSeq ( )
{
SndSeqParser parser = new SndSeqParser ( ) ;
soundsequences . Clear ( ) ;
foreach ( DataReader dr in containers )
{
currentreader = dr ;
List < Stream > streams = dr . GetSndSeqData ( ) ;
// Parse the data
foreach ( Stream s in streams )
{
if ( s ! = null ) parser . Parse ( s , "SNDSEQ" ) ;
}
}
currentreader = null ;
soundsequences = parser . GetSoundSequences ( ) ;
}
2013-09-11 09:47:53 +00:00
//mxd
2014-12-03 23:15:26 +00:00
internal MemoryStream LoadFile ( string name )
{
2015-02-24 13:38:35 +00:00
//relative path?
if ( name . StartsWith ( "..\\" ) ) name = name . Replace ( "..\\" , "" ) ;
2014-12-03 23:15:26 +00:00
foreach ( DataReader dr in containers )
if ( dr . FileExists ( name ) ) return dr . LoadFile ( name ) ;
2013-09-11 09:47:53 +00:00
return null ;
}
#endregion
#region = = = = = = = = = = = = = = = = = = Tools
// This finds the first IWAD resource
2009-04-19 18:07:22 +00:00
// Returns false when not found
2012-06-01 19:53:14 +00:00
public bool FindFirstIWAD ( out DataLocation result )
2009-04-19 18:07:22 +00:00
{
// Go for all data containers
foreach ( DataReader dr in containers )
{
// Container is a WAD file?
if ( dr is WADReader )
{
// Check if it is an IWAD
WADReader wr = dr as WADReader ;
if ( wr . IsIWAD )
{
// Return location!
result = wr . Location ;
return true ;
}
}
}
// No IWAD found
result = new DataLocation ( ) ;
return false ;
}
// This signals the background thread to update the
// used-in-map status on all textures and flats
public void UpdateUsedTextures ( )
{
lock ( usedimages )
{
usedimages . Clear ( ) ;
// Go through the map to find the used textures
foreach ( Sidedef sd in General . Map . Map . Sidedefs )
{
// Add used textures to dictionary
2014-03-05 09:21:28 +00:00
if ( sd . LongHighTexture ! = MapSet . EmptyLongName ) usedimages [ sd . LongHighTexture ] = 0 ;
if ( sd . LongMiddleTexture ! = MapSet . EmptyLongName ) usedimages [ sd . LongMiddleTexture ] = 0 ;
if ( sd . LongLowTexture ! = MapSet . EmptyLongName ) usedimages [ sd . LongLowTexture ] = 0 ;
2009-04-19 18:07:22 +00:00
}
// Go through the map to find the used flats
foreach ( Sector s in General . Map . Map . Sectors )
{
// Add used flats to dictionary
usedimages [ s . LongFloorTexture ] = 0 ;
usedimages [ s . LongCeilTexture ] = 0 ;
}
// Notify the background thread that it needs to update the images
updatedusedtextures = true ;
}
}
#endregion
}
}