//// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
//// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
//// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
//// PARTICULAR PURPOSE.
////
//// Copyright (c) Microsoft Corporation. All rights reserved

#include "pch.h"
#include "SoundDriver.h"
#include "GameMain.h"
#include "BasicLoader.h"
#include "windows.ui.xaml.media.dxinterop.h"

using namespace Microsoft::WRL;
using namespace Windows::Foundation;
using namespace Windows::Foundation::Collections;
using namespace Windows::UI::Core;
using namespace Windows::UI::ViewManagement;

using namespace Windows::UI::ApplicationSettings;
using namespace Windows::UI::Popups;
using namespace Windows::UI::Xaml::Controls;
using namespace Windows::Graphics::Display;
using namespace DirectX;
using namespace D2D1;
using namespace concurrency;


using namespace BasicSprites;

const float GameMain::BACKBUFFER_WIDTH = 320.0f;
const float GameMain::BACKBUFFER_HEIGHT = 240.0f;


GameMain::GameMain() : backBufferViewPort_(0.0f,0.0f,BACKBUFFER_WIDTH,BACKBUFFER_HEIGHT) , isDestroy_(false)
{
  soundDriver_.reset(new sf::SoundDriver());
	soundManager_.reset(new sf::SoundManager(*soundDriver_.get()));
  // サウンド再生スレッドの開始
  soundTask_ = task<void>(create_async([this]()
  {
    ExecuteSoundThread();
  })
  );
	//soundThread_ = std::thread(
 //   [this]() -> void 
	//  {
	//	  ExecuteSoundThread();
	//  }
	//);
}

GameMain::~GameMain()
{
  // サウンド再生スレッドの停止
	isDestroy_ = true;
  soundTask_.wait();
 
	//if(soundThread_.joinable())
	//{
	//	soundThread_.join();
	//}
};

void GameMain::CreateDeviceIndependentResources()
{
    DirectXBase::CreateDeviceIndependentResources();

    // Create the performance throttler.

    autoThrottle_ = ref new AutoThrottle(1.0f / 60.0f);
}

void GameMain::Initialize(
	_In_ Windows::UI::Core::CoreWindow^ window,
	_In_ Windows::UI::Xaml::Controls::SwapChainBackgroundPanel^ swapChainPanel,
	_In_ float dpi
	)
{
	panel_  = swapChainPanel;
	Initialize(window,dpi);
}

void GameMain::CreateDeviceResources()
{
    DirectXBase::CreateDeviceResources();

    // Create the sprite batch.

    spriteBatch_ = ref new SpriteBatch();
    unsigned int capacity = 1024;
    if (m_featureLevel < D3D_FEATURE_LEVEL_9_3)
    {
        capacity = min(Parameters::MaximumCapacityCompatible, capacity);
    }
    spriteBatch_->Initialize(
        m_d3dDevice.Get(),
        capacity
        );

    // Load the sprite textures.

    BasicLoader^ loader = ref new BasicLoader(m_d3dDevice.Get(), m_wicFactory.Get());

    loader->LoadTexture(
        "explosion.png",
        &test_,
        nullptr
        );

	spriteBatch_->AddTexture(test_.Get(),float2(64.0,64.0));

    // Create the Sample Overlay.
    
    sampleOverlay_ = ref new SampleOverlay();

    sampleOverlay_->Initialize(
        m_d2dDevice.Get(),
        m_d2dContext.Get(),
        m_wicFactory.Get(),
        m_dwriteFactory.Get(),
        L"シューティングゲーム"
        );



}

void GameMain::CreateWindowSizeDependentResources()
{
//	DirectXBase::CreateWindowSizeDependentResources();
    // Store the window bounds so the next time we get a SizeChanged event we can
    // avoid rebuilding everything if the size is identical.
    m_windowBounds = m_window->Bounds;

    // If the swap chain already exists, resize it.
    if(m_swapChain != nullptr)
    {
        DX::ThrowIfFailed(
            m_swapChain->ResizeBuffers(2, 0, 0, DXGI_FORMAT_B8G8R8A8_UNORM, 0)
            );
    }
    // Otherwise, create a new one.
    else
    {
        // Allocate a descriptor.
        DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {0};
		scale_ = floorf(m_window->Bounds.Width * m_dpi / ( 96.0f * BACKBUFFER_WIDTH));
        swapChainDesc.Width = static_cast<UINT>(m_window->Bounds.Width * m_dpi / 96.0f);    // Can not use 0 to get the default on Composition SwapChain
        swapChainDesc.Height = static_cast<UINT>(m_window->Bounds.Height * m_dpi / 96.0f);
        swapChainDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;           // this is the most common swapchain format
        swapChainDesc.Stereo = false; 
        swapChainDesc.SampleDesc.Count = 1;                          // don't use multi-sampling
        swapChainDesc.SampleDesc.Quality = 0;
        swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
        swapChainDesc.BufferCount = 2;                               // use double buffering to enable flip
        swapChainDesc.Scaling = DXGI_SCALING_STRETCH;
        swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; // all Metro style apps must use this SwapEffect
        swapChainDesc.Flags = 0;

        // Once the desired swap chain description is configured, it must be created on the same adapter as our D3D Device

        // First, retrieve the underlying DXGI Device from the D3D Device.
        ComPtr<IDXGIDevice1>  dxgiDevice;
        DX::ThrowIfFailed(
            m_d3dDevice.As(&dxgiDevice)
            );

        // Identify the physical adapter (GPU or card) this device is running on.
        ComPtr<IDXGIAdapter> dxgiAdapter;
        DX::ThrowIfFailed(
            dxgiDevice->GetAdapter(&dxgiAdapter)
            );

        // And obtain the factory object that created it.
        ComPtr<IDXGIFactory2> dxgiFactory;
        DX::ThrowIfFailed(
            dxgiAdapter->GetParent(IID_PPV_ARGS(&dxgiFactory))
            );

        // Obtain the final swap chain for this window from the DXGI factory.
        DX::ThrowIfFailed(
            dxgiFactory->CreateSwapChainForComposition(
                m_d3dDevice.Get(),
                &swapChainDesc,
                nullptr,    // allow on all displays
                &m_swapChain
                )
            );

		ComPtr<ISwapChainBackgroundPanelNative> dxRootPanelAsNative;

        // set the swap chain on the SwapChainBackgroundPanel
        reinterpret_cast<IUnknown*>(panel_)->QueryInterface(__uuidof(ISwapChainBackgroundPanelNative), (void**)&dxRootPanelAsNative);

        DX::ThrowIfFailed(
            dxRootPanelAsNative->SetSwapChain(m_swapChain.Get())
            );

        // Ensure that DXGI does not queue more than one frame at a time. This both reduces 
        // latency and ensures that the application will only render after each VSync, minimizing 
        // power consumption.
        DX::ThrowIfFailed(
            dxgiDevice->SetMaximumFrameLatency(1)
            );

    }

    // Obtain the backbuffer for this window which will be the final 3D rendertarget.
    ComPtr<ID3D11Texture2D> backBuffer;
    DX::ThrowIfFailed(
        m_swapChain->GetBuffer(0, IID_PPV_ARGS(&backBuffer))
        );

    // Create a view interface on the rendertarget to use on bind.
    DX::ThrowIfFailed(
        m_d3dDevice->CreateRenderTargetView(
            backBuffer.Get(),
            nullptr,
            &m_renderTargetView
            )
        );

    // Cache the rendertarget dimensions in our helper class for convenient use.
    D3D11_TEXTURE2D_DESC backBufferDesc = {0};
    backBuffer->GetDesc(&backBufferDesc);
    m_renderTargetSize.Width  = static_cast<float>(backBufferDesc.Width);
    m_renderTargetSize.Height = static_cast<float>(backBufferDesc.Height);

    // Create a descriptor for the depth/stencil buffer.
    CD3D11_TEXTURE2D_DESC depthStencilDesc(
        DXGI_FORMAT_D24_UNORM_S8_UINT, 
        backBufferDesc.Width,
        backBufferDesc.Height,
        1,
        1,
        D3D11_BIND_DEPTH_STENCIL
        );

    // Allocate a 2-D surface as the depth/stencil buffer.
    ComPtr<ID3D11Texture2D> depthStencil;
    DX::ThrowIfFailed(
        m_d3dDevice->CreateTexture2D(
            &depthStencilDesc,
            nullptr,
            &depthStencil
            )
        );

    // Create a DepthStencil view on this surface to use on bind.
    DX::ThrowIfFailed(
        m_d3dDevice->CreateDepthStencilView(
            depthStencil.Get(),
            &CD3D11_DEPTH_STENCIL_VIEW_DESC(D3D11_DSV_DIMENSION_TEXTURE2D),
            &m_depthStencilView
            )
        );

    // Create a viewport descriptor of the full window size.
	swapChainViewPort_.Width =         static_cast<float>(backBufferDesc.Width);
	swapChainViewPort_.Height =         static_cast<float>(backBufferDesc.Height);

    // Set the current viewport using the descriptor.
    m_d3dContext->RSSetViewports(1, &swapChainViewPort_);

    // Now we set up the Direct2D render target bitmap linked to the swapchain. 
    // Whenever we render to this bitmap, it will be directly rendered to the 
    // swapchain associated with the window.
    D2D1_BITMAP_PROPERTIES1 bitmapProperties = 
        BitmapProperties1(
            D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW,
            PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED),
            m_dpi,
            m_dpi
            );

    // Direct2D needs the dxgi version of the backbuffer surface pointer.
    ComPtr<IDXGISurface> dxgiBackBuffer;
    DX::ThrowIfFailed(
        m_swapChain->GetBuffer(0, IID_PPV_ARGS(&dxgiBackBuffer))
        );

    // Get a D2D surface from the DXGI back buffer to use as the D2D render target.
    DX::ThrowIfFailed(
        m_d2dContext->CreateBitmapFromDxgiSurface(
            dxgiBackBuffer.Get(),
            &bitmapProperties,
            &m_d2dTargetBitmap
            )
        );

    // So now we can set the Direct2D render target.
    m_d2dContext->SetTarget(m_d2dTargetBitmap.Get());

    // Set D2D text anti-alias mode to Grayscale to ensure proper rendering of text on intermediate surfaces.
    m_d2dContext->SetTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE);

    // Randomly generate some non-interactive asteroids to fit the screen.

    sampleOverlay_->UpdateForWindowSizeChange();
	// バックバッファの作成
    //ComPtr<ID3D11Texture2D> backBuffer;
    //DX::ThrowIfFailed(
    //    m_swapChain->GetBuffer(0, IID_PPV_ARGS(&backBuffer))
    //    );
    //D3D11_TEXTURE2D_DESC backBufferDesc = {0};
    //backBuffer->GetDesc(&backBufferDesc);

	D3D11_TEXTURE2D_DESC desc = {0};
    desc.Width = 320;
    desc.Height = 240;
    desc.Format = backBufferDesc.Format;
    desc.MipLevels = 1;
    desc.SampleDesc.Count = 1;
    desc.SampleDesc.Quality = 0;
    desc.ArraySize = 1;
    desc.Usage = D3D11_USAGE_DEFAULT;
    desc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
//    desc.MiscFlags = D3D11_RESOURCE_MISC_GDI_COMPATIBLE;

    DX::ThrowIfFailed(m_d3dDevice->CreateTexture2D(&desc,NULL,&backBuffer_));

	DX::ThrowIfFailed(m_d3dDevice->CreateRenderTargetView(backBuffer_.Get(),0,&backBufferRenderTargetView_));

 //   // 深度バッファの作成
 //   D3D11_TEXTURE2D_DESC depth = {} ;
 //   depth.Width = desc.Width;//rc.right - rc.left;client_width_;
 //   depth.Height = desc.Height;//rc.bottom - rc.top;client_height_;
 //   depth.MipLevels = 1;
 //   depth.ArraySize = 1;
 //   depth.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
 //   depth.SampleDesc.Count = 1;
 //   depth.SampleDesc.Quality = 0;
 //   depth.Usage = D3D11_USAGE_DEFAULT;
 //   depth.BindFlags = D3D11_BIND_DEPTH_STENCIL;
 //   depth.CPUAccessFlags = 0;
 //   depth.MiscFlags = 0;
 //   ComPtr<ID3D11Texture2D> depthT;
	//DX::ThrowIfFailed(m_d3dDevice->CreateTexture2D( &depth, NULL, &depthT ));

 //   D3D11_DEPTH_STENCIL_VIEW_DESC dsv = {};
 //   dsv.Format = depth.Format;
 //   dsv.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
 //   dsv.Texture2D.MipSlice = 0;

	//DX::ThrowIfFailed(m_d3dDevice->CreateDepthStencilView( depthT.Get(), &dsv, &backBufferDepthStencilView_ ));

	spriteBatch_->AddTexture(backBuffer_.Get(),float2());

	// 深度ステンシルステートを作成する
   //D3D11_DEPTH_STENCIL_DESC ddsDesc;
   //::ZeroMemory( &ddsDesc, sizeof( ddsDesc ) );
   //ddsDesc.DepthEnable = TRUE;                                     // 深度テストを使用する
   //ddsDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
   //ddsDesc.DepthFunc = D3D11_COMPARISON_LESS;
   //ddsDesc.StencilEnable = FALSE;
   //DX::ThrowIfFailed(m_d3dDevice->CreateDepthStencilState( &ddsDesc, &backBufferDepthStencilState_ ));

}

void GameMain::Update(float timeTotal, float timeDelta)
{
    // Update the performance throttler.

    auto control = autoThrottle_->Update(timeDelta);

    //if (control == FrameWorkload::Increase)
    //{
    //    m_numParticlesToDraw += SampleSettings::Performance::ParticleCountDelta;
    //}
    //if (control == FrameWorkload::Decrease)
    //{
    //    m_numParticlesToDraw -= SampleSettings::Performance::ParticleCountDelta;
    //}
    //if (control != FrameWorkload::Maintain)
    //{
    //    m_numParticlesToDraw = max(SampleSettings::Performance::ParticleCountMin, min(SampleSettings::Performance::ParticleCountMax, m_numParticlesToDraw));
    //    if (m_featureLevel < D3D_FEATURE_LEVEL_9_3)
    //    {
    //        m_numParticlesToDraw = min(static_cast<int>(Parameters::MaximumCapacityCompatible - SampleSettings::NumAsteroids - 1), m_numParticlesToDraw);
    //    }
    //}

    // Update the non-interactive asteroids.
    // Their behavior is to drift across the window with a fixed translational and rotational
    // velocity.  Upon crossing a boundary outside the window, their position wraps.

    //for (auto asteroid = m_asteroidData.begin(); asteroid != m_asteroidData.end(); asteroid++)
    //{
    //    static const float border = 100.0f;
    //    asteroid->pos = asteroid->pos + asteroid->vel * timeDelta;
    //    if (asteroid->vel.x < 0)
    //    {
    //        if (asteroid->pos.x < -border)
    //        {
    //            asteroid->pos.x = m_windowBounds.Width + border;
    //        }
    //    }
    //    else
    //    {
    //        if (asteroid->pos.x > m_windowBounds.Width + border)
    //        {
    //            asteroid->pos.x = -border;
    //        }
    //    }
    //    if (asteroid->vel.y < 0)
    //    {
    //        if (asteroid->pos.y < -border)
    //        {
    //            asteroid->pos.y = m_windowBounds.Height + border;
    //        }
    //    }
    //    else
    //    {
    //        if (asteroid->pos.y > m_windowBounds.Height + border)
    //        {
    //            asteroid->pos.y = -border;
    //        }
    //    }

    //    asteroid->rot += asteroid->rotVel * timeDelta;
    //    if (asteroid->rot > static_cast<float>(M_PI))
    //    {
    //        asteroid->rot -= 2.0f * static_cast<float>(M_PI);
    //    }
    //    if (asteroid->rot < static_cast<float>(-M_PI))
    //    {
    //        asteroid->rot += 2.0f * static_cast<float>(M_PI);
    //    }
    //}

    //// Update the interactive particles.
    //// Their behavior is to be gravitationally attracted to two oscillating gravity
    //// wells and repelled by any pressed pointer points.  Upon reaching the edge of
    //// the window, the particles bounce.

    //// Add two gravity wells that move throughout the window.
    //float2 wellPositions[] =
    //{
    //    float2(
    //        (1.0f + 0.8f * cosf(timeTotal / (2.0f * static_cast<float>(M_PI)) + 3.0f)) * m_windowBounds.Width / 2.0f,
    //        (1.0f + 0.8f * sinf(timeTotal / 5.0f)) * m_windowBounds.Height / 2.0f
    //        ),
    //    float2(
    //        (1.0f + 0.8f * cosf(timeTotal / static_cast<float>(M_PI * M_PI) + 1.0f)) * m_windowBounds.Width / 2.0f,
    //        (1.0f + 0.8f * sinf(timeTotal / static_cast<float>(M_PI))) * m_windowBounds.Height / 2.0f
    //        )
    //};

    //for (auto particle = m_particleData.begin(); particle != m_particleData.begin() + m_numParticlesToDraw; particle++)
    //{
    //    if (particle->pos.x < 0)
    //    {
    //        particle->vel.x = abs(particle->vel.x);
    //    }
    //    if (particle->pos.x > m_windowBounds.Width)
    //    {
    //        particle->vel.x = -abs(particle->vel.x);
    //    }
    //    if (particle->pos.y < 0)
    //    {
    //        particle->vel.y = abs(particle->vel.y);
    //    }
    //    if (particle->pos.y > m_windowBounds.Height)
    //    {
    //        particle->vel.y = -abs(particle->vel.y);
    //    }

    //    for (auto repulsor = m_repulsors.begin(); repulsor != m_repulsors.end(); repulsor++)
    //    {
    //        float2 delta = particle->pos - repulsor->second;
    //        float deltaLength = length(delta) + 24.0f; // Offset length to avoid division by zero.
    //        float deltaLengthCubed = deltaLength * deltaLength * deltaLength;
    //        particle->vel = particle->vel + SampleSettings::Physics::Gravity * timeDelta * delta / deltaLengthCubed;
    //    }

    //    for (int i = 0; i < ARRAYSIZE(wellPositions); i++)
    //    {
    //        float gravitySign = 1.0f;
    //        if ((static_cast<int>(timeTotal / 2.0f) + 1) % 10 == 0)
    //        {
    //            // Every 20 seconds, "explode" the gravity wells for 2 seconds.
    //            gravitySign = -1.0f;
    //        }
    //        float2 delta = wellPositions[i] - particle->pos;
    //        float deltaLength = length(delta) + 24.0f;
    //        float deltaLengthCubed = deltaLength * deltaLength * deltaLength;
    //        particle->vel = particle->vel + gravitySign * 0.2f * SampleSettings::Physics::Gravity * timeDelta * delta / deltaLengthCubed;
    //    }

    //    particle->vel = particle->vel * (1.0f - SampleSettings::Physics::Damping);

    //    // Add random noise to the velocity to prevent particles from locking together.
    //    
    //    particle->vel.x += RandFloat(-0.5f, 0.5f);
    //    particle->vel.y += RandFloat(-0.5f, 0.5f);

    //    particle->pos = particle->pos + particle->vel * timeDelta;
    //}
}

void GameMain::Render()
{
	static int frame_count = 0;

    m_d3dContext->OMSetRenderTargets(
        1,
        backBufferRenderTargetView_.GetAddressOf(),
        nullptr//backBufferDepthStencilView_.Get()
        );
//	m_d3dContext->OMSetDepthStencilState(backBufferDepthStencilState_.Get(),0);
	  m_d3dContext->RSSetViewports(1, &backBufferViewPort_);
	//m_d3dContext->RSSetState(


	m_d3dContext->ClearRenderTargetView(
        backBufferRenderTargetView_.Get(),
        reinterpret_cast<float*>(&D2D1::ColorF(D2D1::ColorF::Black))
        );

	//m_d3dContext->ClearDepthStencilView(backBufferDepthStencilView_.Get(),D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL,1.0f,0);


    spriteBatch_->Begin();

    // Draw the background.

    spriteBatch_->Draw(
        test_.Get(),
        float4(160.0f, 120.0f,0.7f,1.0f),
        PositionUnits::Pixels,
        float2(64.0f, 64.0f),
        SizeUnits::Pixels,
        float4(1.0f, 1.0f, 1.0f, 1.0f),
		0.0f,
		BlendMode::Additive,
		float2((float)((frame_count >> 3) % 4) * 64.0f,(float)((frame_count >> 3) / 4) * 64.0f)
        );

	spriteBatch_->Draw(
        test_.Get(),
        float4(128.0f, 100.0f,0.7f,1.0f),
        PositionUnits::Pixels,
        float2(32.0f, 32.0f),
        SizeUnits::Pixels,
        float4(1.0f, 1.0f, 1.0f, 1.0f),
		0.0f,
		BlendMode::Additive,
		float2((float)((frame_count >> 3) % 4) * 64.0f,(float)((frame_count >> 3) / 4) * 64.0f)
        );

	spriteBatch_->Draw(
        test_.Get(),
        float4(128.0f, 50.0f,0.7f,1.0f),
        PositionUnits::Pixels,
        float2(96.0f, 96.0f),
        SizeUnits::Pixels,
        float4(1.0f, 1.0f, 1.0f, 1.0f),
		0.0f,
		BlendMode::Additive,
		float2((float)((frame_count >> 3) % 4) * 64.0f,(float)((frame_count >> 3) / 4) * 64.0f)
        );

	frame_count = (frame_count + 1) & (0x7f);

    //// Draw the non-interactive asteroids.

    //for (auto asteroid = m_asteroidData.begin(); asteroid != m_asteroidData.end(); asteroid++)
    //{
    //    spriteBatch_->Draw(
    //        m_asteroid.Get(),
    //        asteroid->pos,
    //        PositionUnits::DIPs,
    //        float2(1.0f, 1.0f) * asteroid->scale,
    //        SizeUnits::Normalized,
    //        float4(0.8f, 0.8f, 1.0f, 1.0f),
    //        asteroid->rot
    //        );
    //}

    //// Draw the interactive particles.

    //for (auto particle = m_particleData.begin(); particle != m_particleData.begin() + m_numParticlesToDraw; particle++)
    //{
    //    float alpha = length(particle->vel) / 200.0f;
    //    spriteBatch_->Draw(
    //        m_particle.Get(),
    //        particle->pos,
    //        PositionUnits::DIPs,
    //        float2(32.0f, 32.0f),
    //        SizeUnits::DIPs,
    //        float4(0.1f, 0.02f, 0.0f, alpha),
    //        0.0f,
    //        BlendMode::Additive
    //        );
    //}

    spriteBatch_->End();

    m_d3dContext->OMSetRenderTargets(
        1,
        m_renderTargetView.GetAddressOf(),
        nullptr/*m_depthStencilView.Get()*/
        );

	m_d3dContext->RSSetViewports(1, &swapChainViewPort_);


	m_d3dContext->ClearRenderTargetView(
        m_renderTargetView.Get(),
        reinterpret_cast<float*>(&D2D1::ColorF(D2D1::ColorF::MidnightBlue))
        );

	//m_d3dContext->ClearDepthStencilView(m_depthStencilView.Get(),D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL,1.0f,0);

	spriteBatch_->Begin();

    spriteBatch_->Draw(
        backBuffer_.Get(),
        float4(m_window->Bounds.Width / 2.0f,m_window->Bounds.Height / 2.0f,0.0f,1.0f),
        PositionUnits::DIPs,
        float2(1.0f, 1.0f) * scale_,
        SizeUnits::Normalized,
        float4(1.0f, 1.0f, 1.0f, 1.0f),
        0.0f,
        BlendMode::Alpha
        );

	spriteBatch_->End();

    // Render the Sample Overlay.
	sampleOverlay_->Render();
}



float GameMain::RandFloat(float min, float max)
{
    return (static_cast<float>(rand() % RAND_MAX) / static_cast<float>(RAND_MAX)) * (max - min) + min;
}

// サウンド再生スレッド
void GameMain::ExecuteSoundThread()
{
	//sf::com_init comInit;
  InitSound();
  soundManager_->Sequencer().Play();
	while(!isDestroy_)
	{
    soundDriver_->Render();
//		Concurrency::wait(800);
	//	soundDriver_->Update();
	//	soundDriver_->Render();
	}
}

void GameMain::InitSound()
{
      // 鋸波テーブルを作る
      {
        sf::Synthesizer::WaveTable sawtbl;
        sawtbl.sampleRate = 440.0f;
        sawtbl.basePitch = 0.0f;
        sawtbl.stereo = false;

        float v = -1.0f,d = 2.0f / 1024.0f;
        for(int  i = 0;i < 1024;++i)
        {
          //        if(i < 15) v = -1.0f; else v = 1.0f; 
          sawtbl.waveData.push_back(v) ;
          v += d;
        }
        soundManager_->Synthesizer().WaveTables().push_back(std::move(sawtbl));
      }

      // 矩形波テーブルを作る
      {
        sf::Synthesizer::WaveTable squaretbl;
        squaretbl.sampleRate = 440.0f;
        squaretbl.basePitch = 0.0f;
        squaretbl.stereo = false;

        float v = 0.0f;
        for(int  i = 0;i < 32;++i)
        {
          if(i < 15) v = -1.0f; else v = 1.0f; 
          squaretbl.waveData.push_back(v) ;
        }
        soundManager_->Synthesizer().WaveTables().push_back(std::move(squaretbl));
      }

      // 三角波テーブル
      {
        sf::Synthesizer::WaveTable tritbl;
        tritbl.sampleRate = 440.0f;
        tritbl.basePitch = 0.0f;
        tritbl.stereo = false;

        float v = -1.0f,d = 2.0f / 16.0f;
        for(int  i = 0;i < 32;++i)
        {
          if(i < 15) d = -d; 
          tritbl.waveData.push_back(v) ;
          v += d;
        }
        soundManager_->Synthesizer().WaveTables().push_back(std::move(tritbl));
      }

      // sinテーブル
      {
        sf::Synthesizer::WaveTable sintbl;
        sintbl.sampleRate = 440.0f;
        sintbl.basePitch = 0.0f;
        sintbl.stereo = false;

        float v = 0.0f,d = 2.0f * M_PI / 128.0f;
        for(int  i = 0;i < 128;++i)
        {
          sintbl.waveData.push_back(sinf(v));
          v += d;
        }
        soundManager_->Synthesizer().WaveTables().push_back(std::move(sintbl));
      }

      // LFO用 Sinテーブル
      {
        sf::Synthesizer::WaveTable sintbl;
        sintbl.sampleRate = 440.0f;
        sintbl.basePitch = 0.0f;
        sintbl.stereo = false;

        float v = 0.0f,d = 2.0f * M_PI / 128.0f;
        for(int  i = 0;i < 128;++i)
        {
          sintbl.waveData.push_back(sinf(v) / 2.0f + 0.5f);
          v += d;
        }
        soundManager_->Synthesizer().WaveTables().push_back(std::move(sintbl));
      }




      //      ::OutputDebugStringW((boost::wformat(L"waveTable size: %d") % osc_[0].WaveData().size()).str().c_str());

      // timberのセットアップ
      for(int i = 0; i < 4;++i){

        sf::Synthesizer::Timber timber;
        timber.oscillator.reset(new sf::Synthesizer::WaveTableOscillator(&soundManager_->Synthesizer().WaveTables().at(0)));
        timber.amplitude.gain = 1.0f;
        timber.amplitude.envelope.releaseNoteOff = true;
        timber.amplitude.envelope.attackTime = 0.01f;
        timber.amplitude.envelope.decayTime = 0.02f;
        timber.amplitude.envelope.sustainLevel = 0.5f;
        timber.amplitude.envelope.releaseTime = 0.2f;
        timber.amplitude.envelope.gain = 1.0f;
        timber.amplitude.lfo.waveForm = &(soundManager_->Synthesizer().WaveTables()[4]);
        timber.amplitude.lfo.freq = 5.0f;
        timber.amplitude.lfo.gain = 0.0f;

        timber.pitch.lfo.freq = 10.0f;
        timber.pitch.lfo.gain = 0.000f;
        timber.pitch.lfo.waveForm = &(soundManager_->Synthesizer().WaveTables()[4]);
        timber.pitch.lfo.startNoteOn = true;
        timber.pitch.envelope.attackTime = 0.0f;
        timber.pitch.envelope.decayTime = 0.02f;
        timber.pitch.envelope.sustainLevel = 0.5f;
        timber.pitch.envelope.gain =0.0f;
        timber.pitch.pitch = 0.0f;

        timber.pan.lfo.freq = 2.0f;
        timber.pan.lfo.gain = 1.0f;
        timber.pan.lfo.waveForm = &(soundManager_->Synthesizer().WaveTables()[3]);
        timber.pan.lfo.startNoteOn = true;
        timber.pan.envelope.enable = false;
        timber.pan.lfo.envelope.enable = false;
        timber.pan.pan = 0.0f;

        timber.filter.lfo.freq = 5.0f;
        timber.filter.lfo.gain = 1.0f;
        timber.filter.lfo.waveForm = &(soundManager_->Synthesizer().WaveTables()[3]);
        timber.filter.lfo.startNoteOn = true;
        timber.filter.cutoff = 10000.0f;
        timber.filter.resonance = 0.0f;
        timber.filter.envelope.attackTime = 0.01f;
        timber.filter.envelope.decayTime = 0.03f;
        timber.filter.envelope.sustainLevel = 0.05f;
        timber.filter.envelope.releaseTime = 0.2f;
        timber.filter.envelope.gain = 10000.0f;

        soundManager_->Synthesizer().AddProgram(sf::Synthesizer::Program(std::move((boost::wformat(L"Program No.%d") % i).str()),std::move(timber)));   
        //        timbers_.push_back(std::move(timber));
      }

      for(int i = 0,end = soundManager_->Synthesizer().Voices();i < end;++i)
      {
         soundManager_->Synthesizer().AssignProgramToVoice(0,i);
      }

      soundManager_->Synthesizer().isEnable(true);
}

