235 lines
7.6 KiB
C#
235 lines
7.6 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using Aiwaz.Contracts;
|
|
using System.Runtime.InteropServices;
|
|
using Aiwaz.Core;
|
|
using System.Collections.ObjectModel;
|
|
|
|
namespace Aiwaz.Resources
|
|
{
|
|
[AiwazResource("SwapChain", "An output target for render operations, the output could be displayed directly into a window.")]
|
|
public class SwapChain : RenderTarget, ISwapChain
|
|
{
|
|
[DllImport("user32.dll")]
|
|
static extern bool GetClientRect(IntPtr hWnd, out RECT lpRect);
|
|
[Serializable, StructLayout(LayoutKind.Sequential)]
|
|
private struct RECT
|
|
{
|
|
public int Left;
|
|
public int Top;
|
|
public int Right;
|
|
public int Bottom;
|
|
|
|
public RECT(int left_, int top_, int right_, int bottom_)
|
|
{
|
|
Left = left_;
|
|
Top = top_;
|
|
Right = right_;
|
|
Bottom = bottom_;
|
|
}
|
|
|
|
public int Height { get { return Bottom - Top; } }
|
|
public int Width { get { return Right - Left; } }
|
|
}
|
|
|
|
|
|
private SlimDX.DXGI.SwapChainDescription swapChainDescription;
|
|
private SlimDX.DXGI.SwapChain swapChain;
|
|
|
|
public SwapChain(IntPtr windowHandle)
|
|
: this(windowHandle, 0, 0, 0, SlimDX.DXGI.Format.Unknown, 0, 0)
|
|
{
|
|
}
|
|
|
|
public SwapChain(IntPtr windowHandle, int width, int height, int refreshRate, SlimDX.DXGI.Format format)
|
|
: this (windowHandle, width, height, refreshRate, format, 0, 0)
|
|
{
|
|
}
|
|
|
|
public SwapChain(IntPtr windowHandle, int width, int height, int refreshRate, SlimDX.DXGI.Format format, int multiSampleCount, int multiSampleQuality)
|
|
: base()
|
|
{
|
|
VSync = true;
|
|
|
|
// get missing information
|
|
if (multiSampleCount <= 0)
|
|
multiSampleCount = 1;
|
|
if (width == 0 || height == 0)
|
|
{
|
|
RECT windowRect = new RECT();
|
|
GetClientRect(windowHandle, out windowRect);
|
|
if (width == 0)
|
|
width = windowRect.Right - windowRect.Left;
|
|
if (height == 0)
|
|
height = windowRect.Bottom - windowRect.Top;
|
|
}
|
|
if (refreshRate == 0)
|
|
refreshRate = 60; // 60Hz
|
|
if (format == SlimDX.DXGI.Format.Unknown)
|
|
format = SlimDX.DXGI.Format.R8G8B8A8_UNorm; // RGBA(X) 8Bit per channel -> 32Bit
|
|
|
|
swapChainDescription = new SlimDX.DXGI.SwapChainDescription()
|
|
{
|
|
BufferCount = 1,
|
|
Usage = SlimDX.DXGI.Usage.RenderTargetOutput,
|
|
OutputHandle = windowHandle,
|
|
IsWindowed = true,
|
|
ModeDescription = new SlimDX.DXGI.ModeDescription()
|
|
{
|
|
Width = width,
|
|
Height = height,
|
|
Format = (SlimDX.DXGI.Format)format,
|
|
RefreshRate = new SlimDX.Rational(refreshRate, 1)
|
|
},
|
|
SampleDescription = new SlimDX.DXGI.SampleDescription()
|
|
{
|
|
Count = multiSampleCount,
|
|
Quality = multiSampleQuality
|
|
}
|
|
};
|
|
|
|
this.multiSampleCount = multiSampleCount;
|
|
this.multiSampleQuality = multiSampleQuality;
|
|
|
|
Console.WriteLine(string.Format("Creating SwapChain ({0}x{1}x{2} {3})..", width, height, refreshRate, format.ToString()));
|
|
|
|
swapChain = new SlimDX.DXGI.SwapChain(Engine.Factory, Engine.Device, swapChainDescription);
|
|
if (swapChain == null)
|
|
throw new InitializingFailedException(this.GetType().Name, "Unable to create internal swap chain.");
|
|
|
|
this.RetriveData();
|
|
|
|
this.ViewPort = new ViewPort()
|
|
{
|
|
Width = width,
|
|
Height = height
|
|
};
|
|
}
|
|
|
|
public override int RenderTargetWidth
|
|
{
|
|
get { return swapChainDescription.ModeDescription.Width; }
|
|
}
|
|
|
|
public override int RenderTargetHeight
|
|
{
|
|
get { return swapChainDescription.ModeDescription.Height; }
|
|
}
|
|
|
|
public override SlimDX.DXGI.Format RenderTargetFormat
|
|
{
|
|
get { return swapChainDescription.ModeDescription.Format; }
|
|
}
|
|
|
|
#region ISwapChain Members
|
|
|
|
public void Resize(int width, int height)
|
|
{
|
|
if (width <= 0 || height <= 0)
|
|
{
|
|
RECT windowRect = new RECT();
|
|
GetClientRect(swapChainDescription.OutputHandle, out windowRect);
|
|
if (width <= 0)
|
|
width = windowRect.Right - windowRect.Left;
|
|
if (height <= 0)
|
|
height = windowRect.Bottom - windowRect.Top;
|
|
}
|
|
|
|
if (swapChainDescription.ModeDescription.Width == width &&
|
|
swapChainDescription.ModeDescription.Height == height)
|
|
return;
|
|
|
|
var depthStencilBuffer = this.HasDepthStencilBuffer;
|
|
|
|
Engine.Device.ClearState();
|
|
|
|
this.HasDepthStencilBuffer = false;
|
|
|
|
if (this.DX10RenderTargetView != null)
|
|
this.DX10RenderTargetView.Dispose();
|
|
this.DX10RenderTargetView = null;
|
|
|
|
swapChain.ResizeBuffers(swapChainDescription.BufferCount, width, height, swapChainDescription.ModeDescription.Format, SlimDX.DXGI.SwapChainFlags.AllowModeSwitch);
|
|
var desc = swapChainDescription.ModeDescription;
|
|
desc.Width = width;
|
|
desc.Height = height;
|
|
swapChainDescription.ModeDescription = desc;
|
|
this.RetriveData();
|
|
|
|
this.HasDepthStencilBuffer = depthStencilBuffer;
|
|
|
|
this.ViewPort = new ViewPort()
|
|
{
|
|
Width = width,
|
|
Height = height
|
|
};
|
|
}
|
|
|
|
public void Present()
|
|
{
|
|
swapChain.Present(VSync ? 1 : 0, SlimDX.DXGI.PresentFlags.None);
|
|
}
|
|
|
|
public bool Fullscreen
|
|
{
|
|
get { return !swapChainDescription.IsWindowed; }
|
|
set
|
|
{
|
|
if (swapChainDescription.IsWindowed == !value)
|
|
return;
|
|
swapChainDescription.IsWindowed = !value;
|
|
|
|
var hasDepthStencilBuffer = this.HasDepthStencilBuffer;
|
|
Engine.Device.ClearState();
|
|
this.HasDepthStencilBuffer = false;
|
|
|
|
if (this.DX10RenderTargetView != null)
|
|
this.DX10RenderTargetView.Dispose();
|
|
this.DX10RenderTargetView = null;
|
|
|
|
swapChain.SetFullScreenState(value, Engine.DeviceEnumerator.FindBestOutput(false).Output);
|
|
this.RetriveData();
|
|
|
|
this.HasDepthStencilBuffer = hasDepthStencilBuffer;
|
|
}
|
|
}
|
|
|
|
public bool VSync { get; set; }
|
|
|
|
private void RetriveData()
|
|
{
|
|
using (var backbufferTexture = SlimDX.Direct3D10.Texture2D.FromSwapChain<SlimDX.Direct3D10.Texture2D>(swapChain, 0))
|
|
{
|
|
DX10RenderTargetView = new SlimDX.Direct3D10.RenderTargetView(Engine.Device, backbufferTexture);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region IDisposable Members
|
|
|
|
public override void Dispose()
|
|
{
|
|
if (swapChain != null)
|
|
swapChain.Dispose();
|
|
swapChain = null;
|
|
|
|
base.Dispose();
|
|
}
|
|
|
|
#endregion
|
|
|
|
public override ICreationParams CreationParams
|
|
{
|
|
get { return null; }
|
|
}
|
|
|
|
public override ObservableCollection<IResource> Children
|
|
{
|
|
get { return null; }
|
|
}
|
|
}
|
|
}
|