#region License /* FNA - XNA4 Reimplementation for Desktop Platforms * Copyright 2009-2016 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; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Utilities; #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; } } internal GraphicsDevice GraphicsDevice { get { return this.graphicsDevice; } } #endregion #region Internal Variables internal int version; internal int sharedResourceCount; #endregion #region Private Variables private ContentManager contentManager; private Action recordDisposableObject; private ContentTypeReaderManager typeReaderManager; private GraphicsDevice graphicsDevice; private string assetName; private List>> sharedResourceFixups; private ContentTypeReader[] typeReaders; #endregion #region Internal Constructor internal ContentReader( ContentManager manager, Stream stream, GraphicsDevice graphicsDevice, string assetName, int version, Action recordDisposableObject ) : base(stream) { this.graphicsDevice = graphicsDevice; this.recordDisposableObject = recordDisposableObject; this.contentManager = manager; this.assetName = assetName; this.version = version; } #endregion #region Public Read Methods public T ReadExternalReference() { string externalReference = ReadString(); if (!String.IsNullOrEmpty(externalReference)) { return contentManager.Load(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() { return ReadObject(default(T)); } public T ReadObject(ContentTypeReader typeReader) { T result = (T) typeReader.Read(this, default(T)); RecordDisposable(result); return result; } public T ReadObject(T existingInstance) { return InnerReadObject(existingInstance); } public T ReadObject(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() { return (T) ReadRawObject(default(T)); } public T ReadRawObject(ContentTypeReader typeReader) { return (T) ReadRawObject(typeReader, default(T)); } public T ReadRawObject(T existingInstance) { Type objectType = typeof(T); foreach (ContentTypeReader typeReader in typeReaders) { if (typeReader.TargetType == objectType) { return (T) ReadRawObject(typeReader,existingInstance); } } throw new NotSupportedException(); } public T ReadRawObject(ContentTypeReader typeReader, T existingInstance) { return (T) typeReader.Read(this, existingInstance); } public void ReadSharedResource(Action fixup) { int index = Read7BitEncodedInt(); if (index > 0) { sharedResourceFixups.Add( new KeyValuePair> ( index - 1, 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() { InitializeTypeReaders(); // Read primary object object result = ReadObject(); // Read shared resources ReadSharedResources(); return result; } internal void InitializeTypeReaders() { typeReaderManager = new ContentTypeReaderManager(); typeReaders = typeReaderManager.LoadAssetReaders(this); sharedResourceCount = Read7BitEncodedInt(); sharedResourceFixups = new List>>(); } internal void ReadSharedResources() { if (sharedResourceCount <= 0) { return; } object[] sharedResources = new object[sharedResourceCount]; for (int i = 0; i < sharedResourceCount; i += 1) { sharedResources[i] = InnerReadObject(null); } // Fixup shared resources by calling each registered action foreach (KeyValuePair> fixup in sharedResourceFixups) { fixup.Value(sharedResources[fixup.Key]); } } 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 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 result) { IDisposable disposable = result as IDisposable; if (disposable == null) { return; } if (recordDisposableObject != null) { recordDisposableObject(disposable); } else { contentManager.RecordDisposable(disposable); } } #endregion } }