mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-10-06 12:37:28 -04:00

Managed pool places data in both video and system memory. By only using the default pool, we only store data in video memory (at the cost of needing to recreate vertex buffers whenever the context is lost). This also means the client will crash whenever it runs out of video memory.. but really if that happens, you are likely stuffed anyway. I think the tradeoff is worth it. I'll also unload far away chunks to reduce video memory usage.
629 lines
22 KiB
C#
629 lines
22 KiB
C#
// ClassicalSharp copyright 2014-2016 UnknownShadow200 | Licensed under MIT
|
|
#if USE_DX && !ANDROID
|
|
using System;
|
|
using System.Drawing;
|
|
using System.Drawing.Imaging;
|
|
using System.Threading;
|
|
using OpenTK;
|
|
using SharpDX;
|
|
using SharpDX.Direct3D9;
|
|
using D3D = SharpDX.Direct3D9;
|
|
using WinWindowInfo = OpenTK.Platform.Windows.WinWindowInfo;
|
|
|
|
namespace ClassicalSharp.GraphicsAPI {
|
|
|
|
/// <summary> Implements IGraphicsAPI using Direct3D 9. </summary>
|
|
public class Direct3D9Api : IGraphicsApi {
|
|
|
|
Device device;
|
|
Direct3D d3d;
|
|
Capabilities caps;
|
|
const int texBufferSize = 512, iBufferSize = 32, vBufferSize = 2048;
|
|
|
|
D3D.Texture[] textures = new D3D.Texture[texBufferSize];
|
|
DataBuffer[] vBuffers = new DataBuffer[vBufferSize];
|
|
DynamicDataBuffer[] dynamicvBuffers = new DynamicDataBuffer[iBufferSize];
|
|
DataBuffer[] iBuffers = new DataBuffer[iBufferSize];
|
|
|
|
MatrixStack viewStack, projStack, texStack, curStack;
|
|
PrimitiveType[] modeMappings;
|
|
Format[] depthFormats, viewFormats;
|
|
Format depthFormat, viewFormat;
|
|
CreateFlags createFlags = CreateFlags.HardwareVertexProcessing;
|
|
|
|
public Direct3D9Api( Game game ) {
|
|
MinZNear = 0.05f;
|
|
IntPtr windowHandle = ((WinWindowInfo)game.window.WindowInfo).WindowHandle;
|
|
d3d = new Direct3D();
|
|
int adapter = d3d.Adapters[0].Adapter;
|
|
InitFields();
|
|
FindCompatibleFormat( adapter );
|
|
|
|
PresentParameters args = GetPresentArgs( 640, 480 );
|
|
try {
|
|
device = d3d.CreateDevice( adapter, DeviceType.Hardware, windowHandle, createFlags, args );
|
|
} catch( SharpDXException ) {
|
|
createFlags = CreateFlags.MixedVertexProcessing;
|
|
try {
|
|
device = d3d.CreateDevice( adapter, DeviceType.Hardware, windowHandle, createFlags, args );
|
|
} catch ( SharpDXException ) {
|
|
createFlags = CreateFlags.SoftwareVertexProcessing;
|
|
device = d3d.CreateDevice( adapter, DeviceType.Hardware, windowHandle, createFlags, args );
|
|
}
|
|
}
|
|
|
|
caps = device.Capabilities;
|
|
viewStack = new MatrixStack( 32, device, TransformState.View );
|
|
projStack = new MatrixStack( 4, device, TransformState.Projection );
|
|
texStack = new MatrixStack( 4, device, TransformState.Texture0 );
|
|
SetDefaultRenderStates();
|
|
InitDynamicBuffers();
|
|
}
|
|
|
|
void FindCompatibleFormat( int adapter ) {
|
|
for( int i = 0; i < viewFormats.Length; i++ ) {
|
|
viewFormat = viewFormats[i];
|
|
if( d3d.CheckDeviceType( adapter, DeviceType.Hardware, viewFormat, viewFormat, true ) ) break;
|
|
|
|
if( i == viewFormats.Length - 1 )
|
|
throw new InvalidOperationException( "Unable to create a back buffer with sufficient precision." );
|
|
}
|
|
|
|
for( int i = 0; i < depthFormats.Length; i++ ) {
|
|
depthFormat = depthFormats[i];
|
|
if( d3d.CheckDepthStencilMatch( adapter, DeviceType.Hardware, viewFormat, viewFormat, depthFormat ) ) break;
|
|
|
|
if( i == depthFormats.Length - 1 )
|
|
throw new InvalidOperationException( "Unable to create a depth buffer with sufficient precision." );
|
|
}
|
|
}
|
|
|
|
bool alphaTest, alphaBlend;
|
|
public override bool AlphaTest {
|
|
set { if( value == alphaTest ) return;
|
|
alphaTest = value; device.SetRenderState( RenderState.AlphaTestEnable, value );
|
|
}
|
|
}
|
|
|
|
public override bool AlphaBlending {
|
|
set { if( value == alphaBlend ) return;
|
|
alphaBlend = value; device.SetRenderState( RenderState.AlphaBlendEnable, value );
|
|
}
|
|
}
|
|
|
|
Compare[] compareFuncs;
|
|
Compare alphaTestFunc;
|
|
int alphaTestRef;
|
|
public override void AlphaTestFunc( CompareFunc func, float value ) {
|
|
alphaTestFunc = compareFuncs[(int)func];
|
|
device.SetRenderState( RenderState.AlphaFunc, (int)alphaTestFunc );
|
|
alphaTestRef = (int)( value * 255 );
|
|
device.SetRenderState( RenderState.AlphaRef, alphaTestRef );
|
|
}
|
|
|
|
Blend[] blendFuncs;
|
|
Blend srcBlendFunc, dstBlendFunc;
|
|
public override void AlphaBlendFunc( BlendFunc srcFunc, BlendFunc dstFunc ) {
|
|
srcBlendFunc = blendFuncs[(int)srcFunc];
|
|
dstBlendFunc = blendFuncs[(int)dstFunc];
|
|
device.SetRenderState( RenderState.SourceBlend, (int)srcBlendFunc );
|
|
device.SetRenderState( RenderState.DestinationBlend, (int)dstBlendFunc );
|
|
}
|
|
|
|
bool fogEnable;
|
|
public override bool Fog {
|
|
set { if( value == fogEnable ) return;
|
|
fogEnable = value; device.SetRenderState( RenderState.FogEnable, value );
|
|
}
|
|
}
|
|
|
|
int fogCol;
|
|
public override void SetFogColour( FastColour col ) {
|
|
fogCol = col.ToArgb();
|
|
device.SetRenderState( RenderState.FogColor, fogCol );
|
|
}
|
|
|
|
float fogDensity = -1, fogStart = -1, fogEnd = -1;
|
|
public override void SetFogDensity( float value ) {
|
|
if( value == fogDensity ) return;
|
|
fogDensity = value;
|
|
device.SetRenderState( RenderState.FogDensity, value );
|
|
}
|
|
|
|
public override void SetFogStart( float value ) {
|
|
device.SetRenderState( RenderState.FogStart, value );
|
|
}
|
|
|
|
public override void SetFogEnd( float value ) {
|
|
if( value == fogEnd ) return;
|
|
fogEnd = value;
|
|
device.SetRenderState( RenderState.FogEnd, value );
|
|
}
|
|
|
|
FogMode[] modes;
|
|
FogMode fogTableMode;
|
|
public override void SetFogMode( Fog fogMode ) {
|
|
FogMode newMode = modes[(int)fogMode];
|
|
if( newMode == fogTableMode ) return;
|
|
fogTableMode = newMode;
|
|
device.SetRenderState( RenderState.FogTableMode, (int)fogTableMode );
|
|
}
|
|
|
|
public override bool FaceCulling {
|
|
set {
|
|
Cull mode = value ? Cull.Clockwise : Cull.None;
|
|
device.SetRenderState( RenderState.CullMode, (int)mode );
|
|
}
|
|
}
|
|
|
|
public override int MaxTextureDimensions {
|
|
get { return Math.Min( caps.MaxTextureHeight, caps.MaxTextureWidth ); }
|
|
}
|
|
|
|
public override bool Texturing {
|
|
set { if( !value ) device.SetTexture( 0, null ); }
|
|
}
|
|
|
|
public override int CreateTexture( int width, int height, IntPtr scan0 ) {
|
|
D3D.Texture texture = device.CreateTexture( width, height, 0, Usage.None, Format.A8R8G8B8, Pool.Managed );
|
|
texture.SetData( 0, LockFlags.None, scan0, width * height * 4 );
|
|
return GetOrExpand( ref textures, texture, texBufferSize );
|
|
}
|
|
|
|
public override void UpdateTexturePart( int texId, int texX, int texY, FastBitmap part ) {
|
|
D3D.Texture texture = textures[texId];
|
|
texture.SetPartData( 0, LockFlags.None, part.Scan0, texX, texY, part.Width, part.Height );
|
|
}
|
|
|
|
public override void BindTexture( int texId ) {
|
|
device.SetTexture( 0, textures[texId] );
|
|
}
|
|
|
|
public override void DeleteTexture( ref int texId ) {
|
|
Delete( textures, ref texId );
|
|
}
|
|
|
|
int lastClearCol;
|
|
public override void Clear() {
|
|
device.Clear( ClearFlags.Target | ClearFlags.ZBuffer, lastClearCol, 1f, 0 );
|
|
}
|
|
|
|
public override void ClearColour( FastColour col ) {
|
|
lastClearCol = col.ToArgb();
|
|
}
|
|
|
|
public override bool ColourWrite {
|
|
set { device.SetRenderState( RenderState.ColorWriteEnable, value ? 0xF : 0x0 ); }
|
|
}
|
|
|
|
Compare depthTestFunc;
|
|
public override void DepthTestFunc( CompareFunc func ) {
|
|
depthTestFunc = compareFuncs[(int)func];
|
|
device.SetRenderState( RenderState.ZFunc, (int)depthTestFunc );
|
|
}
|
|
|
|
bool depthTest, depthWrite;
|
|
public override bool DepthTest {
|
|
set { depthTest = value; device.SetRenderState( RenderState.ZEnable, value ); }
|
|
}
|
|
|
|
public override bool DepthWrite {
|
|
set { depthWrite = value; device.SetRenderState( RenderState.ZWriteEnable, value ); }
|
|
}
|
|
|
|
public override bool AlphaArgBlend {
|
|
set {
|
|
TextureOp op = value ? TextureOp.Modulate : TextureOp.SelectArg1;
|
|
device.SetTextureStageState( 0, TextureStage.AlphaOperation, (int)op );
|
|
}
|
|
}
|
|
|
|
#region Vertex buffers
|
|
|
|
public override int CreateDynamicVb( VertexFormat format, int maxVertices ) {
|
|
int size = maxVertices * strideSizes[(int)format];
|
|
DynamicDataBuffer buffer = device.CreateDynamicVertexBuffer( size, formatMapping[(int)format] );
|
|
|
|
buffer.Format = formatMapping[(int)format];
|
|
buffer.MaxSize = size;
|
|
return GetOrExpand( ref dynamicvBuffers, buffer, iBufferSize );
|
|
}
|
|
|
|
public override void UpdateDynamicVb<T>( DrawMode mode, int vb, T[] vertices, int count ) {
|
|
int size = count * batchStride;
|
|
DataBuffer buffer = dynamicvBuffers[vb];
|
|
buffer.SetData( vertices, size, LockFlags.Discard );
|
|
|
|
device.SetStreamSource( 0, buffer, 0, batchStride );
|
|
device.DrawPrimitives( modeMappings[(int)mode], 0, NumPrimitives( count, mode ) );
|
|
}
|
|
|
|
public override void UpdateDynamicIndexedVb<T>( DrawMode mode, int vb, T[] vertices, int vCount, int indicesCount ) {
|
|
int size = vCount * batchStride;
|
|
DataBuffer buffer = dynamicvBuffers[vb];
|
|
buffer.SetData( vertices, size, LockFlags.Discard );
|
|
|
|
device.SetStreamSource( 0, buffer, 0, batchStride );
|
|
device.DrawIndexedPrimitives( modeMappings[(int)mode], 0, 0,
|
|
indicesCount / 6 * 4, 0, NumPrimitives( indicesCount, mode ) );
|
|
}
|
|
|
|
public override void SetDynamicVbData<T>( int vb, T[] vertices, int count ) {
|
|
int size = count * batchStride;
|
|
DataBuffer buffer = dynamicvBuffers[vb];
|
|
buffer.SetData( vertices, size, LockFlags.Discard );
|
|
device.SetStreamSource( 0, buffer, 0, batchStride );
|
|
}
|
|
|
|
public override void DeleteDynamicVb( ref int vb ) {
|
|
Delete( dynamicvBuffers, ref vb );
|
|
}
|
|
|
|
D3D.VertexFormat[] formatMapping;
|
|
public override int CreateVb<T>( T[] vertices, VertexFormat format, int count ) {
|
|
int size = count * strideSizes[(int)format];
|
|
DataBuffer buffer = device.CreateVertexBuffer( size, Usage.None, formatMapping[(int)format], Pool.Managed );
|
|
buffer.SetData( vertices, size, LockFlags.None );
|
|
return GetOrExpand( ref vBuffers, buffer, vBufferSize );
|
|
}
|
|
|
|
public override int CreateVb( IntPtr vertices, VertexFormat format, int count ) {
|
|
int size = count * strideSizes[(int)format];
|
|
DataBuffer buffer = device.CreateVertexBuffer( size, Usage.None, formatMapping[(int)format], Pool.Managed );
|
|
buffer.SetData( vertices, size, LockFlags.None );
|
|
return GetOrExpand( ref vBuffers, buffer, vBufferSize );
|
|
}
|
|
|
|
public unsafe override int CreateIb( ushort[] indices, int indicesCount ) {
|
|
int size = indicesCount * sizeof( ushort );
|
|
DataBuffer buffer = device.CreateIndexBuffer( size, Usage.None, Format.Index16, Pool.Managed );
|
|
buffer.SetData( indices, size, LockFlags.None );
|
|
return GetOrExpand( ref iBuffers, buffer, iBufferSize );
|
|
}
|
|
|
|
public override int CreateIb( IntPtr indices, int indicesCount ) {
|
|
int size = indicesCount * sizeof( ushort );
|
|
DataBuffer buffer = device.CreateIndexBuffer( size, Usage.None, Format.Index16, Pool.Managed );
|
|
buffer.SetData( indices, size, LockFlags.None );
|
|
return GetOrExpand( ref iBuffers, buffer, iBufferSize );
|
|
}
|
|
|
|
public override void DeleteVb( ref int vb ) {
|
|
Delete( vBuffers, ref vb );
|
|
}
|
|
|
|
public override void DeleteIb( ref int ib ) {
|
|
Delete( iBuffers, ref ib );
|
|
}
|
|
|
|
int batchStride;
|
|
public override void SetBatchFormat( VertexFormat format ) {
|
|
device.SetVertexFormat( formatMapping[(int)format] );
|
|
batchStride = strideSizes[(int)format];
|
|
}
|
|
|
|
public override void BindVb( int vb ) {
|
|
device.SetStreamSource( 0, vBuffers[vb], 0, batchStride );
|
|
}
|
|
|
|
public override void BindIb( int ib ) {
|
|
device.SetIndices( iBuffers[ib] );
|
|
}
|
|
|
|
public override void DrawVb( DrawMode mode, int startVertex, int verticesCount ) {
|
|
device.DrawPrimitives( modeMappings[(int)mode], startVertex, NumPrimitives( verticesCount, mode ) );
|
|
}
|
|
|
|
public override void DrawIndexedVb( DrawMode mode, int indicesCount, int startIndex ) {
|
|
device.DrawIndexedPrimitives( modeMappings[(int)mode], 0, startIndex / 6 * 4,
|
|
indicesCount / 6 * 4, startIndex, NumPrimitives( indicesCount, mode ) );
|
|
}
|
|
|
|
internal override void DrawIndexedVb_TrisT2fC4b( int indicesCount, int startIndex ) {
|
|
device.DrawIndexedPrimitives( PrimitiveType.TriangleList, 0, startIndex / 6 * 4,
|
|
indicesCount / 6 * 4, startIndex, indicesCount / 3 );
|
|
}
|
|
|
|
internal override void DrawIndexedVb_TrisT2fC4b( int indicesCount, int startVertex, int startIndex ) {
|
|
device.DrawIndexedPrimitives( PrimitiveType.TriangleList, startVertex, 0,
|
|
indicesCount / 6 * 4, startIndex, indicesCount / 3 );
|
|
}
|
|
#endregion
|
|
|
|
|
|
#region Matrix manipulation
|
|
|
|
public override void SetMatrixMode( MatrixType mode ) {
|
|
if( mode == MatrixType.Modelview ) {
|
|
curStack = viewStack;
|
|
} else if( mode == MatrixType.Projection ) {
|
|
curStack = projStack;
|
|
} else if( mode == MatrixType.Texture ) {
|
|
curStack = texStack;
|
|
}
|
|
}
|
|
|
|
public unsafe override void LoadMatrix( ref Matrix4 matrix ) {
|
|
if( curStack == texStack ) {
|
|
matrix.M31 = matrix.M41; // NOTE: this hack fixes the texture movements.
|
|
device.SetTextureStageState( 0, TextureStage.TextureTransformFlags, (int)TextureTransform.Count2 );
|
|
}
|
|
curStack.SetTop( ref matrix );
|
|
}
|
|
|
|
Matrix4 identity = Matrix4.Identity;
|
|
public override void LoadIdentityMatrix() {
|
|
if( curStack == texStack ) {
|
|
device.SetTextureStageState( 0, TextureStage.TextureTransformFlags, (int)TextureTransform.Disable );
|
|
}
|
|
curStack.SetTop( ref identity );
|
|
}
|
|
|
|
public override void PushMatrix() {
|
|
curStack.Push();
|
|
}
|
|
|
|
public override void PopMatrix() {
|
|
curStack.Pop();
|
|
}
|
|
|
|
public unsafe override void MultiplyMatrix( ref Matrix4 matrix ) {
|
|
curStack.MultiplyTop( ref matrix );
|
|
}
|
|
|
|
class MatrixStack
|
|
{
|
|
Matrix4[] stack;
|
|
int stackIndex;
|
|
Device device;
|
|
TransformState matrixType;
|
|
|
|
public MatrixStack( int capacity, Device device, TransformState matrixType ) {
|
|
stack = new Matrix4[capacity];
|
|
stack[0] = Matrix4.Identity;
|
|
this.device = device;
|
|
this.matrixType = matrixType;
|
|
}
|
|
|
|
public void Push() {
|
|
stack[stackIndex + 1] = stack[stackIndex]; // mimic GL behaviour
|
|
stackIndex++; // exact same, we don't need to update DirectX state.
|
|
}
|
|
|
|
public void SetTop( ref Matrix4 matrix ) {
|
|
stack[stackIndex] = matrix;
|
|
device.SetTransform( matrixType, ref stack[stackIndex] );
|
|
}
|
|
|
|
public void MultiplyTop( ref Matrix4 matrix ) {
|
|
stack[stackIndex] = matrix * stack[stackIndex];
|
|
device.SetTransform( matrixType, ref stack[stackIndex] );
|
|
}
|
|
|
|
public void Pop() {
|
|
stackIndex--;
|
|
device.SetTransform( matrixType, ref stack[stackIndex] );
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
public override void BeginFrame( Game game ) {
|
|
device.BeginScene();
|
|
}
|
|
|
|
public override void EndFrame( Game game ) {
|
|
device.EndScene();
|
|
int code = device.Present();
|
|
if( code >= 0 ) return;
|
|
|
|
if( (uint)code != (uint)Direct3DError.DeviceLost )
|
|
throw new SharpDXException( code );
|
|
|
|
// TODO: Make sure this actually works on all graphics cards.
|
|
Utils.LogDebug( "Lost Direct3D device." );
|
|
LoopUntilRetrieved();
|
|
RecreateDevice( game );
|
|
}
|
|
|
|
void LoopUntilRetrieved() {
|
|
ScheduledTask task = new ScheduledTask();
|
|
task.Interval = 1.0 / 20;
|
|
task.Callback = LostContextFunction;
|
|
|
|
while( true ) {
|
|
Thread.Sleep( 50 );
|
|
uint code = (uint)device.TestCooperativeLevel();
|
|
if( (uint)code == (uint)Direct3DError.DeviceNotReset ) {
|
|
Utils.LogDebug( "Retrieved Direct3D device again." ); return;
|
|
}
|
|
task.Callback( task );
|
|
}
|
|
}
|
|
|
|
bool vsync = false;
|
|
public override void SetVSync( Game game, bool value ) {
|
|
vsync = value;
|
|
game.VSync = value;
|
|
RecreateDevice( game );
|
|
}
|
|
|
|
public override void OnWindowResize( Game game ) {
|
|
RecreateDevice( game );
|
|
}
|
|
|
|
void RecreateDevice( Game game ) {
|
|
PresentParameters args = GetPresentArgs( game.Width, game.Height );
|
|
for( int i = 0; i < dynamicvBuffers.Length; i++ ) {
|
|
DynamicDataBuffer buffer = dynamicvBuffers[i];
|
|
if( buffer != null ) buffer.Dispose();
|
|
}
|
|
RaiseContextLost();
|
|
LostContext = true;
|
|
|
|
while( (uint)device.Reset( args ) == (uint)Direct3DError.DeviceLost )
|
|
LoopUntilRetrieved();
|
|
|
|
SetDefaultRenderStates();
|
|
RestoreRenderStates();
|
|
|
|
for( int i = 0; i < dynamicvBuffers.Length; i++ ) {
|
|
DynamicDataBuffer buffer = dynamicvBuffers[i];
|
|
if( buffer == null ) continue;
|
|
|
|
dynamicvBuffers[i] = device.CreateDynamicVertexBuffer( buffer.MaxSize, buffer.Format );
|
|
dynamicvBuffers[i].Format = buffer.Format;
|
|
dynamicvBuffers[i].MaxSize = buffer.MaxSize;
|
|
buffer = dynamicvBuffers[i];
|
|
}
|
|
|
|
LostContext = false;
|
|
RaiseContextRecreated();
|
|
}
|
|
|
|
void SetDefaultRenderStates() {
|
|
device.SetRenderState( RenderState.FillMode, (int)FillMode.Solid );
|
|
FaceCulling = false;
|
|
device.SetRenderState( RenderState.ColorVertex, false );
|
|
device.SetRenderState( RenderState.Lighting, false );
|
|
device.SetRenderState( RenderState.SpecularEnable, false );
|
|
device.SetRenderState( RenderState.LocalViewer, false );
|
|
device.SetRenderState( RenderState.DebugMonitorToken, false );
|
|
}
|
|
|
|
void RestoreRenderStates() {
|
|
device.SetRenderState( RenderState.AlphaTestEnable, alphaTest );
|
|
device.SetRenderState( RenderState.AlphaBlendEnable, alphaBlend );
|
|
device.SetRenderState( RenderState.AlphaFunc, (int)alphaTestFunc );
|
|
device.SetRenderState( RenderState.AlphaRef, alphaTestRef );
|
|
device.SetRenderState( RenderState.SourceBlend, (int)srcBlendFunc );
|
|
device.SetRenderState( RenderState.DestinationBlend, (int)dstBlendFunc );
|
|
device.SetRenderState( RenderState.FogEnable, fogEnable );
|
|
device.SetRenderState( RenderState.FogColor, fogCol );
|
|
device.SetRenderState( RenderState.FogDensity, fogDensity );
|
|
device.SetRenderState( RenderState.FogStart, fogStart );
|
|
device.SetRenderState( RenderState.FogEnd, fogEnd );
|
|
device.SetRenderState( RenderState.FogTableMode, (int)fogTableMode );
|
|
device.SetRenderState( RenderState.ZFunc, (int)depthTestFunc );
|
|
device.SetRenderState( RenderState.ZEnable, depthTest );
|
|
device.SetRenderState( RenderState.ZWriteEnable, depthWrite );
|
|
}
|
|
|
|
PresentParameters GetPresentArgs( int width, int height ) {
|
|
PresentParameters args = new PresentParameters();
|
|
args.AutoDepthStencilFormat = depthFormat;
|
|
args.BackBufferWidth = width;
|
|
args.BackBufferHeight = height;
|
|
args.BackBufferFormat = viewFormat;
|
|
args.BackBufferCount = 1;
|
|
args.EnableAutoDepthStencil = true;
|
|
args.PresentationInterval = vsync ? PresentInterval.One : PresentInterval.Immediate;
|
|
args.SwapEffect = SwapEffect.Discard;
|
|
args.Windowed = true;
|
|
return args;
|
|
}
|
|
|
|
static int GetOrExpand<T>( ref T[] array, T value, int expSize ) {
|
|
// Find first free slot
|
|
for( int i = 1; i < array.Length; i++ ) {
|
|
if( array[i] == null ) {
|
|
array[i] = value;
|
|
return i;
|
|
}
|
|
}
|
|
// Otherwise resize and add more elements
|
|
int oldLength = array.Length;
|
|
Array.Resize( ref array, array.Length + expSize );
|
|
array[oldLength] = value;
|
|
return oldLength;
|
|
}
|
|
|
|
static void Delete<T>( T[] array, ref int id ) where T : class, IDisposable {
|
|
if( id <= 0 || id >= array.Length ) return;
|
|
|
|
T value = array[id];
|
|
if( value != null ) {
|
|
value.Dispose();
|
|
}
|
|
array[id] = null;
|
|
id = -1;
|
|
}
|
|
|
|
static int NumPrimitives( int vertices, DrawMode mode ) {
|
|
return mode == DrawMode.Triangles ? vertices / 3 : vertices / 2;
|
|
}
|
|
|
|
protected unsafe override void LoadOrthoMatrix( float width, float height ) {
|
|
Matrix4 matrix = Matrix4.CreateOrthographicOffCenter( 0, width, height, 0, -10000, 10000 );
|
|
const float zN = -10000, zF = 10000;
|
|
matrix.M33 = 1 / (zN - zF);
|
|
matrix.M43 = zN / (zN - zF);
|
|
matrix.M44 = 1;
|
|
curStack.SetTop( ref matrix );
|
|
}
|
|
|
|
public override void Dispose() {
|
|
base.Dispose();
|
|
device.Dispose();
|
|
d3d.Dispose();
|
|
}
|
|
|
|
internal override void MakeApiInfo() {
|
|
string adapter = d3d.Adapters[0].Details.Description;
|
|
float texMem = (uint)device.AvailableTextureMemory / 1024f / 1024f;
|
|
|
|
ApiInfo = new string[] {
|
|
"-- Using Direct3D9 api --",
|
|
"Adapter: " + adapter,
|
|
"Mode: " + createFlags,
|
|
"Texture memory: " + texMem + " MB",
|
|
"Max 2D texture dimensions: " + MaxTextureDimensions,
|
|
"Depth buffer format: " + depthFormat,
|
|
"Back buffer format: " + viewFormat,
|
|
};
|
|
}
|
|
|
|
public override void TakeScreenshot( string output, int width, int height ) {
|
|
using( Surface backbuffer = device.GetBackBuffer( 0, 0, BackBufferType.Mono ),
|
|
tempSurface = device.CreateOffscreenPlainSurface( width, height, Format.X8R8G8B8, Pool.SystemMemory ) ) {
|
|
// For DX 8 use IDirect3DDevice8::CreateImageSurface
|
|
device.GetRenderTargetData( backbuffer, tempSurface );
|
|
LockedRectangle rect = tempSurface.LockRectangle( LockFlags.ReadOnly | LockFlags.NoDirtyUpdate );
|
|
|
|
using( Bitmap bmp = new Bitmap( width, height, width * sizeof(int),
|
|
PixelFormat.Format32bppRgb, rect.DataPointer ) ) {
|
|
bmp.Save( output, ImageFormat.Png );
|
|
}
|
|
tempSurface.UnlockRectangle();
|
|
}
|
|
}
|
|
|
|
void InitFields() {
|
|
// See comment in KeyMap() constructor for why this is necessary.
|
|
modeMappings = new PrimitiveType[2];
|
|
modeMappings[0] = PrimitiveType.TriangleList; modeMappings[1] = PrimitiveType.LineList;
|
|
depthFormats = new Format[6];
|
|
depthFormats[0] = Format.D32; depthFormats[1] = Format.D24X8; depthFormats[2] = Format.D24S8;
|
|
depthFormats[3] = Format.D24X4S4; depthFormats[4] = Format.D16; depthFormats[5] = Format.D15S1;
|
|
viewFormats = new Format[4];
|
|
viewFormats[0] = Format.X8R8G8B8; viewFormats[1] = Format.R8G8B8;
|
|
viewFormats[2] = Format.R5G6B5; viewFormats[3] = Format.X1R5G5B5;
|
|
|
|
blendFuncs = new Blend[6];
|
|
blendFuncs[0] = Blend.Zero; blendFuncs[1] = Blend.One; blendFuncs[2] = Blend.SourceAlpha;
|
|
blendFuncs[3] = Blend.InverseSourceAlpha; blendFuncs[4] = Blend.DestinationAlpha;
|
|
blendFuncs[5] = Blend.InverseDestinationAlpha;
|
|
compareFuncs = new Compare[8];
|
|
compareFuncs[0] = Compare.Always; compareFuncs[1] = Compare.NotEqual; compareFuncs[2] = Compare.Never;
|
|
compareFuncs[3] = Compare.Less; compareFuncs[4] = Compare.LessEqual; compareFuncs[5] = Compare.Equal;
|
|
compareFuncs[6] = Compare.GreaterEqual; compareFuncs[7] = Compare.Greater;
|
|
|
|
formatMapping = new D3D.VertexFormat[2];
|
|
formatMapping[0] = D3D.VertexFormat.Position | D3D.VertexFormat.Diffuse;
|
|
formatMapping[1] = D3D.VertexFormat.Position | D3D.VertexFormat.Texture2 | D3D.VertexFormat.Diffuse;
|
|
modes = new FogMode[3];
|
|
modes[0] = FogMode.Linear; modes[1] = FogMode.Exponential; modes[2] = FogMode.ExponentialSquared;
|
|
}
|
|
}
|
|
}
|
|
#endif |