空std::当调用析构函数时,列表抛出异常

时间:2022-09-25 19:19:03

So if I use the code below when the program exits I get an exception in std::list at this location. This is regardless of whether I add items to it or not.

因此,如果我在程序退出时使用下面的代码,我会在这个位置得到std::list中的一个异常。这与我是否添加项目无关。

 void clear() _NOEXCEPT
    {   // erase all
 #if _ITERATOR_DEBUG_LEVEL == 2
    this->_Orphan_ptr(*this, nullptr);
 #endif /* _ITERATOR_DEBUG_LEVEL == 2 */

    _Nodeptr _Pnode = this->_Nextnode(this->_Myhead);
    this->_Nextnode(this->_Myhead) = this->_Myhead;
    this->_Prevnode(this->_Myhead) = this->_Myhead;
    this->_Mysize = 0;

    for (_Nodeptr _Pnext; _Pnode != this->_Myhead; _Pnode = _Pnext)
        {   // delete an element
        _Pnext = this->_Nextnode(_Pnode); //Unhandled exception, access violation
        this->_Freenode(_Pnode);
        }
    }

Here's the only container I'm using std::list in currently and I only have 1 of them ... if I switch std::list to std::vector then it works fine.

这是我目前使用的唯一一个容器:列表,我只有一个……如果我将std::list转换为std::vector那么它就可以工作了。

#pragma once
#ifndef EVENT_H
#define EVENT_H
#include <delegate.h>
#include <list>
#include <vector>

using fd::delegate;

template<typename... Args>
class Event;

template<typename...Args>
class Event<void(Args...)>
{
 private:
std::list<delegate<void(Args...)>> m_delegates;
 public:
void addListener(const delegate<void(Args...)>& d)
{
    if (d)
    m_delegates.push_back(d);
}

void removeListener(const delegate<void(Args...)>& d)
{
    if (d)
    m_delegates.remove(d);
}

void removeDeadListeners()
{
    for (auto i = m_delegates.begin(); i != m_delegates.end(); i++)
    {
        if (i->empty())
            m_delegates.remove(i);
    }
}

void operator()(Args... args)
{
    for (auto& d : m_delegates)
    {
        d(args...);
    }
}
};

#endif //EVENT_H

Any way to use std::list?

有使用std::list的方法吗?

2 个解决方案

#1


3  

I believe your problem is that you're removing items from the list while iterating over it, but I'm surprised the code you've shown compiles at all.

我认为您的问题是在迭代时从列表中删除项目,但我对您所显示的编译代码感到惊讶。

for (auto i = m_delegates.begin(); i != m_delegates.end(); i++)
{
    if (i->empty())
        m_delegates.remove(i);  // <-- This shouldn't compile
}

list::remove takes a list::value_type as the argument, and not list::iterator, so the above should fail to compile. The solution is to use list::erase

list::remove使用一个list::value_type作为参数,而不是list:::iterator,因此上面的代码应该无法编译。解决办法是使用列表:::擦除

for (auto i = m_delegates.begin(); i != m_delegates.end(); )
{
    if (i->empty())
        i = m_delegates.erase(i); // get iterator to next element
    else
        ++i;
}

You could also eliminate the loop completely and use list::remove_if

您还可以完全消除循环并使用list::remove_if

m_delegates.remove_if([](decltype(m_delegates)::value_type const& elem) {
    return elem.empty();
});

#2


0  

I've determined it's just something to do with the class it is declared in as I can use Event fine in other classes ..... I'm just confused because I NEVER call a single method. I'm just modifying a tutorial code to make it a bit easier to work with for a test project of mine. The default constructor works fine for other classes and I can add / call methods fine it's just this one ... I'm stumped.

我已经确定了它只是与它的类有关它被声明为我可以在其他类中使用事件fine…我很困惑,因为我从来没有调用过一个方法。我只是修改了一段教程代码,以便在我的测试项目中更容易使用。默认的构造函数对其他类都适用,我可以添加/调用方法很好,就是这个。我难住了。

The .h

. h的

#pragma once
#ifndef D3DAPP_H
#define D3DAPP_H
#pragma warning(push)
#pragma warning( disable : 4005) //Ignore Identical Macro declarations that exist in Windows and DirectX headers
#include <D3D11.h>
#include <D3DX11.h>
#include <Windows.h>
#pragma warning(pop)
#include "GameTimer.h"
#include <string>
#include "Event.h"

class D3DApp
{
public:
    D3DApp(HINSTANCE hInstance);
    virtual ~D3DApp();

    HINSTANCE AppInst() const;
    HWND MainWnd() const;
    float AspectRatio() const;

    int Run();
    /*
        Framework methods. Derived client class overrides these methods
        to implement specific application requirements
    */
    virtual bool Init();
    virtual void Release();
    Event<void(int,int)> OnResize;
    virtual void UpdateScene(float dt) = 0;
    virtual void DrawScene() = 0;
    virtual LRESULT MsgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
    //Convenience overrides for handling mouse input
    virtual void OnMouseDown(WPARAM btnState, int x, int y);
    virtual void OnMouseUp(WPARAM btnState, int x, int y);
    virtual void OnMouseMove(WPARAM btnState, int x, int y);
protected:
    virtual void ApplicationResize(int w, int h);
    bool InitMainWindow();
    bool InitDirect3D();
    void CalculateFrameStats();
protected:
    HINSTANCE mAppInstance;
    HWND mMainWnd;
    bool mAppPaused;
    bool mMinimized;
    bool mMaximized;
    bool mResizing;
    bool mInitialized;
    UINT m4xMsaaQuality;

    GameTimer mTimer;

    ID3D11Device* md3dDevice;
    ID3D11DeviceContext* md3dImmediateContext;
    IDXGISwapChain* mSwapChain;
    ID3D11Texture2D* mDepthStencilBuffer;
    ID3D11RenderTargetView* mRenderTargetView;
    ID3D11DepthStencilView* mDepthStencilView;
    D3D11_VIEWPORT mScreenViewport;

    std::wstring mMainWndCaption;
    D3D_DRIVER_TYPE md3dDriverType;
    int mClientWidth;
    int mClientHeight;
    bool mEnable4xMsaa;
};

#endif //D3DAPP_H

The .cpp

cpp里面

#include "d3dApp.h"
#include "Utility.h"
#include <assert.h>
#include <sstream>

D3DApp* g_d3dApp = 0;

LRESULT CALLBACK
MainWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
    return g_d3dApp->MsgProc(hwnd, msg, wParam,lParam);
}

D3DApp::D3DApp(HINSTANCE hInstance)
    : mAppInstance(hInstance),
    mMainWndCaption(L"D3D11 Application"),
    md3dDriverType(D3D_DRIVER_TYPE_HARDWARE),
    mClientWidth(800),
    mClientHeight(600),
    mEnable4xMsaa(false),
    mMainWnd(0),
    mAppPaused(false),
    mMinimized(false),
    mMaximized(false),
    mResizing(false),
    mInitialized(false),
    m4xMsaaQuality(0),
    md3dDevice(0),
    md3dImmediateContext(0),
    mSwapChain(0),
    mDepthStencilBuffer(0),
    mRenderTargetView(0),
    mDepthStencilView(0)
{
    ZeroMemory(&mScreenViewport, sizeof(D3D11_VIEWPORT));
    g_d3dApp = this;
}


void D3DApp::Release()
{
    ReleaseCOM(mRenderTargetView);
    ReleaseCOM(mDepthStencilView);
    ReleaseCOM(mSwapChain);
    ReleaseCOM(mDepthStencilBuffer);

    if (md3dImmediateContext)
        md3dImmediateContext->ClearState();

    ReleaseCOM(md3dImmediateContext);
    ReleaseCOM(md3dDevice);
    if (g_d3dApp == this)
        g_d3dApp = nullptr;

    mInitialized = false;
}

D3DApp::~D3DApp()
{
    if (mInitialized) Release();
}

float D3DApp::AspectRatio() const
{
    return static_cast<float>(mClientWidth) / mClientHeight;
}

int D3DApp::Run()
{
    MSG msg = { 0 };
    mTimer.Reset();

    while (msg.message != WM_QUIT)
    {
        if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        else
        {
            mTimer.Tick();

            CalculateFrameStats();
            UpdateScene(mTimer.DeltaTime());
            DrawScene();
        }
    }

    return (int)msg.wParam;
}

bool D3DApp::Init()
{
    if (!InitMainWindow())
        return false;

    if (!InitDirect3D())
        return false;

    mInitialized = true;
    return true;
}

void D3DApp::ApplicationResize(int w,int h)
{
    assert(md3dImmediateContext);
    assert(md3dDevice);
    assert(mSwapChain);

    ReleaseCOM(mRenderTargetView);
    ReleaseCOM(mDepthStencilView);
    ReleaseCOM(mDepthStencilBuffer);

    mClientWidth = w;
    mClientHeight = h;

    HR(mSwapChain->ResizeBuffers(1, mClientWidth, mClientHeight, DXGI_FORMAT_R8G8B8A8_UNORM, 0));
    ID3D11Texture2D* backBuffer;
    HR(mSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&backBuffer)));
    HR(md3dDevice->CreateRenderTargetView(backBuffer, 0, &mRenderTargetView));
    ReleaseCOM(backBuffer);

    D3D11_TEXTURE2D_DESC depthStencilDesc;
    ZeroMemory(&depthStencilDesc, sizeof(D3D11_TEXTURE2D_DESC));
    depthStencilDesc.Width = mClientWidth;
    depthStencilDesc.Height = mClientHeight;
    depthStencilDesc.MipLevels = 1;
    depthStencilDesc.ArraySize = 1;
    depthStencilDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;

    if (mEnable4xMsaa)
    {
        depthStencilDesc.SampleDesc.Count = 4;
        depthStencilDesc.SampleDesc.Quality = m4xMsaaQuality - 1;
    } //No MSAA
    else
    {
        depthStencilDesc.SampleDesc.Count = 1;
        depthStencilDesc.SampleDesc.Quality = 0;
    }

    depthStencilDesc.Usage = D3D11_USAGE_DEFAULT;
    depthStencilDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
    depthStencilDesc.CPUAccessFlags = 0;
    depthStencilDesc.MipLevels = 0;

    HR(md3dDevice->CreateTexture2D(&depthStencilDesc, 0, &mDepthStencilBuffer));
    HR(md3dDevice->CreateDepthStencilView(mDepthStencilBuffer, 0, &mDepthStencilView));

    md3dImmediateContext->OMSetRenderTargets(1, &mRenderTargetView,mDepthStencilView);

    mScreenViewport.TopLeftX = 0;
    mScreenViewport.TopLeftY = 0;
    mScreenViewport.Width = static_cast<float>(mClientWidth);
    mScreenViewport.Height = static_cast<float>(mClientWidth);
    mScreenViewport.MinDepth = 0.0f;
    mScreenViewport.MaxDepth = 1.0f;

    md3dImmediateContext->RSSetViewports(1, &mScreenViewport);

    //OnResize(w, h);
}

LRESULT D3DApp::MsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    //Ignore messages until we have intialized everything
    if (!mInitialized) 
        return DefWindowProc(hWnd, msg, wParam, lParam);

    switch (msg)
    {
    case WM_ACTIVATE:
        if (LOWORD(wParam) == WA_INACTIVE)
        {
            mAppPaused = true;
            mTimer.Stop();
        }
        else
        {
            mAppPaused = false;
            mTimer.Start();
        }
        return 0;
    case WM_SIZE:
        if (wParam == SIZE_MINIMIZED)
        {
            mAppPaused = true;
            mMinimized = true;
            mMaximized = false;
            mTimer.Stop();
        }
        else if (wParam == SIZE_MAXIMIZED)
        {
            mAppPaused = SIZE_MAXIMIZED;
            mMinimized = false;
            mMaximized = true;
            ApplicationResize(LOWORD(lParam), HIWORD(lParam));
        }
        else if (wParam == SIZE_RESTORED)
        {
            if (mMinimized)
            {
                mAppPaused = false;
                mMinimized = false;
                mTimer.Start();
                ApplicationResize(LOWORD(lParam), HIWORD(lParam));
            }
            else if (mMaximized)
            {
                mAppPaused = false;
                mMaximized = false;
                ApplicationResize(LOWORD(lParam), HIWORD(lParam));
            }
            else if (mResizing)
            {
                //We don't want to do stuff while this is going on
            }
            else
            {
                ApplicationResize(LOWORD(lParam), HIWORD(lParam));
            }
        }
        return 0;
    case WM_ENTERSIZEMOVE:
        mAppPaused = true;
        mResizing = true;
        mTimer.Stop();
        return 0;
    case WM_EXITSIZEMOVE:
        mAppPaused = false;
        mResizing = false;
        mTimer.Start();
        if (lParam != 0)
        ApplicationResize(LOWORD(lParam), HIWORD(lParam));
        return 0;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    case WM_MENUCHAR:
        //Don't beep when we alt-enter
        return MAKELRESULT(0, MNC_CLOSE);
    case WM_GETMINMAXINFO:
        ((MINMAXINFO*)lParam)->ptMinTrackSize.x = 200;
        ((MINMAXINFO*)lParam)->ptMinTrackSize.y = 200;
        return 0;
    case WM_LBUTTONDOWN:
    case WM_MBUTTONDOWN:
    case WM_RBUTTONDOWN:
        OnMouseDown(wParam, LOWORD(lParam), HIWORD(lParam));
        return 0;
    case WM_LBUTTONUP:
    case WM_MBUTTONUP:
    case WM_RBUTTONUP:
        OnMouseUp(wParam, LOWORD(lParam), HIWORD(lParam));
        return 0;
    case WM_MOUSEMOVE:
        OnMouseMove(wParam, LOWORD(lParam), HIWORD(lParam));
        return 0;
    }

    return DefWindowProc(hWnd, msg, wParam, lParam);
}

bool D3DApp::InitMainWindow()
{
    WNDCLASS wc;
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = MainWndProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = mAppInstance;
    wc.hIcon = LoadIcon(0, IDI_APPLICATION);
    wc.hCursor = LoadCursor(0, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH);
    wc.lpszMenuName = 0;
    wc.lpszClassName = L"D3DWndClassName";

    if (!RegisterClass(&wc))
    {
        MessageBox(0, L"RegisterClass Failed!", 0, 0);
        return false;
    }

    RECT R = { 0, 0, mClientWidth, mClientHeight };
    AdjustWindowRect(&R, WS_OVERLAPPEDWINDOW, false);
    int width = R.right - R.left;
    int height = R.bottom - R.top;

    mMainWnd = CreateWindow(L"D3DWndClassName", mMainWndCaption.c_str(),
        WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, width, height, 0, 0, mAppInstance, 0);

    if (mMainWnd);
    {
        MessageBox(0, L"CreateWindow Failed", 0, 0); 
        return false;
    }

    ShowWindow(mMainWnd, SW_SHOW);
    UpdateWindow(mMainWnd);

    return true;
}

bool D3DApp::InitDirect3D()
{
    //Create the device and device context
    UINT createDeviceFlags = 0;
#if defined(DEBUG) || defined(_DEBUG)
    createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif
    D3D_FEATURE_LEVEL featureLevel;
    HRESULT hr = D3D11CreateDevice(
        0,
        md3dDriverType,
        0,
        createDeviceFlags,
        0, 0,
        D3D11_SDK_VERSION,
        &md3dDevice,
        &featureLevel,
        &md3dImmediateContext);

    if (FAILED(hr))
    {
        MessageBox(0, L"D3D11CreateDevice Failed.", 0, 0);
        return false;
    }

    if (featureLevel != D3D_FEATURE_LEVEL_11_0)
    {
        MessageBox(0, L"Direct3D Feature Level 11 unsupported", 0, 0);
        return false;
    }

    HR(md3dDevice->CheckMultisampleQualityLevels(
        DXGI_FORMAT_R8G8B8A8_UNORM, 4, &m4xMsaaQuality));

    assert(m4xMsaaQuality > 0);

    DXGI_SWAP_CHAIN_DESC sd;
    sd.BufferDesc.Width = mClientWidth;
    sd.BufferDesc.Height = mClientHeight;
    sd.BufferDesc.RefreshRate.Numerator = 60;
    sd.BufferDesc.RefreshRate.Denominator = 1;
    sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    sd.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
    sd.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;

    if (mEnable4xMsaa)
    {
        sd.SampleDesc.Count = 4;
        sd.SampleDesc.Quality = m4xMsaaQuality - 1;
    }
    else
    {
        sd.SampleDesc.Count = 1;
        sd.SampleDesc.Quality = 0;
    }

    sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    sd.BufferCount = 1;
    sd.OutputWindow = mMainWnd;
    sd.Windowed = true;
    sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
    sd.Flags = 0;

    IDXGIDevice* dxgiDevice = 0;
    HR(md3dDevice->QueryInterface(__uuidof(IDXGIDevice), (void**)&dxgiDevice));

    IDXGIAdapter* dxgiAdapter = 0;
    HR(dxgiDevice->GetParent(__uuidof(IDXGIAdapter), (void**)&dxgiAdapter));

    IDXGIFactory* dxgiFactory = 0;
    HR(dxgiAdapter->GetParent(__uuidof(IDXGIFactory), (void**)&dxgiFactory));

    HR(dxgiFactory->CreateSwapChain(md3dDevice, &sd, &mSwapChain));

    ReleaseCOM(dxgiDevice);
    ReleaseCOM(dxgiAdapter);
    ReleaseCOM(dxgiFactory);

    ApplicationResize(mClientWidth, mClientHeight);

    return true;
}

void D3DApp::CalculateFrameStats()
{
    //Code computes the average frames per second also the average 
    //time it takes to render one frame. These stats
    //are appended to the window caption bar.

    static int frameCnt = 0;
    static float timeElapsed = 0.0f;

    frameCnt++;
    float dt = mTimer.TotalTime() - timeElapsed;
    if (dt >= 1.0f)
    {
        float fps = (float)frameCnt/dt;
        float mspf = 1000.0f / fps; 

        std::wstringstream outs;
        outs.precision(6);
        outs << mMainWndCaption << L"   "
            << L"FPS: " << fps << L"   "
            << L"Frame Time: " << mspf << L" (ms)";
        SetWindowText(mMainWnd, outs.str().c_str());

        frameCnt = 0;
        timeElapsed += dt;
    }
}

void D3DApp::OnMouseDown(WPARAM btnState, int x, int y)
{

}

void D3DApp::OnMouseUp(WPARAM btnState, int x, int y)
{

}
void D3DApp::OnMouseMove(WPARAM btnState, int x, int y)
{

}

#1


3  

I believe your problem is that you're removing items from the list while iterating over it, but I'm surprised the code you've shown compiles at all.

我认为您的问题是在迭代时从列表中删除项目,但我对您所显示的编译代码感到惊讶。

for (auto i = m_delegates.begin(); i != m_delegates.end(); i++)
{
    if (i->empty())
        m_delegates.remove(i);  // <-- This shouldn't compile
}

list::remove takes a list::value_type as the argument, and not list::iterator, so the above should fail to compile. The solution is to use list::erase

list::remove使用一个list::value_type作为参数,而不是list:::iterator,因此上面的代码应该无法编译。解决办法是使用列表:::擦除

for (auto i = m_delegates.begin(); i != m_delegates.end(); )
{
    if (i->empty())
        i = m_delegates.erase(i); // get iterator to next element
    else
        ++i;
}

You could also eliminate the loop completely and use list::remove_if

您还可以完全消除循环并使用list::remove_if

m_delegates.remove_if([](decltype(m_delegates)::value_type const& elem) {
    return elem.empty();
});

#2


0  

I've determined it's just something to do with the class it is declared in as I can use Event fine in other classes ..... I'm just confused because I NEVER call a single method. I'm just modifying a tutorial code to make it a bit easier to work with for a test project of mine. The default constructor works fine for other classes and I can add / call methods fine it's just this one ... I'm stumped.

我已经确定了它只是与它的类有关它被声明为我可以在其他类中使用事件fine…我很困惑,因为我从来没有调用过一个方法。我只是修改了一段教程代码,以便在我的测试项目中更容易使用。默认的构造函数对其他类都适用,我可以添加/调用方法很好,就是这个。我难住了。

The .h

. h的

#pragma once
#ifndef D3DAPP_H
#define D3DAPP_H
#pragma warning(push)
#pragma warning( disable : 4005) //Ignore Identical Macro declarations that exist in Windows and DirectX headers
#include <D3D11.h>
#include <D3DX11.h>
#include <Windows.h>
#pragma warning(pop)
#include "GameTimer.h"
#include <string>
#include "Event.h"

class D3DApp
{
public:
    D3DApp(HINSTANCE hInstance);
    virtual ~D3DApp();

    HINSTANCE AppInst() const;
    HWND MainWnd() const;
    float AspectRatio() const;

    int Run();
    /*
        Framework methods. Derived client class overrides these methods
        to implement specific application requirements
    */
    virtual bool Init();
    virtual void Release();
    Event<void(int,int)> OnResize;
    virtual void UpdateScene(float dt) = 0;
    virtual void DrawScene() = 0;
    virtual LRESULT MsgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
    //Convenience overrides for handling mouse input
    virtual void OnMouseDown(WPARAM btnState, int x, int y);
    virtual void OnMouseUp(WPARAM btnState, int x, int y);
    virtual void OnMouseMove(WPARAM btnState, int x, int y);
protected:
    virtual void ApplicationResize(int w, int h);
    bool InitMainWindow();
    bool InitDirect3D();
    void CalculateFrameStats();
protected:
    HINSTANCE mAppInstance;
    HWND mMainWnd;
    bool mAppPaused;
    bool mMinimized;
    bool mMaximized;
    bool mResizing;
    bool mInitialized;
    UINT m4xMsaaQuality;

    GameTimer mTimer;

    ID3D11Device* md3dDevice;
    ID3D11DeviceContext* md3dImmediateContext;
    IDXGISwapChain* mSwapChain;
    ID3D11Texture2D* mDepthStencilBuffer;
    ID3D11RenderTargetView* mRenderTargetView;
    ID3D11DepthStencilView* mDepthStencilView;
    D3D11_VIEWPORT mScreenViewport;

    std::wstring mMainWndCaption;
    D3D_DRIVER_TYPE md3dDriverType;
    int mClientWidth;
    int mClientHeight;
    bool mEnable4xMsaa;
};

#endif //D3DAPP_H

The .cpp

cpp里面

#include "d3dApp.h"
#include "Utility.h"
#include <assert.h>
#include <sstream>

D3DApp* g_d3dApp = 0;

LRESULT CALLBACK
MainWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
    return g_d3dApp->MsgProc(hwnd, msg, wParam,lParam);
}

D3DApp::D3DApp(HINSTANCE hInstance)
    : mAppInstance(hInstance),
    mMainWndCaption(L"D3D11 Application"),
    md3dDriverType(D3D_DRIVER_TYPE_HARDWARE),
    mClientWidth(800),
    mClientHeight(600),
    mEnable4xMsaa(false),
    mMainWnd(0),
    mAppPaused(false),
    mMinimized(false),
    mMaximized(false),
    mResizing(false),
    mInitialized(false),
    m4xMsaaQuality(0),
    md3dDevice(0),
    md3dImmediateContext(0),
    mSwapChain(0),
    mDepthStencilBuffer(0),
    mRenderTargetView(0),
    mDepthStencilView(0)
{
    ZeroMemory(&mScreenViewport, sizeof(D3D11_VIEWPORT));
    g_d3dApp = this;
}


void D3DApp::Release()
{
    ReleaseCOM(mRenderTargetView);
    ReleaseCOM(mDepthStencilView);
    ReleaseCOM(mSwapChain);
    ReleaseCOM(mDepthStencilBuffer);

    if (md3dImmediateContext)
        md3dImmediateContext->ClearState();

    ReleaseCOM(md3dImmediateContext);
    ReleaseCOM(md3dDevice);
    if (g_d3dApp == this)
        g_d3dApp = nullptr;

    mInitialized = false;
}

D3DApp::~D3DApp()
{
    if (mInitialized) Release();
}

float D3DApp::AspectRatio() const
{
    return static_cast<float>(mClientWidth) / mClientHeight;
}

int D3DApp::Run()
{
    MSG msg = { 0 };
    mTimer.Reset();

    while (msg.message != WM_QUIT)
    {
        if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        else
        {
            mTimer.Tick();

            CalculateFrameStats();
            UpdateScene(mTimer.DeltaTime());
            DrawScene();
        }
    }

    return (int)msg.wParam;
}

bool D3DApp::Init()
{
    if (!InitMainWindow())
        return false;

    if (!InitDirect3D())
        return false;

    mInitialized = true;
    return true;
}

void D3DApp::ApplicationResize(int w,int h)
{
    assert(md3dImmediateContext);
    assert(md3dDevice);
    assert(mSwapChain);

    ReleaseCOM(mRenderTargetView);
    ReleaseCOM(mDepthStencilView);
    ReleaseCOM(mDepthStencilBuffer);

    mClientWidth = w;
    mClientHeight = h;

    HR(mSwapChain->ResizeBuffers(1, mClientWidth, mClientHeight, DXGI_FORMAT_R8G8B8A8_UNORM, 0));
    ID3D11Texture2D* backBuffer;
    HR(mSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&backBuffer)));
    HR(md3dDevice->CreateRenderTargetView(backBuffer, 0, &mRenderTargetView));
    ReleaseCOM(backBuffer);

    D3D11_TEXTURE2D_DESC depthStencilDesc;
    ZeroMemory(&depthStencilDesc, sizeof(D3D11_TEXTURE2D_DESC));
    depthStencilDesc.Width = mClientWidth;
    depthStencilDesc.Height = mClientHeight;
    depthStencilDesc.MipLevels = 1;
    depthStencilDesc.ArraySize = 1;
    depthStencilDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;

    if (mEnable4xMsaa)
    {
        depthStencilDesc.SampleDesc.Count = 4;
        depthStencilDesc.SampleDesc.Quality = m4xMsaaQuality - 1;
    } //No MSAA
    else
    {
        depthStencilDesc.SampleDesc.Count = 1;
        depthStencilDesc.SampleDesc.Quality = 0;
    }

    depthStencilDesc.Usage = D3D11_USAGE_DEFAULT;
    depthStencilDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
    depthStencilDesc.CPUAccessFlags = 0;
    depthStencilDesc.MipLevels = 0;

    HR(md3dDevice->CreateTexture2D(&depthStencilDesc, 0, &mDepthStencilBuffer));
    HR(md3dDevice->CreateDepthStencilView(mDepthStencilBuffer, 0, &mDepthStencilView));

    md3dImmediateContext->OMSetRenderTargets(1, &mRenderTargetView,mDepthStencilView);

    mScreenViewport.TopLeftX = 0;
    mScreenViewport.TopLeftY = 0;
    mScreenViewport.Width = static_cast<float>(mClientWidth);
    mScreenViewport.Height = static_cast<float>(mClientWidth);
    mScreenViewport.MinDepth = 0.0f;
    mScreenViewport.MaxDepth = 1.0f;

    md3dImmediateContext->RSSetViewports(1, &mScreenViewport);

    //OnResize(w, h);
}

LRESULT D3DApp::MsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    //Ignore messages until we have intialized everything
    if (!mInitialized) 
        return DefWindowProc(hWnd, msg, wParam, lParam);

    switch (msg)
    {
    case WM_ACTIVATE:
        if (LOWORD(wParam) == WA_INACTIVE)
        {
            mAppPaused = true;
            mTimer.Stop();
        }
        else
        {
            mAppPaused = false;
            mTimer.Start();
        }
        return 0;
    case WM_SIZE:
        if (wParam == SIZE_MINIMIZED)
        {
            mAppPaused = true;
            mMinimized = true;
            mMaximized = false;
            mTimer.Stop();
        }
        else if (wParam == SIZE_MAXIMIZED)
        {
            mAppPaused = SIZE_MAXIMIZED;
            mMinimized = false;
            mMaximized = true;
            ApplicationResize(LOWORD(lParam), HIWORD(lParam));
        }
        else if (wParam == SIZE_RESTORED)
        {
            if (mMinimized)
            {
                mAppPaused = false;
                mMinimized = false;
                mTimer.Start();
                ApplicationResize(LOWORD(lParam), HIWORD(lParam));
            }
            else if (mMaximized)
            {
                mAppPaused = false;
                mMaximized = false;
                ApplicationResize(LOWORD(lParam), HIWORD(lParam));
            }
            else if (mResizing)
            {
                //We don't want to do stuff while this is going on
            }
            else
            {
                ApplicationResize(LOWORD(lParam), HIWORD(lParam));
            }
        }
        return 0;
    case WM_ENTERSIZEMOVE:
        mAppPaused = true;
        mResizing = true;
        mTimer.Stop();
        return 0;
    case WM_EXITSIZEMOVE:
        mAppPaused = false;
        mResizing = false;
        mTimer.Start();
        if (lParam != 0)
        ApplicationResize(LOWORD(lParam), HIWORD(lParam));
        return 0;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    case WM_MENUCHAR:
        //Don't beep when we alt-enter
        return MAKELRESULT(0, MNC_CLOSE);
    case WM_GETMINMAXINFO:
        ((MINMAXINFO*)lParam)->ptMinTrackSize.x = 200;
        ((MINMAXINFO*)lParam)->ptMinTrackSize.y = 200;
        return 0;
    case WM_LBUTTONDOWN:
    case WM_MBUTTONDOWN:
    case WM_RBUTTONDOWN:
        OnMouseDown(wParam, LOWORD(lParam), HIWORD(lParam));
        return 0;
    case WM_LBUTTONUP:
    case WM_MBUTTONUP:
    case WM_RBUTTONUP:
        OnMouseUp(wParam, LOWORD(lParam), HIWORD(lParam));
        return 0;
    case WM_MOUSEMOVE:
        OnMouseMove(wParam, LOWORD(lParam), HIWORD(lParam));
        return 0;
    }

    return DefWindowProc(hWnd, msg, wParam, lParam);
}

bool D3DApp::InitMainWindow()
{
    WNDCLASS wc;
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = MainWndProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = mAppInstance;
    wc.hIcon = LoadIcon(0, IDI_APPLICATION);
    wc.hCursor = LoadCursor(0, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH);
    wc.lpszMenuName = 0;
    wc.lpszClassName = L"D3DWndClassName";

    if (!RegisterClass(&wc))
    {
        MessageBox(0, L"RegisterClass Failed!", 0, 0);
        return false;
    }

    RECT R = { 0, 0, mClientWidth, mClientHeight };
    AdjustWindowRect(&R, WS_OVERLAPPEDWINDOW, false);
    int width = R.right - R.left;
    int height = R.bottom - R.top;

    mMainWnd = CreateWindow(L"D3DWndClassName", mMainWndCaption.c_str(),
        WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, width, height, 0, 0, mAppInstance, 0);

    if (mMainWnd);
    {
        MessageBox(0, L"CreateWindow Failed", 0, 0); 
        return false;
    }

    ShowWindow(mMainWnd, SW_SHOW);
    UpdateWindow(mMainWnd);

    return true;
}

bool D3DApp::InitDirect3D()
{
    //Create the device and device context
    UINT createDeviceFlags = 0;
#if defined(DEBUG) || defined(_DEBUG)
    createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif
    D3D_FEATURE_LEVEL featureLevel;
    HRESULT hr = D3D11CreateDevice(
        0,
        md3dDriverType,
        0,
        createDeviceFlags,
        0, 0,
        D3D11_SDK_VERSION,
        &md3dDevice,
        &featureLevel,
        &md3dImmediateContext);

    if (FAILED(hr))
    {
        MessageBox(0, L"D3D11CreateDevice Failed.", 0, 0);
        return false;
    }

    if (featureLevel != D3D_FEATURE_LEVEL_11_0)
    {
        MessageBox(0, L"Direct3D Feature Level 11 unsupported", 0, 0);
        return false;
    }

    HR(md3dDevice->CheckMultisampleQualityLevels(
        DXGI_FORMAT_R8G8B8A8_UNORM, 4, &m4xMsaaQuality));

    assert(m4xMsaaQuality > 0);

    DXGI_SWAP_CHAIN_DESC sd;
    sd.BufferDesc.Width = mClientWidth;
    sd.BufferDesc.Height = mClientHeight;
    sd.BufferDesc.RefreshRate.Numerator = 60;
    sd.BufferDesc.RefreshRate.Denominator = 1;
    sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    sd.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
    sd.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;

    if (mEnable4xMsaa)
    {
        sd.SampleDesc.Count = 4;
        sd.SampleDesc.Quality = m4xMsaaQuality - 1;
    }
    else
    {
        sd.SampleDesc.Count = 1;
        sd.SampleDesc.Quality = 0;
    }

    sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    sd.BufferCount = 1;
    sd.OutputWindow = mMainWnd;
    sd.Windowed = true;
    sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
    sd.Flags = 0;

    IDXGIDevice* dxgiDevice = 0;
    HR(md3dDevice->QueryInterface(__uuidof(IDXGIDevice), (void**)&dxgiDevice));

    IDXGIAdapter* dxgiAdapter = 0;
    HR(dxgiDevice->GetParent(__uuidof(IDXGIAdapter), (void**)&dxgiAdapter));

    IDXGIFactory* dxgiFactory = 0;
    HR(dxgiAdapter->GetParent(__uuidof(IDXGIFactory), (void**)&dxgiFactory));

    HR(dxgiFactory->CreateSwapChain(md3dDevice, &sd, &mSwapChain));

    ReleaseCOM(dxgiDevice);
    ReleaseCOM(dxgiAdapter);
    ReleaseCOM(dxgiFactory);

    ApplicationResize(mClientWidth, mClientHeight);

    return true;
}

void D3DApp::CalculateFrameStats()
{
    //Code computes the average frames per second also the average 
    //time it takes to render one frame. These stats
    //are appended to the window caption bar.

    static int frameCnt = 0;
    static float timeElapsed = 0.0f;

    frameCnt++;
    float dt = mTimer.TotalTime() - timeElapsed;
    if (dt >= 1.0f)
    {
        float fps = (float)frameCnt/dt;
        float mspf = 1000.0f / fps; 

        std::wstringstream outs;
        outs.precision(6);
        outs << mMainWndCaption << L"   "
            << L"FPS: " << fps << L"   "
            << L"Frame Time: " << mspf << L" (ms)";
        SetWindowText(mMainWnd, outs.str().c_str());

        frameCnt = 0;
        timeElapsed += dt;
    }
}

void D3DApp::OnMouseDown(WPARAM btnState, int x, int y)
{

}

void D3DApp::OnMouseUp(WPARAM btnState, int x, int y)
{

}
void D3DApp::OnMouseMove(WPARAM btnState, int x, int y)
{

}