/* * Copyright (c) 2007-2009 SlimDX Group * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ using System; using System.Collections.Generic; using System.Reflection; using System.Runtime.InteropServices; using System.Security.Permissions; using SlimDX; using SlimDX.Direct3D9; namespace SampleFramework { /// /// Manages aspects of the graphics device unique to Direct3D9. /// public class Direct3D9Manager { GraphicsDeviceManager manager; /// /// Gets the graphics device. /// /// The graphics device. #if TEST_Direct3D9Ex public DeviceEx Device //yyagi #else public DeviceCache Device #endif { get; internal set; } /// /// Initializes a new instance of the class. /// /// The parent manager. internal Direct3D9Manager(GraphicsDeviceManager manager) { this.manager = manager; } /// /// Creates a vertex declaration using the specified vertex type. /// /// Type of the vertex. /// The vertex declaration for the specified vertex type. [EnvironmentPermission(SecurityAction.LinkDemand)] public VertexDeclaration CreateVertexDeclaration(Type vertexType) { // ensure that we have a value type if (!vertexType.IsValueType) throw new InvalidOperationException("Vertex types must be value types."); // grab the list of elements in the vertex List objectAttributes = new List(); FieldInfo[] fields = vertexType.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); foreach (FieldInfo field in fields) { // check for the custom attribute VertexElementAttribute[] attributes = (VertexElementAttribute[])field.GetCustomAttributes(typeof(VertexElementAttribute), false); if (field.Name.Contains("<") && field.Name.Contains(">")) { // look up the property matching this field to see if it has the attribute int index1 = field.Name.IndexOf('<'); int index2 = field.Name.IndexOf('>'); // parse out the name string propertyName = field.Name.Substring(index1 + 1, index2 - index1 - 1); PropertyInfo property = vertexType.GetProperty(propertyName, field.FieldType); if (property != null) attributes = (VertexElementAttribute[])property.GetCustomAttributes(typeof(VertexElementAttribute), false); } if (attributes.Length == 1) { // add the attribute to the list attributes[0].Offset = Marshal.OffsetOf(vertexType, field.Name).ToInt32(); objectAttributes.Add(attributes[0]); } } // make sure we have at least one element if (objectAttributes.Count < 1) throw new InvalidOperationException("The vertex type must have at least one field or property marked with the VertexElement attribute."); // loop through the attributes and start building vertex elements List elements = new List(); Dictionary usages = new Dictionary(); foreach (VertexElementAttribute attribute in objectAttributes) { // check the current usage index if (!usages.ContainsKey(attribute.Usage)) usages.Add(attribute.Usage, 0); // advance the current usage count int index = usages[attribute.Usage]; usages[attribute.Usage]++; // create the element elements.Add(new VertexElement((short)attribute.Stream, (short)attribute.Offset, attribute.Type, attribute.Method, attribute.Usage, (byte)index)); } elements.Add(VertexElement.VertexDeclarationEnd); return new VertexDeclaration(Device.UnderlyingDevice, elements.ToArray()); } /// /// Creates a render target surface that is compatible with the current device settings. /// /// The width of the surface. /// The height of the surface. /// The newly created render target surface. public Texture CreateRenderTarget(int width, int height) { return new Texture(Device.UnderlyingDevice, width, height, 1, Usage.RenderTarget, manager.CurrentSettings.BackBufferFormat, Pool.Default); } /// /// Creates a resolve target for capturing the back buffer. /// /// The newly created resolve target. public Texture CreateResolveTarget() { return new Texture(Device.UnderlyingDevice, manager.ScreenWidth, manager.ScreenHeight, 1, Usage.RenderTarget, manager.CurrentSettings.BackBufferFormat, Pool.Default); } /// /// Resolves the current back buffer into a texture. /// /// The target texture. /// Thrown when the resolve process fails. public void ResolveBackBuffer(Texture target) { ResolveBackBuffer(target, 0); } /// /// Resolves the current back buffer into a texture. /// /// The target texture. /// The index of the back buffer. /// Thrown when the resolve process fails. public void ResolveBackBuffer(Texture target, int backBufferIndex) { // disable exceptions for this method bool storedThrow = Configuration.ThrowOnError; Configuration.ThrowOnError = false; Surface destination = null; try { // grab the current back buffer Surface backBuffer = Device.GetBackBuffer(0, backBufferIndex); if (backBuffer == null || Result.Last.IsFailure) throw new InvalidOperationException("Could not obtain back buffer surface."); // grab the destination surface destination = target.GetSurfaceLevel(0); if (destination == null || Result.Last.IsFailure) throw new InvalidOperationException("Could not obtain resolve target surface."); // first try to copy using linear filtering if (Device.StretchRectangle(backBuffer, destination, TextureFilter.Linear).IsFailure) { // that failed, so try with no filtering if (Device.StretchRectangle(backBuffer, destination, TextureFilter.None).IsFailure) { // that failed as well, so the last thing we can try is a load surface call if (Surface.FromSurface(destination, backBuffer, Filter.Default, 0).IsFailure) throw new InvalidOperationException("Could not copy surfaces."); } } } finally { if (destination != null) destination.Dispose(); Configuration.ThrowOnError = storedThrow; } } /// /// Resets the render target. /// public void ResetRenderTarget() { Surface backBuffer = Device.GetBackBuffer(0, 0); try { Device.SetRenderTarget(0, backBuffer); } finally { backBuffer.Dispose(); } } } }