Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge branch 'branch_develop3d_GLContextLostReloadResources' into dev…

…elop3d
  • Loading branch information...
commit 26539aa2d89ee335f770cee036690ae1137632ff 2 parents 9ed4a4d + 93a291a
@Aranda Aranda authored
View
6 MonoGame.Framework/Android/AndroidGameActivity.cs
@@ -78,6 +78,12 @@ protected override void OnResume()
(deviceManager as GraphicsDeviceManager).ForceSetFullScreen();
Game.Window.RequestFocus();
}
+
+ protected override void OnRestart()
+ {
+ base.OnRestart();
+ Game.Window.OnRestart();
+ }
}
public static class ActivityExtensions
View
21 MonoGame.Framework/Android/AndroidGameWindow.cs
@@ -71,6 +71,7 @@ public class AndroidGameWindow : AndroidGameView , Android.Views.View.IOnTouchLi
private DisplayOrientation _currentOrientation;
private AndroidTouchEventManager _touchManager = null;
private bool exiting = false;
+ private bool _contextWasLost = false;
public bool TouchEnabled
{
@@ -146,7 +147,15 @@ public override bool OnKeyUp(Keycode keyCode, KeyEvent e)
{
//
}
-
+
+ internal void OnRestart()
+ {
+ // If restarting, check if the context was lost. It appears that it always is,
+ // but I suspect that it's possible to avoid this case as some games don't need
+ // to reload their textures after switching back from another app.
+ _contextWasLost = GraphicsContext == null || GraphicsContext.IsDisposed;
+ }
+
protected override void CreateFrameBuffer()
{
Android.Util.Log.Debug("MonoGame", "AndroidGameWindow.CreateFrameBuffer");
@@ -155,20 +164,28 @@ protected override void CreateFrameBuffer()
{
GLContextVersion = GLContextVersion.Gles2_0;
base.CreateFrameBuffer();
+ Android.Util.Log.Debug("MonoGame", "AndroidGameWindow.CreateFrameBuffer");
}
catch (Exception)
#endif
{
throw new NotSupportedException("Could not create OpenGLES 2.0 frame buffer");
}
- if (_game.GraphicsDevice != null)
+ if (_game.GraphicsDevice != null && _contextWasLost)
{
+ _contextWasLost = false;
_game.GraphicsDevice.Initialize();
+ EffectPass.RecompileAll();
+ Microsoft.Xna.Framework.Content.ContentManager.ReloadGraphicsContent();
+
+ _game.graphicsDeviceManager.OnDeviceReset(EventArgs.Empty);
+ _game.GraphicsDevice.OnDeviceReset();
}
if (!GraphicsContext.IsCurrent)
MakeCurrent();
}
+
protected override void DestroyFrameBuffer()
{
Android.Util.Log.Debug("MonoGame", "AndroidGameWindow.DestroyFrameBuffer");
View
418 MonoGame.Framework/Content/ContentManager.cs
@@ -72,7 +72,8 @@ private static void AddContentManager(ContentManager contentManager)
{
lock (ContentManagerLock)
{
- ContentManagers.Add(contentManager);
+ if (!ContentManagers.Contains(contentManager))
+ ContentManagers.Add(contentManager);
}
}
@@ -85,13 +86,13 @@ private static void RemoveContentManager(ContentManager contentManager)
}
}
- internal static void ReloadAllContent()
+ internal static void ReloadGraphicsContent()
{
lock (ContentManagerLock)
{
foreach (var contentManager in ContentManagers)
{
- contentManager.ReloadContent();
+ contentManager.ReloadGraphicsAssets();
}
}
}
@@ -116,6 +117,7 @@ public ContentManager(IServiceProvider serviceProvider)
throw new ArgumentNullException("serviceProvider");
}
this.serviceProvider = serviceProvider;
+ AddContentManager(this);
}
public ContentManager(IServiceProvider serviceProvider, string rootDirectory)
@@ -130,6 +132,7 @@ public ContentManager(IServiceProvider serviceProvider, string rootDirectory)
}
this.RootDirectory = rootDirectory;
this.serviceProvider = serviceProvider;
+ AddContentManager(this);
}
public void Dispose()
@@ -138,6 +141,8 @@ public void Dispose()
// Tell the garbage collector not to call the finalizer
// since all the cleanup will already be done.
GC.SuppressFinalize(this);
+ // Once disposed, content manager wont be used again
+ RemoveContentManager(this);
}
// If disposing is true, it was called explicitly.
@@ -177,12 +182,7 @@ public virtual T Load<T>(string assetName)
// Load the asset.
result = ReadAsset<T>(assetName, null);
- // Cache the result.
- if (!loadedAssets.ContainsKey(assetName))
- {
- loadedAssets.Add(assetName, result);
- }
-
+ loadedAssets[assetName] = result;
return result;
}
@@ -191,8 +191,9 @@ protected virtual Stream OpenStream(string assetName)
Stream stream;
try
{
- string assetPath = Path.Combine(_rootDirectory, assetName) + ".xnb";
+ string assetPath = Path.Combine(_rootDirectory, assetName) + ".xnb";
stream = TitleContainer.OpenStream(assetPath);
+
#if ANDROID
// Read the asset into memory in one go. This results in a ~50% reduction
// in load times on Android due to slow Android asset streams.
@@ -247,13 +248,32 @@ protected T ReadAsset<T>(string assetName, Action<IDisposable> recordDisposableO
}
Stream stream = null;
- bool loadXnb = false;
try
{
//try load it traditionally
stream = OpenStream(assetName);
- loadXnb = true;
- }
+
+ // Try to load as XNB file
+ try
+ {
+ using (BinaryReader xnbReader = new BinaryReader(stream))
+ {
+ using (ContentReader reader = GetContentReaderFromXnb(assetName, ref stream, xnbReader, recordDisposableObject))
+ {
+ result = reader.ReadAsset<T>();
+ if (result is GraphicsResource)
+ ((GraphicsResource)result).Name = originalAssetName;
+ }
+ }
+ }
+ finally
+ {
+ if (stream != null)
+ {
+ stream.Dispose();
+ }
+ }
+ }
catch (ContentLoadException)
{
//MonoGame try to load as a non-content file
@@ -330,139 +350,19 @@ protected T ReadAsset<T>(string assetName, Action<IDisposable> recordDisposableO
result = new Effect(this.graphicsDeviceService.GraphicsDevice, data);
}
}
+ }
+
+ if (result == null)
+ {
+ throw new ContentLoadException("Could not load " + originalAssetName + " asset!");
}
-
- if (loadXnb) {
- // Try to load as XNB file
- try
- {
- using(BinaryReader xnbReader = new BinaryReader(stream))
- {
- // The first 4 bytes should be the "XNB" header. i use that to detect an invalid file
- byte x = xnbReader.ReadByte();
- byte n = xnbReader.ReadByte();
- byte b = xnbReader.ReadByte();
- byte platform = xnbReader.ReadByte();
-
- if (x != 'X' || n != 'N' || b != 'B' ||
- !(platform == 'w' || platform == 'x' || platform == 'm'))
- {
- throw new ContentLoadException("Asset does not appear to be a valid XNB file. Did you process your content for Windows?");
- }
-
- byte version = xnbReader.ReadByte();
- byte flags = xnbReader.ReadByte();
-
- bool compressed = (flags & 0x80) != 0;
- if (version != 5 && version != 4)
- {
- throw new ContentLoadException("Invalid XNB version");
- }
-
- // The next int32 is the length of the XNB file
- int xnbLength = xnbReader.ReadInt32();
-
- ContentReader reader;
- if (compressed)
- {
- //decompress the xnb
- //thanks to ShinAli (https://bitbucket.org/alisci01/xnbdecompressor)
- int compressedSize = xnbLength - 14;
- int decompressedSize = xnbReader.ReadInt32();
- int newFileSize = decompressedSize + 10;
-
- MemoryStream decompressedStream = new MemoryStream(decompressedSize);
-
- // default window size for XNB encoded files is 64Kb (need 16 bits to represent it)
- LzxDecoder dec = new LzxDecoder(16);
- int decodedBytes = 0;
- long startPos = stream.Position;
- long pos = startPos;
-
-#if ANDROID
- // Android native stream does not support the Position property. LzxDecoder.Decompress also uses
- // Seek. So we read the entirity of the stream into a memory stream and replace stream with the
- // memory stream.
- MemoryStream memStream = new MemoryStream();
- stream.CopyTo(memStream);
- memStream.Seek(0, SeekOrigin.Begin);
- stream.Dispose();
- stream = memStream;
- pos = -14;
-#endif
-
- while (pos-startPos < compressedSize)
- {
- // the compressed stream is seperated into blocks that will decompress
- // into 32Kb or some other size if specified.
- // normal, 32Kb output blocks will have a short indicating the size
- // of the block before the block starts
- // blocks that have a defined output will be preceded by a byte of value
- // 0xFF (255), then a short indicating the output size and another
- // for the block size
- // all shorts for these cases are encoded in big endian order
- int hi = stream.ReadByte();
- int lo = stream.ReadByte();
- int block_size = (hi << 8) | lo;
- int frame_size = 0x8000; // frame size is 32Kb by default
- // does this block define a frame size?
- if (hi == 0xFF)
- {
- hi = lo;
- lo = (byte)stream.ReadByte();
- frame_size = (hi << 8) | lo;
- hi = (byte)stream.ReadByte();
- lo = (byte)stream.ReadByte();
- block_size = (hi << 8) | lo;
- pos += 5;
- }
- else
- pos += 2;
-
- // either says there is nothing to decode
- if (block_size == 0 || frame_size == 0)
- break;
-
- int lzxRet = dec.Decompress(stream, block_size, decompressedStream, frame_size);
- pos += block_size;
- decodedBytes += frame_size;
-
- // reset the position of the input just incase the bit buffer
- // read in some unused bytes
- stream.Seek(pos, SeekOrigin.Begin);
- }
-
- if (decompressedStream.Position != decompressedSize)
- {
- throw new ContentLoadException("Decompression of " + originalAssetName + " failed. ");
- }
-
- decompressedStream.Seek(0, SeekOrigin.Begin);
- reader = new ContentReader( this, decompressedStream, this.graphicsDeviceService.GraphicsDevice,
- originalAssetName, version, recordDisposableObject);
- }
- else
- {
- reader = new ContentReader( this, stream, this.graphicsDeviceService.GraphicsDevice,
- originalAssetName, version, recordDisposableObject);
- }
-
- using(reader)
- {
- result = reader.ReadAsset<T>();
- if (result is GraphicsResource)
- ((GraphicsResource)result).Name = originalAssetName;
- }
- }
- }
- finally
- {
- if (stream != null)
- {
- stream.Dispose();
- }
- }
+ if (result is IDisposable)
+ {
+ if (recordDisposableObject != null)
+ recordDisposableObject(result as IDisposable);
+ else
+ disposableAssets.Add(result as IDisposable);
}
if (result == null)
@@ -471,31 +371,166 @@ protected T ReadAsset<T>(string assetName, Action<IDisposable> recordDisposableO
}
CurrentAssetDirectory = null;
-
+
return (T)result;
}
+ private ContentReader GetContentReaderFromXnb(string originalAssetName, ref Stream stream, BinaryReader xnbReader, Action<IDisposable> recordDisposableObject)
+ {
+ // The first 4 bytes should be the "XNB" header. i use that to detect an invalid file
+ byte x = xnbReader.ReadByte();
+ byte n = xnbReader.ReadByte();
+ byte b = xnbReader.ReadByte();
+ byte platform = xnbReader.ReadByte();
+
+ if (x != 'X' || n != 'N' || b != 'B' ||
+ !(platform == 'w' || platform == 'x' || platform == 'm'))
+ {
+ throw new ContentLoadException("Asset does not appear to be a valid XNB file. Did you process your content for Windows?");
+ }
+
+ byte version = xnbReader.ReadByte();
+ byte flags = xnbReader.ReadByte();
+
+ bool compressed = (flags & 0x80) != 0;
+ if (version != 5 && version != 4)
+ {
+ throw new ContentLoadException("Invalid XNB version");
+ }
+
+ // The next int32 is the length of the XNB file
+ int xnbLength = xnbReader.ReadInt32();
+
+ ContentReader reader;
+ if (compressed)
+ {
+ //decompress the xnb
+ //thanks to ShinAli (https://bitbucket.org/alisci01/xnbdecompressor)
+ int compressedSize = xnbLength - 14;
+ int decompressedSize = xnbReader.ReadInt32();
+ int newFileSize = decompressedSize + 10;
+
+ MemoryStream decompressedStream = new MemoryStream(decompressedSize);
+
+ // default window size for XNB encoded files is 64Kb (need 16 bits to represent it)
+ LzxDecoder dec = new LzxDecoder(16);
+ int decodedBytes = 0;
+ long startPos = stream.Position;
+ long pos = startPos;
+
+#if ANDROID
+ // Android native stream does not support the Position property. LzxDecoder.Decompress also uses
+ // Seek. So we read the entirity of the stream into a memory stream and replace stream with the
+ // memory stream.
+ MemoryStream memStream = new MemoryStream();
+ stream.CopyTo(memStream);
+ memStream.Seek(0, SeekOrigin.Begin);
+ stream.Dispose();
+ stream = memStream;
+ pos = -14;
+#endif
+
+ while (pos - startPos < compressedSize)
+ {
+ // the compressed stream is seperated into blocks that will decompress
+ // into 32Kb or some other size if specified.
+ // normal, 32Kb output blocks will have a short indicating the size
+ // of the block before the block starts
+ // blocks that have a defined output will be preceded by a byte of value
+ // 0xFF (255), then a short indicating the output size and another
+ // for the block size
+ // all shorts for these cases are encoded in big endian order
+ int hi = stream.ReadByte();
+ int lo = stream.ReadByte();
+ int block_size = (hi << 8) | lo;
+ int frame_size = 0x8000; // frame size is 32Kb by default
+ // does this block define a frame size?
+ if (hi == 0xFF)
+ {
+ hi = lo;
+ lo = (byte)stream.ReadByte();
+ frame_size = (hi << 8) | lo;
+ hi = (byte)stream.ReadByte();
+ lo = (byte)stream.ReadByte();
+ block_size = (hi << 8) | lo;
+ pos += 5;
+ }
+ else
+ pos += 2;
+
+ // either says there is nothing to decode
+ if (block_size == 0 || frame_size == 0)
+ break;
+
+ int lzxRet = dec.Decompress(stream, block_size, decompressedStream, frame_size);
+ pos += block_size;
+ decodedBytes += frame_size;
+
+ // reset the position of the input just incase the bit buffer
+ // read in some unused bytes
+ stream.Seek(pos, SeekOrigin.Begin);
+ }
+
+ if (decompressedStream.Position != decompressedSize)
+ {
+ throw new ContentLoadException("Decompression of " + originalAssetName + " failed. ");
+ }
+
+ decompressedStream.Seek(0, SeekOrigin.Begin);
+ reader = new ContentReader(this, decompressedStream, this.graphicsDeviceService.GraphicsDevice,
+ originalAssetName, version, recordDisposableObject);
+ }
+ else
+ {
+ reader = new ContentReader(this, stream, this.graphicsDeviceService.GraphicsDevice,
+ originalAssetName, version, recordDisposableObject);
+ }
+ return reader;
+ }
+
internal void RecordDisposable(IDisposable disposable)
{
Debug.Assert(disposable != null, "The disposable is null!");
- // Be sure the system isn't accidentally recording
- // disposable objects twice!
- Debug.Assert(!disposableAssets.Contains(disposable), "The disposable has already been recorded!");
+ // Avoid recording disposable objects twice. ReloadAsset will try to record the disposables again.
+ // We don't know which asset recorded which disposable so just guard against storing multiple of the same instance.
+ if (!disposableAssets.Contains(disposable))
+ disposableAssets.Add(disposable);
+ }
- // Store it for disposal later.
- disposableAssets.Add(disposable);
+ /// <summary>
+ /// Virtual property to allow a derived ContentManager to have it's assets reloaded
+ /// </summary>
+ protected virtual Dictionary<string, object> LoadedAssets
+ {
+ get { return loadedAssets; }
}
- protected void ReloadContent()
+ protected virtual void ReloadGraphicsAssets()
{
- foreach (var asset in loadedAssets)
+ foreach (var asset in LoadedAssets)
{
- ReloadAsset(asset.Key, asset.Value);
+ if (asset.Value is Texture2D)
+ {
+ ReloadAsset<Texture2D>(asset.Key, asset.Value as Texture2D);
+ }
+ else if (asset.Value is SpriteFont)
+ {
+ ReloadAsset<SpriteFont>(asset.Key, asset.Value as SpriteFont);
+ }
+ else if (asset.Value is Model)
+ {
+ ReloadAsset<Model>(asset.Key, asset.Value as Model);
+ }
+ // Not requried as we are recompiling them from cached source anyway - see EffectPass.RecompileAll().
+ //else if (asset.Value is Effect)
+ //{
+ // ReloadAsset<Effect>(asset.Key, asset.Value as Effect);
+ //}
}
}
-
- protected void ReloadAsset(string originalAssetName, object currentAsset)
+
+ protected virtual void ReloadAsset<T>(string originalAssetName, T currentAsset)
{
string assetName = originalAssetName;
if (string.IsNullOrEmpty(assetName))
@@ -517,16 +552,36 @@ protected void ReloadAsset(string originalAssetName, object currentAsset)
}
Stream stream = null;
- //bool loadXnb = false;
try
{
- //try load it traditionally
- stream = OpenStream(assetName);
- stream.Dispose();
+ //try load it traditionally
+ stream = OpenStream(assetName);
+
+ // Try to load as XNB file
+ try
+ {
+ using (BinaryReader xnbReader = new BinaryReader(stream))
+ {
+ using (ContentReader reader = GetContentReaderFromXnb(assetName, ref stream, xnbReader, null))
+ {
+ reader.InitializeTypeReaders();
+ reader.ReadObject<T>(currentAsset);
+ reader.ReadSharedResources();
+ }
+ }
+ }
+ finally
+ {
+ if (stream != null)
+ {
+ stream.Dispose();
+ }
+ }
}
catch (ContentLoadException)
{
- //MonoGame try to load as a non-content file
+ // Try to reload as a non-xnb file.
+ // Just textures supported for now.
assetName = TitleContainer.GetFilename(Path.Combine (_rootDirectory, assetName));
@@ -534,51 +589,15 @@ protected void ReloadAsset(string originalAssetName, object currentAsset)
{
assetName = Texture2DReader.Normalize(assetName);
}
- else if ((currentAsset is SpriteFont))
- {
- assetName = SpriteFontReader.Normalize(assetName);
- }
-#if !WINRT
- else if ((currentAsset is Song))
- {
- assetName = SongReader.Normalize(assetName);
- }
- else if ((currentAsset is SoundEffect))
- {
- assetName = SoundEffectReader.Normalize(assetName);
- }
- else if ((currentAsset is Video))
- {
- assetName = Video.Normalize(assetName);
- }
-#endif
- if (string.IsNullOrEmpty(assetName))
- {
- throw new ContentLoadException("Could not load " + originalAssetName + " asset!");
- }
-
- if ((currentAsset is Texture2D))
+
+ if (currentAsset is Texture2D)
{
- using (Stream assetStream = OpenStream(assetName))
+ using (Stream assetStream = TitleContainer.OpenStream(assetName))
{
var asset = currentAsset as Texture2D;
asset.Reload(assetStream);
}
}
- else if ((currentAsset is SpriteFont))
- {
- }
-#if !WINRT
- else if ((currentAsset is Song))
- {
- }
- else if ((currentAsset is SoundEffect))
- {
- }
- else if ((currentAsset is Video))
- {
- }
-#endif
}
}
@@ -590,7 +609,6 @@ public virtual void Unload()
if (disposable != null)
disposable.Dispose();
}
- RemoveContentManager(this);
disposableAssets.Clear();
loadedAssets.Clear();
}
View
43 MonoGame.Framework/Content/ContentReader.cs
@@ -94,8 +94,19 @@ public string AssetName
internal object ReadAsset<T>()
{
- object result = null;
+ InitializeTypeReaders();
+ // Read primary object
+ object result = ReadObject<T>();
+
+ // Read shared resources
+ ReadSharedResources();
+
+ return result;
+ }
+
+ internal void InitializeTypeReaders()
+ {
typeReaderManager = new ContentTypeReaderManager(this);
typeReaders = typeReaderManager.LoadAssetReaders();
foreach (ContentTypeReader r in typeReaders)
@@ -105,26 +116,13 @@ internal object ReadAsset<T>()
sharedResourceCount = Read7BitEncodedInt();
sharedResourceFixups = new List<KeyValuePair<int, Action<object>>>();
-
- // Read primary object
- int index = Read7BitEncodedInt();
- if (index > 0)
- {
- ContentTypeReader contentReader = typeReaders[index - 1];
- result = ReadObject<T>(contentReader);
- }
-
- // Read shared resources
- if (sharedResourceCount > 0)
- {
- ReadSharedResources(sharedResourceCount);
- }
-
- return result;
}
- void ReadSharedResources(int sharedResourceCount)
+ internal void ReadSharedResources()
{
+ if (sharedResourceCount <= 0)
+ return;
+
object[] sharedResources = new object[sharedResourceCount];
for (int i = 0; i < sharedResourceCount; ++i)
{
@@ -256,11 +254,12 @@ public T ReadObject<T>(ContentTypeReader typeReader)
public T ReadObject<T>(T existingInstance)
{
- ContentTypeReader typeReader = typeReaderManager.GetTypeReader(typeof(T));
- if (typeReader == null)
- throw new ContentLoadException(String.Format("Could not read object type " + typeof(T).Name));
+ int typeReaderIndex = Read7BitEncodedInt();
- var result = (T)typeReader.Read(this, existingInstance);
+ if (typeReaderIndex == 0)
+ return default(T);
+
+ var result = (T)typeReaders[typeReaderIndex - 1].Read(this, existingInstance);
RecordDisposable(result);
View
18 MonoGame.Framework/Content/ContentReaders/ModelReader.cs
@@ -160,7 +160,11 @@ protected internal override Model Read(ContentReader reader, Model existingInsta
for (uint j = 0; j < partCount; j++)
{
- ModelMeshPart part = new ModelMeshPart();
+ ModelMeshPart part;
+ if (existingInstance != null)
+ part = existingInstance.Meshes[i].MeshParts[(int)j];
+ else
+ part = new ModelMeshPart();
part.VertexOffset = reader.ReadInt32();
part.NumVertices = reader.ReadInt32();
@@ -188,6 +192,10 @@ protected internal override Model Read(ContentReader reader, Model existingInsta
}
+
+ if (existingInstance != null)
+ continue;
+
ModelMesh mesh = new ModelMesh(reader.GraphicsDevice, parts);
mesh.Name = name;
mesh.ParentBone = bones[parentBoneIndex];
@@ -196,6 +204,14 @@ protected internal override Model Read(ContentReader reader, Model existingInsta
meshes.Add(mesh);
}
+ if (existingInstance != null)
+ {
+ // Read past remaining data and return existing instance
+ ReadBoneReference(reader, boneCount);
+ reader.ReadObject<object>();
+ return existingInstance;
+ }
+
// Read the final pieces of model data.
var rootBoneIndex = ReadBoneReference(reader, boneCount);
View
45 MonoGame.Framework/Content/ContentReaders/SpriteFontReader.cs
@@ -49,19 +49,42 @@ internal static string Normalize(string fileName)
protected internal override SpriteFont Read(ContentReader input, SpriteFont existingInstance)
{
- Texture2D texture = input.ReadObject<Texture2D>();
- List<Rectangle> glyphs = input.ReadObject<List<Rectangle>>();
- List<Rectangle> cropping = input.ReadObject<List<Rectangle>>();
- List<char> charMap = input.ReadObject<List<char>>();
- int lineSpacing = input.ReadInt32();
- float spacing = input.ReadSingle();
- List<Vector3> kerning = input.ReadObject<List<Vector3>>();
- char? defaultCharacter = null;
- if (input.ReadBoolean())
+ if (existingInstance != null)
{
- defaultCharacter = new char?(input.ReadChar());
+ // Read the texture into the existing texture instance
+ input.ReadObject<Texture2D>(existingInstance._texture);
+
+ // discard the rest of the SpriteFont data as we are only reloading GPU resources for now
+ input.ReadObject<List<Rectangle>>();
+ input.ReadObject<List<Rectangle>>();
+ input.ReadObject<List<char>>();
+ input.ReadInt32();
+ input.ReadSingle();
+ input.ReadObject<List<Vector3>>();
+ if (input.ReadBoolean())
+ {
+ input.ReadChar();
+ }
+
+ return existingInstance;
+ }
+ else
+ {
+ // Create a fresh SpriteFont instance
+ Texture2D texture = input.ReadObject<Texture2D>();
+ List<Rectangle> glyphs = input.ReadObject<List<Rectangle>>();
+ List<Rectangle> cropping = input.ReadObject<List<Rectangle>>();
+ List<char> charMap = input.ReadObject<List<char>>();
+ int lineSpacing = input.ReadInt32();
+ float spacing = input.ReadSingle();
+ List<Vector3> kerning = input.ReadObject<List<Vector3>>();
+ char? defaultCharacter = null;
+ if (input.ReadBoolean())
+ {
+ defaultCharacter = new char?(input.ReadChar());
+ }
+ return new SpriteFont(texture, glyphs, cropping, charMap, lineSpacing, spacing, kerning, defaultCharacter);
}
- return new SpriteFont(texture, glyphs, cropping, charMap, lineSpacing, spacing, kerning, defaultCharacter);
}
}
}
View
5 MonoGame.Framework/Content/ContentReaders/Texture2DReader.cs
@@ -111,7 +111,10 @@ protected internal override Texture2D Read(ContentReader reader, Texture2D exist
break;
}
- texture = new Texture2D(reader.GraphicsDevice, width, height, levelCount > 1, convertedFormat);
+ if (existingInstance == null)
+ texture = new Texture2D(reader.GraphicsDevice, width, height, levelCount > 1, convertedFormat);
+ else
+ texture = existingInstance;
for (int level=0; level<levelCount; level++)
{
View
25 MonoGame.Framework/Graphics/Effect/DXShader.cs
@@ -36,10 +36,8 @@ internal class DXShader
public int ShaderHandle;
-#if DEBUG
- // We only keep around the GLSL code for debugging.
+ // We keep this around for recompiling on context lost and debugging.
private string _glslCode;
-#endif
private struct Attribute
{
@@ -87,7 +85,7 @@ private struct Sampler
private readonly Sampler[] _samplers;
private readonly int[] _cbuffers;
-
+
internal DXShader(GraphicsDevice device, BinaryReader reader)
{
var isVertexShader = reader.ReadBoolean();
@@ -138,7 +136,7 @@ internal DXShader(GraphicsDevice device, BinaryReader reader)
#endif // DIRECTX
#if OPENGL
- var glslCode = System.Text.Encoding.ASCII.GetString(shaderBytecode);
+ _glslCode = System.Text.Encoding.ASCII.GetString(shaderBytecode);
var attributeCount = (int)reader.ReadByte();
_attributes = new Attribute[attributeCount];
@@ -150,22 +148,23 @@ internal DXShader(GraphicsDevice device, BinaryReader reader)
_attributes[a].format = reader.ReadInt16();
}
-
+ CompileShader();
+
+#endif // OPENGL
+ }
+
+ internal void CompileShader()
+ {
Threading.BlockOnUIThread(() =>
{
ShaderHandle = GL.CreateShader(ShaderType);
#if GLES
- GL.ShaderSource(ShaderHandle, 1, new string[] { glslCode }, (int[])null);
+ GL.ShaderSource(ShaderHandle, 1, new string[] { _glslCode }, (int[])null);
#else
GL.ShaderSource(ShaderHandle, glslCode);
#endif
GL.CompileShader(ShaderHandle);
-#if DEBUG
- // When debugging store this for later inspection.
- _glslCode = glslCode;
-#endif
-
var compiled = 0;
#if GLES
GL.GetShader(ShaderHandle, ShaderParameter.CompileStatus, ref compiled);
@@ -193,8 +192,6 @@ internal DXShader(GraphicsDevice device, BinaryReader reader)
throw new InvalidOperationException("Shader Compilation Failed");
}
});
-
-#endif // OPENGL
}
#if OPENGL
View
17 MonoGame.Framework/Graphics/Effect/EffectPass.cs
@@ -45,6 +45,8 @@ public class EffectPass
static readonly float[] _posFixup = new float[4];
+
+
#endif // OPENGL
#if PSS
@@ -101,9 +103,24 @@ internal EffectPass(Effect effect, EffectPass cloneSource)
#endif
}
+ internal static List<EffectPass> AllEffectPasses = new List<EffectPass>();
+
+ internal static void RecompileAll()
+ {
+ foreach (var pass in AllEffectPasses)
+ {
+ pass._vertexShader.CompileShader();
+ pass._pixelShader.CompileShader();
+ pass.Initialize();
+ }
+ }
+
private void Initialize()
{
#if OPENGL
+ if (!AllEffectPasses.Contains(this))
+ AllEffectPasses.Add(this);
+
Threading.BlockOnUIThread(() =>
{
// TODO: Shouldn't we be calling GL.DeleteProgram() somewhere?
View
23 MonoGame.Framework/Graphics/GraphicsDevice.cs
@@ -911,17 +911,8 @@ public void Present(Rectangle? sourceRectangle, Rectangle? destinationRectangle,
public void Reset()
{
- _viewport.Width = DisplayMode.Width;
- _viewport.Height = DisplayMode.Height;
-
- if (ResourcesLost)
- {
- ContentManager.ReloadAllContent();
- ResourcesLost = false;
- }
-
- if(DeviceReset != null)
- DeviceReset(null, new EventArgs());
+ // Manually resetting the device is not currently supported.
+ throw new NotImplementedException();
}
public void Reset(Microsoft.Xna.Framework.Graphics.PresentationParameters presentationParameters)
@@ -934,6 +925,16 @@ public void Reset(Microsoft.Xna.Framework.Graphics.PresentationParameters presen
throw new NotImplementedException();
}
+ /// <summary>
+ /// Trigger the DeviceReset event to allow games to be notified of a device reset.
+ /// Currently internal to allow the various platforms to send the event at the appropriate time.
+ /// </summary>
+ internal void OnDeviceReset()
+ {
+ if (DeviceReset != null)
+ DeviceReset(this, EventArgs.Empty);
+ }
+
public Microsoft.Xna.Framework.Graphics.DisplayMode DisplayMode
{
get
View
2  MonoGame.Framework/Graphics/SpriteFont.cs
@@ -85,7 +85,7 @@ static class Errors
private readonly Dictionary<char, Glyph> _glyphs;
- private readonly Texture2D _texture;
+ internal readonly Texture2D _texture;
internal SpriteFont (
Texture2D texture, List<Rectangle> glyphBounds, List<Rectangle> cropping, List<char> characters,
View
37 MonoGame.Framework/Graphics/Texture2D.cs
@@ -685,6 +685,33 @@ public static Texture2D FromStream(GraphicsDevice graphicsDevice, Stream stream)
#endif
}
+ private void FillTextureFromStream(Stream stream)
+ {
+ // Work-around for "The program 'Mono' has exited with code 255 (0xff)."
+ // Based on http://stackoverflow.com/questions/7535503/mono-for-android-exit-code-255-on-bitmapfactory-decodestream
+ //Bitmap image = BitmapFactory.DecodeStream(stream);
+ Bitmap image = null;
+ using (MemoryStream memStream = new MemoryStream())
+ {
+ stream.CopyTo(memStream);
+ image = BitmapFactory.DecodeByteArray(memStream.GetBuffer(), 0, (int)memStream.Length);
+ }
+ var width = image.Width;
+ var height = image.Height;
+
+ int[] pixels = new int[width * height];
+ image.GetPixels(pixels, 0, width, 0, 0, width, height);
+
+ // Convert from ARGB to ABGR
+ for (int i = 0; i < width * height; ++i)
+ {
+ uint pixel = (uint)pixels[i];
+ pixels[i] = (int)((pixel & 0xFF00FF00) | ((pixel & 0x00FF0000) >> 16) | ((pixel & 0x000000FF) << 16));
+ }
+
+ this.SetData<int>(pixels);
+ }
+
public void SaveAsJpeg(Stream stream, int width, int height)
{
#if WINRT
@@ -733,6 +760,16 @@ private void SaveAsImage(Guid encoderId, Stream stream, int width, int height)
//What was this for again?
internal void Reload(Stream textureStream)
{
+ if (!GL.IsTexture(this.glTexture))
+ {
+#if IPHONE || ANDROID
+ GL.GenTextures(1, ref this.glTexture);
+#else
+ GL.GenTextures(1, out this.glTexture);
+#endif
+ }
+
+ FillTextureFromStream(textureStream);
}
#if ANDROID
Please sign in to comment.
Something went wrong with that request. Please try again.