Show More
Commit Description:
Various UI improvements.
Commit Description:
Various UI improvements.
References:
File last commit:
Show/Diff file:
Action:
FNA/src/Content/ContentReader.cs
360 lines | 7.7 KiB | text/x-csharp | CSharpLexer
360 lines | 7.7 KiB | text/x-csharp | CSharpLexer
r0 | #region License | |||
/* FNA - XNA4 Reimplementation for Desktop Platforms | ||||
* Copyright 2009-2020 Ethan Lee and the MonoGame Team | ||||
* | ||||
* Released under the Microsoft Public License. | ||||
* See LICENSE for details. | ||||
*/ | ||||
/* Derived from code by the Mono.Xna Team (Copyright 2006). | ||||
* Released under the MIT License. See monoxna.LICENSE for details. | ||||
*/ | ||||
#endregion | ||||
#region Using Statements | ||||
using System; | ||||
using System.Collections.Generic; | ||||
using System.IO; | ||||
#endregion | ||||
namespace Microsoft.Xna.Framework.Content | ||||
{ | ||||
public sealed class ContentReader : BinaryReader | ||||
{ | ||||
#region Public Properties | ||||
public ContentManager ContentManager | ||||
{ | ||||
get | ||||
{ | ||||
return contentManager; | ||||
} | ||||
} | ||||
public string AssetName | ||||
{ | ||||
get | ||||
{ | ||||
return assetName; | ||||
} | ||||
} | ||||
#endregion | ||||
#region Internal Properties | ||||
internal ContentTypeReader[] TypeReaders | ||||
{ | ||||
get | ||||
{ | ||||
return typeReaders; | ||||
} | ||||
} | ||||
#endregion | ||||
#region Internal Variables | ||||
internal int version; | ||||
internal char platform; | ||||
#endregion | ||||
#region Private Variables | ||||
private ContentManager contentManager; | ||||
private Action<IDisposable> recordDisposableObject; | ||||
private ContentTypeReaderManager typeReaderManager; | ||||
private ContentTypeReader[] typeReaders; | ||||
private string assetName; | ||||
/* From what I can tell, shared resources work like this: | ||||
* A list of shared resources is stored at the end of the file, | ||||
* and while we're reading the whole object, the parts that ask | ||||
* for "shared" objects store the 1-based index of the shared | ||||
* resource in the list. For example, if there are two shared | ||||
* resources, a ReadSharedResource function will ask for either | ||||
* 1 or 2. For null references, the index will be 0. | ||||
*/ | ||||
private int sharedResourceCount; | ||||
private List<Action<object>>[] sharedResourceFixups; | ||||
#endregion | ||||
#region Internal Constructor | ||||
internal ContentReader( | ||||
ContentManager manager, | ||||
Stream stream, | ||||
string assetName, | ||||
int version, | ||||
char platform, | ||||
Action<IDisposable> recordDisposableObject | ||||
) : base(stream) { | ||||
this.recordDisposableObject = recordDisposableObject; | ||||
this.contentManager = manager; | ||||
this.assetName = assetName; | ||||
this.version = version; | ||||
this.platform = platform; | ||||
} | ||||
#endregion | ||||
#region Public Read Methods | ||||
public T ReadExternalReference<T>() | ||||
{ | ||||
string externalReference = ReadString(); | ||||
if (!String.IsNullOrEmpty(externalReference)) | ||||
{ | ||||
return contentManager.Load<T>( | ||||
MonoGame.Utilities.FileHelpers.ResolveRelativePath(assetName, externalReference) | ||||
); | ||||
} | ||||
return default(T); | ||||
} | ||||
public Matrix ReadMatrix() | ||||
{ | ||||
Matrix result = new Matrix(); | ||||
result.M11 = ReadSingle(); | ||||
result.M12 = ReadSingle(); | ||||
result.M13 = ReadSingle(); | ||||
result.M14 = ReadSingle(); | ||||
result.M21 = ReadSingle(); | ||||
result.M22 = ReadSingle(); | ||||
result.M23 = ReadSingle(); | ||||
result.M24 = ReadSingle(); | ||||
result.M31 = ReadSingle(); | ||||
result.M32 = ReadSingle(); | ||||
result.M33 = ReadSingle(); | ||||
result.M34 = ReadSingle(); | ||||
result.M41 = ReadSingle(); | ||||
result.M42 = ReadSingle(); | ||||
result.M43 = ReadSingle(); | ||||
result.M44 = ReadSingle(); | ||||
return result; | ||||
} | ||||
public T ReadObject<T>() | ||||
{ | ||||
return ReadObject(default(T)); | ||||
} | ||||
public T ReadObject<T>(ContentTypeReader typeReader) | ||||
{ | ||||
T result = (T) typeReader.Read(this, default(T)); | ||||
RecordDisposable(result); | ||||
return result; | ||||
} | ||||
public T ReadObject<T>(T existingInstance) | ||||
{ | ||||
return InnerReadObject(existingInstance); | ||||
} | ||||
public T ReadObject<T>(ContentTypeReader typeReader, T existingInstance) | ||||
{ | ||||
if (!typeReader.TargetType.IsValueType) | ||||
{ | ||||
return ReadObject(existingInstance); | ||||
} | ||||
T result = (T) typeReader.Read(this, existingInstance); | ||||
RecordDisposable(result); | ||||
return result; | ||||
} | ||||
public Quaternion ReadQuaternion() | ||||
{ | ||||
Quaternion result = new Quaternion(); | ||||
result.X = ReadSingle(); | ||||
result.Y = ReadSingle(); | ||||
result.Z = ReadSingle(); | ||||
result.W = ReadSingle(); | ||||
return result; | ||||
} | ||||
public T ReadRawObject<T>() | ||||
{ | ||||
return (T) ReadRawObject<T>(default(T)); | ||||
} | ||||
public T ReadRawObject<T>(ContentTypeReader typeReader) | ||||
{ | ||||
return (T) ReadRawObject<T>(typeReader, default(T)); | ||||
} | ||||
public T ReadRawObject<T>(T existingInstance) | ||||
{ | ||||
Type objectType = typeof(T); | ||||
foreach (ContentTypeReader typeReader in typeReaders) | ||||
{ | ||||
if (typeReader.TargetType == objectType) | ||||
{ | ||||
return (T) ReadRawObject<T>(typeReader,existingInstance); | ||||
} | ||||
} | ||||
throw new NotSupportedException(); | ||||
} | ||||
public T ReadRawObject<T>(ContentTypeReader typeReader, T existingInstance) | ||||
{ | ||||
return (T) typeReader.Read(this, existingInstance); | ||||
} | ||||
public void ReadSharedResource<T>(Action<T> fixup) | ||||
{ | ||||
int index = Read7BitEncodedInt(); | ||||
if (index > 0) | ||||
{ | ||||
sharedResourceFixups[index - 1].Add( | ||||
delegate(object v) | ||||
{ | ||||
if (!(v is T)) | ||||
{ | ||||
throw new ContentLoadException( | ||||
String.Format( | ||||
"Error loading shared resource. Expected type {0}, received type {1}", | ||||
typeof(T).Name, v.GetType().Name | ||||
) | ||||
); | ||||
} | ||||
fixup((T) v); | ||||
} | ||||
); | ||||
} | ||||
} | ||||
public Vector2 ReadVector2() | ||||
{ | ||||
Vector2 result = new Vector2(); | ||||
result.X = ReadSingle(); | ||||
result.Y = ReadSingle(); | ||||
return result; | ||||
} | ||||
public Vector3 ReadVector3() | ||||
{ | ||||
Vector3 result = new Vector3(); | ||||
result.X = ReadSingle(); | ||||
result.Y = ReadSingle(); | ||||
result.Z = ReadSingle(); | ||||
return result; | ||||
} | ||||
public Vector4 ReadVector4() | ||||
{ | ||||
Vector4 result = new Vector4(); | ||||
result.X = ReadSingle(); | ||||
result.Y = ReadSingle(); | ||||
result.Z = ReadSingle(); | ||||
result.W = ReadSingle(); | ||||
return result; | ||||
} | ||||
public Color ReadColor() | ||||
{ | ||||
Color result = new Color(); | ||||
result.R = ReadByte(); | ||||
result.G = ReadByte(); | ||||
result.B = ReadByte(); | ||||
result.A = ReadByte(); | ||||
return result; | ||||
} | ||||
#endregion | ||||
#region Internal Methods | ||||
internal object ReadAsset<T>() | ||||
{ | ||||
InitializeTypeReaders(); | ||||
// Read primary object | ||||
object result = ReadObject<T>(); | ||||
// Read shared resources | ||||
ReadSharedResources(); | ||||
return result; | ||||
} | ||||
internal void InitializeTypeReaders() | ||||
{ | ||||
typeReaderManager = new ContentTypeReaderManager(); | ||||
typeReaders = typeReaderManager.LoadAssetReaders(this); | ||||
sharedResourceCount = Read7BitEncodedInt(); | ||||
sharedResourceFixups = new List<Action<object>>[sharedResourceCount]; | ||||
for (int i = 0; i < sharedResourceCount; i += 1) | ||||
{ | ||||
sharedResourceFixups[i] = new List<Action<object>>(); | ||||
} | ||||
} | ||||
internal void ReadSharedResources() | ||||
{ | ||||
for (int i = 0; i < sharedResourceCount; i += 1) | ||||
{ | ||||
// Load the shared object... | ||||
object sharedResource = InnerReadObject<object>(null); | ||||
// ... then send it to each ReadSharedResource caller | ||||
foreach (Action<object> fixup in sharedResourceFixups[i]) | ||||
{ | ||||
fixup(sharedResource); | ||||
} | ||||
} | ||||
} | ||||
internal new int Read7BitEncodedInt() | ||||
{ | ||||
return base.Read7BitEncodedInt(); | ||||
} | ||||
internal BoundingSphere ReadBoundingSphere() | ||||
{ | ||||
Vector3 position = ReadVector3(); | ||||
float radius = ReadSingle(); | ||||
return new BoundingSphere(position, radius); | ||||
} | ||||
#endregion | ||||
#region Private Methods | ||||
private T InnerReadObject<T>(T existingInstance) | ||||
{ | ||||
int typeReaderIndex = Read7BitEncodedInt(); | ||||
if (typeReaderIndex == 0) | ||||
{ | ||||
return existingInstance; | ||||
} | ||||
if (typeReaderIndex > typeReaders.Length) | ||||
{ | ||||
throw new ContentLoadException( | ||||
"Incorrect type reader index found!" | ||||
); | ||||
} | ||||
ContentTypeReader typeReader = typeReaders[typeReaderIndex - 1]; | ||||
T result = (T) typeReader.Read(this, default(T)); | ||||
RecordDisposable(result); | ||||
return result; | ||||
} | ||||
private void RecordDisposable<T>(T result) | ||||
{ | ||||
IDisposable disposable = result as IDisposable; | ||||
if (disposable == null) | ||||
{ | ||||
return; | ||||
} | ||||
if (recordDisposableObject != null) | ||||
{ | ||||
recordDisposableObject(disposable); | ||||
} | ||||
else | ||||
{ | ||||
contentManager.RecordDisposable(disposable); | ||||
} | ||||
} | ||||
#endregion | ||||
} | ||||
} | ||||