using SharpDX;
using SharpDX.Direct3D;
using SharpDX.Direct3D11;
using SharpDX.DirectInput;
using SharpDX.DXGI;
using SharpDX.Windows;
using System;
using System.Threading;
using System.Windows.Forms;
using System.Diagnostics;
using SharpDX.XAudio2;

namespace WindowsFormsApp4
{
public class FirstPersonShooter
{
StaticObject O;

Matrix view;
Matrix proj;

Shooter Master;

SwapChainDescription desc;
SwapChain swapChain;
SharpDX.Direct3D11.Device device;
SharpDX.Direct3D11.DeviceContext context;

Thread T;

int ScreenWidth = 0;
int ScreenHeight = 0;

//***************
private int lastTick;
private int lastFrameRate;
private int frameRate;

private int FPS = 0;

private long Frame_Time = 0;

Stopwatch stopwatch = new Stopwatch();
//*****************



Keyboard keyboard;
Mouse mouse;
DirectInput DI = new DirectInput();



public int Mouse_X = 0;
public int Mouse_Y = 0;
public Vector2 Mouse_Previous = new Vector2(0, 0);


public int ClientNbr = -1;


//***************

public FirstPersonShooter(Shooter master)
{

Master = master;
ScreenWidth = Master.ClientSize.Width;
ScreenHeight = Master.ClientSize.Height;// - Master.statusStrip1.Height;


desc = new SwapChainDescription()
{
BufferCount = 1,
ModeDescription =
new ModeDescription(ScreenWidth, ScreenHeight,
new Rational(60, 1), Format.R8G8B8A8_UNorm),
IsWindowed = true,
OutputHandle = master.Handle,
SampleDescription = new SampleDescription(1, 0),
SwapEffect = SwapEffect.Discard,
Usage = Usage.RenderTargetOutput
};

SharpDX.Direct3D11.Device.CreateWithSwapChain(DriverType.Hardware, DeviceCreationFlags.BgraSupport, new[] { SharpDX.Direct3D.FeatureLevel.Level_11_0 }, desc, out device, out swapChain);
context = device.ImmediateContext;

keyboard = new Keyboard(DI);
mouse = new Mouse(DI);


// Acquire the joystick
keyboard.Properties.BufferSize = 128;
keyboard.Acquire();

mouse.Acquire();

O = new StaticObject("tutorial_0.blend.txt", device, context);

{
T = new Thread(WorkThreadFunction);
T.Start();
}//);

//WorkThreadFunction();
}


public void WorkThreadFunction()
{

// Prepare matrices
view = Matrix.LookAtLH(new Vector3(0, 0, -40.0f), new Vector3(0, 0, 0), Vector3.UnitY);
proj = Matrix.Identity;

Texture2D backBuffer = null;
RenderTargetView renderView = null;
Texture2D depthBuffer = null;
DepthStencilView depthView = null;

float rotation = 0.0f;

Master.Invoke(new Action(() =>

RenderLoop.Run(Master, () =>
{

// If Form resized
if (Master.ResizeForm1)
{

MessageBox.Show("resize");
// Dispose all previous allocated resources
Utilities.Dispose(ref backBuffer);
Utilities.Dispose(ref renderView);
Utilities.Dispose(ref depthBuffer);
Utilities.Dispose(ref depthView);

ScreenWidth = Master.ClientSize.Width;
ScreenHeight = Master.ClientSize.Height;

// Resize the backbuffer
swapChain.ResizeBuffers(desc.BufferCount, ScreenWidth, ScreenHeight, Format.Unknown, SwapChainFlags.None);

// Get the backbuffer from the swapchain
backBuffer = Texture2D.FromSwapChain(swapChain, 0);

// Renderview on the backbuffer
renderView = new RenderTargetView(device, backBuffer);

// Create the depth buffer
depthBuffer = new Texture2D(device, new Texture2DDescription()
{
Format = Format.D32_Float_S8X24_UInt,
ArraySize = 1,
MipLevels = 1,
Width = ScreenWidth,
Height = ScreenHeight,
SampleDescription = new SampleDescription(1, 0),
Usage = ResourceUsage.Default,
BindFlags = BindFlags.DepthStencil,
CpuAccessFlags = CpuAccessFlags.None,
OptionFlags = ResourceOptionFlags.None
});

// Create the depth buffer view
depthView = new DepthStencilView(device, depthBuffer);

// Setup targets and viewport for rendering
context.Rasterizer.SetViewport(new Viewport(0, 0, ScreenWidth, ScreenHeight, 0.0f, 1.0f));
context.OutputMerger.SetTargets(depthView, renderView);

// Setup new projection matrix with correct aspect ratio
proj = Matrix.PerspectiveFovLH((float)Math.PI / 4.0f, ScreenWidth / (float)ScreenHeight, 0.1f, 1000.0f);

// We are done resizing
Master.ResizeForm1 = false;
}

// Clear views
context.ClearDepthStencilView(depthView, DepthStencilClearFlags.Depth, 1.0f, 0);
context.ClearRenderTargetView(renderView, SharpDX.Color.Black);





rotation += 0.007f;
O.Render(view, proj, Matrix.Identity * Matrix.RotationY(rotation) * Matrix.RotationX(2*rotation), context, new Vector4(0, 0, -100.0f, 0));


// Present!
swapChain.Present(1, PresentFlags.None);
//});
})));
depthBuffer.Dispose();
depthView.Dispose();
renderView.Dispose();
backBuffer.Dispose();
}
}
}