<commit_before>// Copyright (C) 2016 <NAME>
// This file is part of the Ouzel engine.

#include "RendererD3D11.h"
#include "core/Engine.h"
#include "TextureD3D11.h"
#include "ShaderD3D11.h"
#include "MeshBufferD3D11.h"
#include "RenderTargetD3D11.h"
#include "utils/Utils.h"
#include "TexturePSD3D11.h"
#include "TextureVSD3D11.h"
#include "ColorPSD3D11.h"
#include "ColorVSD3D11.h"
#include "scene/Camera.h"
#include "core/Cache.h"
#include "BlendStateD3D11.h"
#include "win/WindowWin.h"
#include "stb_image_write.h"

using namespace ouzel;

namespace ouzel
{
    namespace graphics
    {
        RendererD3D11::RendererD3D11():
            Renderer(Driver::DIRECT3D11)
        {
            apiVersion = 11;
        }

        RendererD3D11::~RendererD3D11()
        {
            if (depthStencilState)
            {
                depthStencilState->Release();
            }

            if (scissorTestRasterizerState)
            {
                scissorTestRasterizerState->Release();
            }

            if (rasterizerState)
            {
                rasterizerState->Release();
            }

            if (samplerState)
            {
                samplerState->Release();
            }

            if (renderTargetView)
            {
                renderTargetView->Release();
            }

            if (backBuffer)
            {
                backBuffer->Release();
            }

            if (swapChain)
            {
                swapChain->Release();
            }

            if (adapter)
            {
                adapter->Release();
            }
        }

        void RendererD3D11::free()
        {
            Renderer::free();

            if (depthStencilState)
            {
                depthStencilState->Release();
                depthStencilState = nullptr;
            }

            if (scissorTestRasterizerState)
            {
                scissorTestRasterizerState->Release();
                scissorTestRasterizerState = nullptr;
            }

            if (rasterizerState)
            {
                rasterizerState->Release();
                rasterizerState = nullptr;
            }

            if (samplerState)
            {
                samplerState->Release();
                samplerState = nullptr;
            }

            if (renderTargetView)
            {
                renderTargetView->Release();
                renderTargetView = nullptr;
            }

            if (backBuffer)
            {
                backBuffer->Release();
                backBuffer= nullptr;
            }

            if (swapChain)
            {
                swapChain->Release();
                swapChain = nullptr;
            }

            if (adapter)
            {
                adapter->Release();
                adapter = nullptr;
            }
        }

        bool RendererD3D11::init(const WindowPtr& window,
                                 uint32_t newSampleCount,
                                 TextureFiltering newTextureFiltering,
                                 float newTargetFPS,
                                 bool newVerticalSync)
        {
            if (!Renderer::init(window, newSampleCount, newTextureFiltering, newTargetFPS, newVerticalSync))
            {
                return false;
            }

            free();

            UINT deviceCreationFlags = 0;
    #if D3D11_DEBUG
            deviceCreationFlags |= D3D11_CREATE_DEVICE_DEBUG;
    #endif

            HRESULT hr = D3D11CreateDevice(
                nullptr, // adapter
                D3D_DRIVER_TYPE_HARDWARE,
                nullptr, // software rasterizer (unused)
                deviceCreationFlags,
                nullptr, // feature levels
                0, // no feature levels
                D3D11_SDK_VERSION,
                &device,
                nullptr,
                &context);

            if (FAILED(hr))
            {
                log("Failed to create the D3D11 device");
                return false;
            }

            IDXGIDevice* dxgiDevice;
            IDXGIFactory* factory;

            device->QueryInterface(IID_IDXGIDevice, (void**)&dxgiDevice);
            dxgiDevice->GetParent(IID_IDXGIAdapter, (void**)&adapter);
            hr = adapter->GetParent(IID_IDXGIFactory, (void**)&factory);
            if (FAILED(hr))
            {
                log("Failed to get the DXGI factory");
                return false;
            }

            std::shared_ptr<WindowWin> windowWin = std::static_pointer_cast<WindowWin>(window);

            DXGI_SWAP_CHAIN_DESC swapChainDesc;
            memset(&swapChainDesc, 0, sizeof(swapChainDesc));

            swapChainDesc.BufferDesc.Width = static_cast<UINT>(size.width);
            swapChainDesc.BufferDesc.Height = static_cast<UINT>(size.height);
            swapChainDesc.BufferDesc.RefreshRate.Numerator = 0;
            swapChainDesc.BufferDesc.RefreshRate.Denominator = 1;
            swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
            swapChainDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_PROGRESSIVE;
            swapChainDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_STRETCHED;
            swapChainDesc.SampleDesc.Count = sampleCount;
            swapChainDesc.SampleDesc.Quality = 0;
            swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
            swapChainDesc.BufferCount = 1;
            swapChainDesc.OutputWindow = windowWin->getNativeWindow();
            swapChainDesc.Windowed = static_cast<BOOL>(!fullscreen);
            swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
            swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;

            swapInterval = verticalSync ? 1 : 0;

            hr = factory->CreateSwapChain(device, &swapChainDesc, &swapChain);
            if (FAILED(hr))
            {
                log("Failed to create the D3D11 swap chain");
                return false;
            }

            factory->MakeWindowAssociation(windowWin->getNativeWindow(), DXGI_MWA_NO_ALT_ENTER);

            factory->Release();
            dxgiDevice->Release();

            // Backbuffer
            hr = swapChain->GetBuffer(0, IID_ID3D11Texture2D, reinterpret_cast<void**>(&backBuffer));
            if (FAILED(hr))
            {
                log("Failed to retrieve D3D11 backbuffer");
                return false;
            }

            hr = device->CreateRenderTargetView(backBuffer, nullptr, &renderTargetView);
            if (FAILED(hr))
            {
                log("Failed to create D3D11 render target view");
                return false;
            }

            // Sampler state
            D3D11_SAMPLER_DESC samplerStateDesc;
            switch (textureFiltering)
            {
                case Renderer::TextureFiltering::NONE:
                    samplerStateDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
                    break;
                case Renderer::TextureFiltering::LINEAR:
                    samplerStateDesc.Filter = D3D11_FILTER_MIN_MAG_POINT_MIP_LINEAR;
                    break;
                case Renderer::TextureFiltering::BILINEAR:
                    samplerStateDesc.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT;
                    break;
                case Renderer::TextureFiltering::TRILINEAR:
                    samplerStateDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
                    break;
            }
            samplerStateDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
            samplerStateDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
            samplerStateDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
            samplerStateDesc.MipLODBias = 0.0f;
            samplerStateDesc.MaxAnisotropy = 1;
            samplerStateDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;

            samplerStateDesc.BorderColor[0] = 0.0f;
            samplerStateDesc.BorderColor[1] = 0.0f;
            samplerStateDesc.BorderColor[2] = 0.0f;
            samplerStateDesc.BorderColor[3] = 0.0f;

            samplerStateDesc.MinLOD = 0.0f;
            samplerStateDesc.MaxLOD = D3D11_FLOAT32_MAX;

            hr = device->CreateSamplerState(&samplerStateDesc, &samplerState);
            if (FAILED(hr))
            {
                log("Failed to create D3D11 sampler state");
                return false;
            }

            // Rasterizer state
            D3D11_RASTERIZER_DESC rasterStateDesc =
            {
                D3D11_FILL_SOLID,
                D3D11_CULL_NONE,
                FALSE, // front = ccw?
                0, 0, 0, // depth bias, clamp, slope scale
                FALSE, // depth clip
                FALSE, // scissor test
                (sampleCount > 1) ? TRUE : FALSE, // MSAA
                TRUE, // AA lines
            };

            hr = device->CreateRasterizerState(&rasterStateDesc, &rasterizerState);
            if (FAILED(hr))
            {
                log("Failed to create D3D11 rasterizer state");
                return false;
            }

            rasterStateDesc.ScissorEnable = TRUE;

            hr = device->CreateRasterizerState(&rasterStateDesc, &scissorTestRasterizerState);
            if (FAILED(hr))
            {
                log("Failed to create D3D11 rasterizer state");
                return false;
            }

            // Depth/stencil state
            D3D11_DEPTH_STENCIL_DESC depthStencilStateDesc =
            {
                FALSE, // disable depth test
            };
            hr = device->CreateDepthStencilState(&depthStencilStateDesc, &depthStencilState);
            if (FAILED(hr))
            {
                log("Failed to create D3D11 depth stencil state");
                return false;
            }

            ShaderPtr textureShader = createShader();
            textureShader->initFromBuffers(TEXTURE_PIXEL_SHADER_D3D11, sizeof(TEXTURE_PIXEL_SHADER_D3D11),
                                           TEXTURE_VERTEX_SHADER_D3D11, sizeof(TEXTURE_VERTEX_SHADER_D3D11),
                                           VertexPCT::ATTRIBUTES);

            textureShader->setVertexShaderConstantInfo({{"modelViewProj", sizeof(Matrix4)}});
            textureShader->setPixelShaderConstantInfo({{"color", 4 * sizeof(float)}}, 256);

            sharedEngine->getCache()->setShader(SHADER_TEXTURE, textureShader);

            ShaderPtr colorShader = createShader();
            colorShader->initFromBuffers(COLOR_PIXEL_SHADER_D3D11, sizeof(COLOR_PIXEL_SHADER_D3D11),
                                         COLOR_VERTEX_SHADER_D3D11, sizeof(COLOR_VERTEX_SHADER_D3D11),
                                         VertexPC::ATTRIBUTES);

            colorShader->setVertexShaderConstantInfo({{"modelViewProj", sizeof(Matrix4)}});
            colorShader->setPixelShaderConstantInfo({{"color", 4 * sizeof(float)}}, 256);

            sharedEngine->getCache()->setShader(SHADER_COLOR, colorShader);

            BlendStatePtr noBlendState = createBlendState();

            noBlendState->init(false,
                               BlendState::BlendFactor::ONE, BlendState::BlendFactor::ZERO,
                               BlendState::BlendOperation::ADD,
                               BlendState::BlendFactor::ONE, BlendState::BlendFactor::ZERO,
                               BlendState::BlendOperation::ADD);

            sharedEngine->getCache()->setBlendState(BLEND_NO_BLEND, noBlendState);

            BlendStatePtr addBlendState = createBlendState();

            addBlendState->init(true,
                                BlendState::BlendFactor::ONE, BlendState::BlendFactor::ONE,
                                BlendState::BlendOperation::ADD,
                                BlendState::BlendFactor::ONE, BlendState::BlendFactor::ONE,
                                BlendState::BlendOperation::ADD);

            sharedEngine->getCache()->setBlendState(BLEND_ADD, addBlendState);

            BlendStatePtr multiplyBlendState = createBlendState();

            multiplyBlendState->init(true,
                                     BlendState::BlendFactor::DEST_COLOR, BlendState::BlendFactor::ZERO,
                                     BlendState::BlendOperation::ADD,
                                     BlendState::BlendFactor::ONE, BlendState::BlendFactor::ONE,
                                     BlendState::BlendOperation::ADD);

            sharedEngine->getCache()->setBlendState(BLEND_MULTIPLY, multiplyBlendState);

            BlendStatePtr alphaBlendState = createBlendState();

            alphaBlendState->init(true,
                                  BlendState::BlendFactor::SRC_ALPHA, BlendState::BlendFactor::INV_SRC_ALPHA,
                                  BlendState::BlendOperation::ADD,
                                  BlendState::BlendFactor::ONE, BlendState::BlendFactor::ONE,
                                  BlendState::BlendOperation::ADD);

            sharedEngine->getCache()->setBlendState(BLEND_ALPHA, alphaBlendState);

            memset(&resourceViews, 0, sizeof(resourceViews));
            memset(&samplerStates, 0, sizeof(samplerStates));

            ready = true;

            setSize(size);

            return true;
        }

        void RendererD3D11::clear()
        {
            Renderer::clear();

            clearedRenderTargetViews.clear();

            context->RSSetState(rasterizerState);
        }

        void RendererD3D11::present()
        {
            Renderer::present();

            swapChain->Present(swapInterval, 0);
        }

        IDXGIOutput* RendererD3D11::getOutput() const
        {
            std::shared_ptr<WindowWin> windowWin = std::static_pointer_cast<WindowWin>(sharedEngine->getWindow());

            HMONITOR monitor = windowWin->getMonitor();

            if (!monitor)
            {
                log("Window is not on any monitor");
                return nullptr;
            }

            UINT i = 0;
            IDXGIOutput* output;
            DXGI_OUTPUT_DESC outputDesc;
            HRESULT hr;

            while (adapter->EnumOutputs(i, &output) != DXGI_ERROR_NOT_FOUND)
            {
                hr = output->GetDesc(&outputDesc);

                if (SUCCEEDED(hr) && outputDesc.Monitor == monitor)
                {
                    return output;
                }

                output->Release();

                ++i;
            }

            return nullptr;
        }

        std::vector<Size2> RendererD3D11::getSupportedResolutions() const
        {
            std::vector<Size2> result;

            IDXGIOutput* output = getOutput();

            if (!output)
            {
                return result;
            }

            UINT numModes = 0;
            DXGI_FORMAT format = DXGI_FORMAT_R8G8B8A8_UNORM;
            HRESULT hr = output->GetDisplayModeList(format, 0, &numModes, nullptr);
            if (FAILED(hr))
            {
                log("Failed to get display mode list");
                output->Release();
            }

            if (numModes > 0)
            {
                std::vector<DXGI_MODE_DESC> displayModes(numModes);
                output->GetDisplayModeList(format, 0, &numModes, displayModes.data());

                for (const DXGI_MODE_DESC& displayMode : displayModes)
                {
                    result.push_back(Size2(static_cast<float>(displayMode.Width),
                                           static_cast<float>(displayMode.Height)));
                }
            }

            output->Release();

            return result;
        }

        void RendererD3D11::setSize(const Size2& newSize)
        {
            Renderer::setSize(newSize);

            if (swapChain)
            {
                UINT width = static_cast<UINT>(size.width);
                UINT height = static_cast<UINT>(size.height);

                if (renderTargetView)
                {
                    renderTargetView->Release();
                    renderTargetView = nullptr;
                }

                if (backBuffer)
                {
                    backBuffer->Release();
                    backBuffer = nullptr;
                }

                swapChain->ResizeBuffers(0, width, height, DXGI_FORMAT_UNKNOWN, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH);

                HRESULT hr = swapChain->GetBuffer(0, IID_ID3D11Texture2D, (void**)&backBuffer);
                if (FAILED(hr))
                {
                    log("Failed to retrieve D3D11 backbuffer");
                    return;
                }

                hr = device->CreateRenderTargetView(backBuffer, nullptr, &renderTargetView);
                if (FAILED(hr))
                {
                    log("Failed to create D3D11 render target view");
                    return;
                }

                viewport = { 0, 0, size.width, size.height, 0.0f, 1.0f };

                if (!activeRenderTarget)
                {
                    context->OMSetRenderTargets(1, &renderTargetView, nullptr);
                    context->RSSetViewports(1, &viewport);
                }
            }
        }

        void RendererD3D11::setFullscreen(bool newFullscreen)
        {
            Renderer::setFullscreen(newFullscreen);

            BOOL isFullscreen;
            swapChain->GetFullscreenState(&isFullscreen, nullptr);

            if (isFullscreen != static_cast<BOOL>(fullscreen))
            {
                if (fullscreen)
                {
                    IDXGIOutput* output = getOutput();

                    if (!output)
                    {
                        return;
                    }

                    DXGI_OUTPUT_DESC desc;
                    HRESULT hr = output->GetDesc(&desc);
                    if (FAILED(hr))
                    {
                        output->Release();
                        return;
                    }

                    MONITORINFOEX info;
                    info.cbSize = sizeof(MONITORINFOEX);
                    GetMonitorInfo(desc.Monitor, &info);
                    DEVMODE devMode;
                    devMode.dmSize = sizeof(DEVMODE);
                    devMode.dmDriverExtra = 0;
                    EnumDisplaySettings(info.szDevice, ENUM_CURRENT_SETTINGS, &devMode);

                    DXGI_MODE_DESC current;
                    current.Width = devMode.dmPelsWidth;
                    current.Height = devMode.dmPelsHeight;
                    bool defaultRefreshRate = (devMode.dmDisplayFrequency == 0 || devMode.dmDisplayFrequency == 1);
                    current.RefreshRate.Numerator = defaultRefreshRate ? 0 : devMode.dmDisplayFrequency;
                    current.RefreshRate.Denominator = defaultRefreshRate ? 0 : 1;
                    current.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
                    current.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
                    current.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;

                    DXGI_MODE_DESC closestDisplayMode;
                    hr = output->FindClosestMatchingMode(&current, &closestDisplayMode, nullptr);
                    if (FAILED(hr))
                    {
                        output->Release();
                        return;
                    }

                    setSize(Size2(static_cast<float>(closestDisplayMode.Width),
                                  static_cast<float>(closestDisplayMode.Height)));
                    swapChain->SetFullscreenState(TRUE, output);

                    output->Release();
                }
                else
                {
                    swapChain->SetFullscreenState(FALSE, nullptr);
                }
            }
        }

        BlendStatePtr RendererD3D11::createBlendState()
        {
            std::shared_ptr<BlendStateD3D11> blendState(new BlendStateD3D11());
            return blendState;
        }

        bool RendererD3D11::activateBlendState(BlendStatePtr blendState)
        {
            if (activeBlendState == blendState)
            {
                return true;
            }

            if (!Renderer::activateBlendState(blendState))
            {
                return false;
            }

            if (blendState)
            {
                std::shared_ptr<BlendStateD3D11> blendStateD3D11 = std::static_pointer_cast<BlendStateD3D11>(activeBlendState);

                context->OMSetBlendState(blendStateD3D11->getBlendState(), NULL, 0xffffffff);
            }
            else
            {
                context->OMSetBlendState(NULL, NULL, 0xffffffff);
            }

            return true;
        }

        TexturePtr RendererD3D11::createTexture()
        {
            std::shared_ptr<TextureD3D11> texture(new TextureD3D11());
            return texture;
        }

        bool RendererD3D11::activateTexture(const TexturePtr& texture, uint32_t layer)
        {
            if (activeTextures[layer] == texture)
            {
                return true;
            }

            if (!Renderer::activateTexture(texture, layer))
            {
                return false;
            }

            if (activeTextures[layer])
            {
                std::shared_ptr<TextureD3D11> textureD3D11 = std::static_pointer_cast<TextureD3D11>(activeTextures[layer]);

                resourceViews[layer] = textureD3D11->getResourceView();
                samplerStates[layer] = samplerState;
            }
            else
            {
                resourceViews[layer] = nullptr;
                samplerStates[layer] = nullptr;
            }

            return true;
        }

        RenderTargetPtr RendererD3D11::createRenderTarget()
        {
            std::shared_ptr<RenderTargetD3D11> renderTarget(new RenderTargetD3D11());
            return renderTarget;
        }

        bool RendererD3D11::activateRenderTarget(const RenderTargetPtr& renderTarget)
        {
            if (!Renderer::activateRenderTarget(renderTarget))
            {
                return false;
            }

            ID3D11RenderTargetView* newRenderTargetView = nullptr;
            Color newClearColor;
            D3D11_VIEWPORT newViewport;

            if (activeRenderTarget)
            {
                std::shared_ptr<RenderTargetD3D11> renderTargetD3D11 = std::static_pointer_cast<RenderTargetD3D11>(activeRenderTarget);

                newRenderTargetView = renderTargetD3D11->getRenderTargetView();
                newClearColor = renderTargetD3D11->getClearColor();
                newViewport = renderTargetD3D11->getViewport();
            }
            else
            {
                newRenderTargetView = renderTargetView;
                newClearColor = clearColor;
                newViewport = viewport;
            }

            context->OMSetRenderTargets(1, &newRenderTargetView, nullptr);
            context->RSSetViewports(1, &newViewport);

            if (clearedRenderTargetViews.find(newRenderTargetView) == clearedRenderTargetViews.end())
            {
                float color[4] = { newClearColor.getR(), newClearColor.getG(), newClearColor.getB(), newClearColor.getA() };
                context->ClearRenderTargetView(newRenderTargetView, color);

                clearedRenderTargetViews.insert(newRenderTargetView);
            }

            return true;
        }

        ShaderPtr RendererD3D11::loadShaderFromFiles()
        {
            std::shared_ptr<ShaderD3D11> shader(new ShaderD3D11());
            return shader;
        }

        bool RendererD3D11::activateShader(const ShaderPtr& shader)
        {
            if (activeShader == shader)
            {
                return true;
            }

            if (!Renderer::activateShader(shader))
            {
                return false;
            }
<commit_msg>Fix the name of createShader method<commit_after>// Copyright (C) 2016 <NAME>
// This file is part of the Ouzel engine.

#include "RendererD3D11.h"
#include "core/Engine.h"
#include "TextureD3D11.h"
#include "ShaderD3D11.h"
#include "MeshBufferD3D11.h"
#include "RenderTargetD3D11.h"
#include "utils/Utils.h"
#include "TexturePSD3D11.h"
#include "TextureVSD3D11.h"
#include "ColorPSD3D11.h"
#include "ColorVSD3D11.h"
#include "scene/Camera.h"
#include "core/Cache.h"
#include "BlendStateD3D11.h"
#include "win/WindowWin.h"
#include "stb_image_write.h"

using namespace ouzel;

namespace ouzel
{
    namespace graphics
    {
        RendererD3D11::RendererD3D11():
            Renderer(Driver::DIRECT3D11)
        {
            apiVersion = 11;
        }

        RendererD3D11::~RendererD3D11()
        {
            if (depthStencilState)
            {
                depthStencilState->Release();
            }

            if (scissorTestRasterizerState)
            {
                scissorTestRasterizerState->Release();
            }

            if (rasterizerState)
            {
                rasterizerState->Release();
            }

            if (samplerState)
            {
                samplerState->Release();
            }

            if (renderTargetView)
            {
                renderTargetView->Release();
            }

            if (backBuffer)
            {
                backBuffer->Release();
            }

            if (swapChain)
            {
                swapChain->Release();
            }

            if (adapter)
            {
                adapter->Release();
            }
        }

        void RendererD3D11::free()
        {
            Renderer::free();

            if (depthStencilState)
            {
                depthStencilState->Release();
                depthStencilState = nullptr;
            }

            if (scissorTestRasterizerState)
            {
                scissorTestRasterizerState->Release();
                scissorTestRasterizerState = nullptr;
            }

            if (rasterizerState)
            {
                rasterizerState->Release();
                rasterizerState = nullptr;
            }

            if (samplerState)
            {
                samplerState->Release();
                samplerState = nullptr;
            }

            if (renderTargetView)
            {
                renderTargetView->Release();
                renderTargetView = nullptr;
            }

            if (backBuffer)
            {
                backBuffer->Release();
                backBuffer= nullptr;
            }

            if (swapChain)
            {
                swapChain->Release();
                swapChain = nullptr;
            }

            if (adapter)
            {
                adapter->Release();
                adapter = nullptr;
            }
        }

        bool RendererD3D11::init(const WindowPtr& window,
                                 uint32_t newSampleCount,
                                 TextureFiltering newTextureFiltering,
                                 float newTargetFPS,
                                 bool newVerticalSync)
        {
            if (!Renderer::init(window, newSampleCount, newTextureFiltering, newTargetFPS, newVerticalSync))
            {
                return false;
            }

            free();

            UINT deviceCreationFlags = 0;
    #if D3D11_DEBUG
            deviceCreationFlags |= D3D11_CREATE_DEVICE_DEBUG;
    #endif

            HRESULT hr = D3D11CreateDevice(
                nullptr, // adapter
                D3D_DRIVER_TYPE_HARDWARE,
                nullptr, // software rasterizer (unused)
                deviceCreationFlags,
                nullptr, // feature levels
                0, // no feature levels
                D3D11_SDK_VERSION,
                &device,
                nullptr,
                &context);

            if (FAILED(hr))
            {
                log("Failed to create the D3D11 device");
                return false;
            }

            IDXGIDevice* dxgiDevice;
            IDXGIFactory* factory;

            device->QueryInterface(IID_IDXGIDevice, (void**)&dxgiDevice);
            dxgiDevice->GetParent(IID_IDXGIAdapter, (void**)&adapter);
            hr = adapter->GetParent(IID_IDXGIFactory, (void**)&factory);
            if (FAILED(hr))
            {
                log("Failed to get the DXGI factory");
                return false;
            }

            std::shared_ptr<WindowWin> windowWin = std::static_pointer_cast<WindowWin>(window);

            DXGI_SWAP_CHAIN_DESC swapChainDesc;
            memset(&swapChainDesc, 0, sizeof(swapChainDesc));

            swapChainDesc.BufferDesc.Width = static_cast<UINT>(size.width);
            swapChainDesc.BufferDesc.Height = static_cast<UINT>(size.height);
            swapChainDesc.BufferDesc.RefreshRate.Numerator = 0;
            swapChainDesc.BufferDesc.RefreshRate.Denominator = 1;
            swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
            swapChainDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_PROGRESSIVE;
            swapChainDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_STRETCHED;
            swapChainDesc.SampleDesc.Count = sampleCount;
            swapChainDesc.SampleDesc.Quality = 0;
            swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
            swapChainDesc.BufferCount = 1;
            swapChainDesc.OutputWindow = windowWin->getNativeWindow();
            swapChainDesc.Windowed = static_cast<BOOL>(!fullscreen);
            swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
            swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;

            swapInterval = verticalSync ? 1 : 0;

            hr = factory->CreateSwapChain(device, &swapChainDesc, &swapChain);
            if (FAILED(hr))
            {
                log("Failed to create the D3D11 swap chain");
                return false;
            }

            factory->MakeWindowAssociation(windowWin->getNativeWindow(), DXGI_MWA_NO_ALT_ENTER);

            factory->Release();
            dxgiDevice->Release();

            // Backbuffer
            hr = swapChain->GetBuffer(0, IID_ID3D11Texture2D, reinterpret_cast<void**>(&backBuffer));
            if (FAILED(hr))
            {
                log("Failed to retrieve D3D11 backbuffer");
                return false;
            }

            hr = device->CreateRenderTargetView(backBuffer, nullptr, &renderTargetView);
            if (FAILED(hr))
            {
                log("Failed to create D3D11 render target view");
                return false;
            }

            // Sampler state
            D3D11_SAMPLER_DESC samplerStateDesc;
            switch (textureFiltering)
            {
                case Renderer::TextureFiltering::NONE:
                    samplerStateDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
                    break;
                case Renderer::TextureFiltering::LINEAR:
                    samplerStateDesc.Filter = D3D11_FILTER_MIN_MAG_POINT_MIP_LINEAR;
                    break;
                case Renderer::TextureFiltering::BILINEAR:
                    samplerStateDesc.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT;
                    break;
                case Renderer::TextureFiltering::TRILINEAR:
                    samplerStateDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
                    break;
            }
            samplerStateDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
            samplerStateDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
            samplerStateDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
            samplerStateDesc.MipLODBias = 0.0f;
            samplerStateDesc.MaxAnisotropy = 1;
            samplerStateDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;

            samplerStateDesc.BorderColor[0] = 0.0f;
            samplerStateDesc.BorderColor[1] = 0.0f;
            samplerStateDesc.BorderColor[2] = 0.0f;
            samplerStateDesc.BorderColor[3] = 0.0f;

            samplerStateDesc.MinLOD = 0.0f;
            samplerStateDesc.MaxLOD = D3D11_FLOAT32_MAX;

            hr = device->CreateSamplerState(&samplerStateDesc, &samplerState);
            if (FAILED(hr))
            {
                log("Failed to create D3D11 sampler state");
                return false;
            }

            // Rasterizer state
            D3D11_RASTERIZER_DESC rasterStateDesc =
            {
                D3D11_FILL_SOLID,
                D3D11_CULL_NONE,
                FALSE, // front = ccw?
                0, 0, 0, // depth bias, clamp, slope scale
                FALSE, // depth clip
                FALSE, // scissor test
                (sampleCount > 1) ? TRUE : FALSE, // MSAA
                TRUE, // AA lines
            };

            hr = device->CreateRasterizerState(&rasterStateDesc, &rasterizerState);
            if (FAILED(hr))
            {
                log("Failed to create D3D11 rasterizer state");
                return false;
            }

            rasterStateDesc.ScissorEnable = TRUE;

            hr = device->CreateRasterizerState(&rasterStateDesc, &scissorTestRasterizerState);
            if (FAILED(hr))
            {
                log("Failed to create D3D11 rasterizer state");
                return false;
            }

            // Depth/stencil state
            D3D11_DEPTH_STENCIL_DESC depthStencilStateDesc =
            {
                FALSE, // disable depth test
            };
            hr = device->CreateDepthStencilState(&depthStencilStateDesc, &depthStencilState);
            if (FAILED(hr))
            {
                log("Failed to create D3D11 depth stencil state");
                return false;
            }

            ShaderPtr textureShader = createShader();
            textureShader->initFromBuffers(TEXTURE_PIXEL_SHADER_D3D11, sizeof(TEXTURE_PIXEL_SHADER_D3D11),
                                           TEXTURE_VERTEX_SHADER_D3D11, sizeof(TEXTURE_VERTEX_SHADER_D3D11),
                                           VertexPCT::ATTRIBUTES);

            textureShader->setVertexShaderConstantInfo({{"modelViewProj", sizeof(Matrix4)}});
            textureShader->setPixelShaderConstantInfo({{"color", 4 * sizeof(float)}}, 256);

            sharedEngine->getCache()->setShader(SHADER_TEXTURE, textureShader);

            ShaderPtr colorShader = createShader();
            colorShader->initFromBuffers(COLOR_PIXEL_SHADER_D3D11, sizeof(COLOR_PIXEL_SHADER_D3D11),
                                         COLOR_VERTEX_SHADER_D3D11, sizeof(COLOR_VERTEX_SHADER_D3D11),
                                         VertexPC::ATTRIBUTES);

            colorShader->setVertexShaderConstantInfo({{"modelViewProj", sizeof(Matrix4)}});
            colorShader->setPixelShaderConstantInfo({{"color", 4 * sizeof(float)}}, 256);

            sharedEngine->getCache()->setShader(SHADER_COLOR, colorShader);

            BlendStatePtr noBlendState = createBlendState();

            noBlendState->init(false,
                               BlendState::BlendFactor::ONE, BlendState::BlendFactor::ZERO,
                               BlendState::BlendOperation::ADD,
                               BlendState::BlendFactor::ONE, BlendState::BlendFactor::ZERO,
                               BlendState::BlendOperation::ADD);

            sharedEngine->getCache()->setBlendState(BLEND_NO_BLEND, noBlendState);

            BlendStatePtr addBlendState = createBlendState();

            addBlendState->init(true,
                                BlendState::BlendFactor::ONE, BlendState::BlendFactor::ONE,
                                BlendState::BlendOperation::ADD,
                                BlendState::BlendFactor::ONE, BlendState::BlendFactor::ONE,
                                BlendState::BlendOperation::ADD);

            sharedEngine->getCache()->setBlendState(BLEND_ADD, addBlendState);

            BlendStatePtr multiplyBlendState = createBlendState();

            multiplyBlendState->init(true,
                                     BlendState::BlendFactor::DEST_COLOR, BlendState::BlendFactor::ZERO,
                                     BlendState::BlendOperation::ADD,
                                     BlendState::BlendFactor::ONE, BlendState::BlendFactor::ONE,
                                     BlendState::BlendOperation::ADD);

            sharedEngine->getCache()->setBlendState(BLEND_MULTIPLY, multiplyBlendState);

            BlendStatePtr alphaBlendState = createBlendState();

            alphaBlendState->init(true,
                                  BlendState::BlendFactor::SRC_ALPHA, BlendState::BlendFactor::INV_SRC_ALPHA,
                                  BlendState::BlendOperation::ADD,
                                  BlendState::BlendFactor::ONE, BlendState::BlendFactor::ONE,
                                  BlendState::BlendOperation::ADD);

            sharedEngine->getCache()->setBlendState(BLEND_ALPHA, alphaBlendState);

            memset(&resourceViews, 0, sizeof(resourceViews));
            memset(&samplerStates, 0, sizeof(samplerStates));

            ready = true;

            setSize(size);

            return true;
        }

        void RendererD3D11::clear()
        {
            Renderer::clear();

            clearedRenderTargetViews.clear();

            context->RSSetState(rasterizerState);
        }

        void RendererD3D11::present()
        {
            Renderer::present();

            swapChain->Present(swapInterval, 0);
        }

        IDXGIOutput* RendererD3D11::getOutput() const
        {
            std::shared_ptr<WindowWin> windowWin = std::static_pointer_cast<WindowWin>(sharedEngine->getWindow());

            HMONITOR monitor = windowWin->getMonitor();

            if (!monitor)
            {
                log("Window is not on any monitor");
                return nullptr;
            }

            UINT i = 0;
            IDXGIOutput* output;
            DXGI_OUTPUT_DESC outputDesc;
            HRESULT hr;

            while (adapter->EnumOutputs(i, &output) != DXGI_ERROR_NOT_FOUND)
            {
                hr = output->GetDesc(&outputDesc);

                if (SUCCEEDED(hr) && outputDesc.Monitor == monitor)
                {
                    return output;
                }

                output->Release();

                ++i;
            }

            return nullptr;
        }

        std::vector<Size2> RendererD3D11::getSupportedResolutions() const
        {
            std::vector<Size2> result;

            IDXGIOutput* output = getOutput();

            if (!output)
            {
                return result;
            }

            UINT numModes = 0;
            DXGI_FORMAT format = DXGI_FORMAT_R8G8B8A8_UNORM;
            HRESULT hr = output->GetDisplayModeList(format, 0, &numModes, nullptr);
            if (FAILED(hr))
            {
                log("Failed to get display mode list");
                output->Release();
            }

            if (numModes > 0)
            {
                std::vector<DXGI_MODE_DESC> displayModes(numModes);
                output->GetDisplayModeList(format, 0, &numModes, displayModes.data());

                for (const DXGI_MODE_DESC& displayMode : displayModes)
                {
                    result.push_back(Size2(static_cast<float>(displayMode.Width),
                                           static_cast<float>(displayMode.Height)));
                }
            }

            output->Release();

            return result;
        }

        void RendererD3D11::setSize(const Size2& newSize)
        {
            Renderer::setSize(newSize);

            if (swapChain)
            {
                UINT width = static_cast<UINT>(size.width);
                UINT height = static_cast<UINT>(size.height);

                if (renderTargetView)
                {
                    renderTargetView->Release();
                    renderTargetView = nullptr;
                }

                if (backBuffer)
                {
                    backBuffer->Release();
                    backBuffer = nullptr;
                }

                swapChain->ResizeBuffers(0, width, height, DXGI_FORMAT_UNKNOWN, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH);

                HRESULT hr = swapChain->GetBuffer(0, IID_ID3D11Texture2D, (void**)&backBuffer);
                if (FAILED(hr))
                {
                    log("Failed to retrieve D3D11 backbuffer");
                    return;
                }

                hr = device->CreateRenderTargetView(backBuffer, nullptr, &renderTargetView);
                if (FAILED(hr))
                {
                    log("Failed to create D3D11 render target view");
                    return;
                }

                viewport = { 0, 0, size.width, size.height, 0.0f, 1.0f };

                if (!activeRenderTarget)
                {
                    context->OMSetRenderTargets(1, &renderTargetView, nullptr);
                    context->RSSetViewports(1, &viewport);
                }
            }
        }

        void RendererD3D11::setFullscreen(bool newFullscreen)
        {
            Renderer::setFullscreen(newFullscreen);

            BOOL isFullscreen;
            swapChain->GetFullscreenState(&isFullscreen, nullptr);

            if (isFullscreen != static_cast<BOOL>(fullscreen))
            {
                if (fullscreen)
                {
                    IDXGIOutput* output = getOutput();

                    if (!output)
                    {
                        return;
                    }

                    DXGI_OUTPUT_DESC desc;
                    HRESULT hr = output->GetDesc(&desc);
                    if (FAILED(hr))
                    {
                        output->Release();
                        return;
                    }

                    MONITORINFOEX info;
                    info.cbSize = sizeof(MONITORINFOEX);
                    GetMonitorInfo(desc.Monitor, &info);
                    DEVMODE devMode;
                    devMode.dmSize = sizeof(DEVMODE);
                    devMode.dmDriverExtra = 0;
                    EnumDisplaySettings(info.szDevice, ENUM_CURRENT_SETTINGS, &devMode);

                    DXGI_MODE_DESC current;
                    current.Width = devMode.dmPelsWidth;
                    current.Height = devMode.dmPelsHeight;
                    bool defaultRefreshRate = (devMode.dmDisplayFrequency == 0 || devMode.dmDisplayFrequency == 1);
                    current.RefreshRate.Numerator = defaultRefreshRate ? 0 : devMode.dmDisplayFrequency;
                    current.RefreshRate.Denominator = defaultRefreshRate ? 0 : 1;
                    current.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
                    current.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
                    current.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;

                    DXGI_MODE_DESC closestDisplayMode;
                    hr = output->FindClosestMatchingMode(&current, &closestDisplayMode, nullptr);
                    if (FAILED(hr))
                    {
                        output->Release();
                        return;
                    }

                    setSize(Size2(static_cast<float>(closestDisplayMode.Width),
                                  static_cast<float>(closestDisplayMode.Height)));
                    swapChain->SetFullscreenState(TRUE, output);

                    output->Release();
                }
                else
                {
                    swapChain->SetFullscreenState(FALSE, nullptr);
                }
            }
        }

        BlendStatePtr RendererD3D11::createBlendState()
        {
            std::shared_ptr<BlendStateD3D11> blendState(new BlendStateD3D11());
            return blendState;
        }

        bool RendererD3D11::activateBlendState(BlendStatePtr blendState)
        {
            if (activeBlendState == blendState)
            {
                return true;
            }

            if (!Renderer::activateBlendState(blendState))
            {
                return false;
            }

            if (blendState)
            {
                std::shared_ptr<BlendStateD3D11> blendStateD3D11 = std::static_pointer_cast<BlendStateD3D11>(activeBlendState);

                context->OMSetBlendState(blendStateD3D11->getBlendState(), NULL, 0xffffffff);
            }
            else
            {
                context->OMSetBlendState(NULL, NULL, 0xffffffff);
            }

            return true;
        }

        TexturePtr RendererD3D11::createTexture()
        {
            std::shared_ptr<TextureD3D11> texture(new TextureD3D11());
            return texture;
        }

        bool RendererD3D11::activateTexture(const TexturePtr& texture, uint32_t layer)
        {
            if (activeTextures[layer] == texture)
            {
                return true;
            }

            if (!Renderer::activateTexture(texture, layer))
            {
                return false;
            }

            if (activeTextures[layer])
            {
                std::shared_ptr<TextureD3D11> textureD3D11 = std::static_pointer_cast<TextureD3D11>(activeTextures[layer]);

                resourceViews[layer] = textureD3D11->getResourceView();
                samplerStates[layer] = samplerState;
            }
            else
            {
                resourceViews[layer] = nullptr;
                samplerStates[layer] = nullptr;
            }

            return true;
        }

        RenderTargetPtr RendererD3D11::createRenderTarget()
        {
            std::shared_ptr<RenderTargetD3D11> renderTarget(new RenderTargetD3D11());
            return renderTarget;
        }

        bool RendererD3D11::activateRenderTarget(const RenderTargetPtr& renderTarget)
        {
            if (!Renderer::activateRenderTarget(renderTarget))
            {
                return false;
            }

            ID3D11RenderTargetView* newRenderTargetView = nullptr;
            Color newClearColor;
            D3D11_VIEWPORT newViewport;

            if (activeRenderTarget)
            {
                std::shared_ptr<RenderTargetD3D11> renderTargetD3D11 = std::static_pointer_cast<RenderTargetD3D11>(activeRenderTarget);

                newRenderTargetView = renderTargetD3D11->getRenderTargetView();
                newClearColor = renderTargetD3D11->getClearColor();
                newViewport = renderTargetD3D11->getViewport();
            }
            else
            {
                newRenderTargetView = renderTargetView;
                newClearColor = clearColor;
                newViewport = viewport;
            }

            context->OMSetRenderTargets(1, &newRenderTargetView, nullptr);
            context->RSSetViewports(1, &newViewport);

            if (clearedRenderTargetViews.find(newRenderTargetView) == clearedRenderTargetViews.end())
            {
                float color[4] = { newClearColor.getR(), newClearColor.getG(), newClearColor.getB(), newClearColor.getA() };
                context->ClearRenderTargetView(newRenderTargetView, color);

                clearedRenderTargetViews.insert(newRenderTargetView);
            }

            return true;
        }

        ShaderPtr RendererD3D11::createShader()
        {
            std::shared_ptr<ShaderD3D11> shader(new ShaderD3D11());
            return shader;
        }

        bool RendererD3D11::activateShader(const ShaderPtr& shader)
        {
            if (activeShader == shader)
            {
                return true;
            }

            if (!Renderer::activateShader(shader))
            {
                return false;
            }

{'fraction_non_alphanumeric': 0.08614663345821386, 'fraction_numerical': 0.015948429226229098, 'mean_word_length': 1.482077922077922, 'pattern_counts': {'":': 0, '<': 61, '<?xml version=': 0, '>': 243, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 4, 'word_list_counts': {'cursed_substrings.json': 46, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4421123', 'n_tokens_mistral': 13261, 'n_tokens_neox': 12246, 'n_words': 1893}