#include "Framework.h" using namespace fw; #pragma comment(lib, "d3d10.lib") #pragma comment(lib, "d3dx10.lib") #pragma comment(lib, "dxerr.lib") template<> D3D10Renderer* Singleton<D3D10Renderer>::ms_instance = nullptr; D3D10Renderer::D3D10Renderer(HWND hWnd) : D3DRenderer(hWnd, DXVersion::D3D_10), m_pd3dDevice(nullptr), m_pSwapChain(nullptr), m_pScreenRTTargetView(nullptr), m_pDepthStencilTexture(nullptr), m_pDSState(nullptr), m_pDepthStencilView(nullptr), m_pSprite(nullptr), m_pFont(nullptr), m_sTextInfo(L"D3D10 Renderer"), m_bFSAA(false), m_pPerformanceTimer(nullptr) { } D3D10Renderer::~D3D10Renderer() { if (m_pd3dDevice) { m_pd3dDevice->ClearState(); } SAFE_RELEASE(m_pScreenRTTargetView); SAFE_RELEASE(m_pSwapChain); SAFE_RELEASE(m_pd3dDevice); SHADER_MANAGER->UnRegisterAllShaders(); SCENE_MANAGER->DeleteAllNodes(); } bool D3D10Renderer::Initialize(bool bFullscreen) { m_bFullscreen = bFullscreen; // Variable pour stocker l'état erreur / succès HRESULT hr = S_OK; if (!CreateSwapChain()) { return false; } if (!CreateRenderTarget()) { return false; } if (!CreateDepthStencilView()) { return false; } if (!CreateRasterizerState()) { return false; } if (!CreateDepthStencilState()) { return false; } CreateViewport(); ShowCursor(false); SetupTextInfo(); // Faire un gestionnaire de modules singletons new ShaderManager; new D3D10TextureManager; new SceneManager; new OBJFormatLoader; new ThreadsWrapper; SCENE_MANAGER->AddCamera(new FPSCamera("FPSCamera")); SCENE_MANAGER->SetActiveCamera("FPSCamera"); //SHADER_MANAGER->RegisterShader(new ShaderTechnique_SkySphere, "SkySphere"); //SHADER_MANAGER->RegisterShader(new ShaderTechnique_SimpleTexture, "SimpleTexture"); //SHADER_MANAGER->RegisterShader(new ShaderTechnique_Vertex3DLines, "Vertex3DLines"); // ShaderTechnique_SimpleTexture* pSimpleTextureShader = // reinterpret_cast<ShaderTechnique_SimpleTexture*>(SHADER_MANAGER->GetShader("SimpleTexture")); LoadCustomCursor(); D3D10MeshSceneNode* pWaterPlane = OBJ_LOADER_MANAGER->LoadMeshD3D10("water_plane.obj"); ShaderTechnique::ShaderParameters param; param.SetParam(CUSTOM_SHADER_TEXTURE_NAME, "water.jpg"); param.SetParam(CUSTOM_SHADER_TEXTURE_TILE_FACTOR, 50.0f); SCENE_MANAGER->AddMeshSceneNode(pWaterPlane); SCENE_MANAGER->EnableDebugLines(false); /* LoadMeshPrepared("oildrum2.obj", D3DXVECTOR3(0.0f, 10.0f, 0.0f), D3DXVECTOR3(0.0f, 0.0f, 0.0f), D3DXVECTOR3(18.0f, 18.0f, 18.0f), pSimpleTextureShader, "Oildrum", "oildrum_col.jpg"); */ m_pPerformanceTimer = new PerformanceTimer; return true; } bool D3D10Renderer::CreateRenderTarget() { HRESULT hr = S_OK; // Créé le back buffer ID3D10Texture2D* pBackBuffer; hr = m_pSwapChain->GetBuffer(0, __uuidof(ID3D10Texture2D), (LPVOID*)&pBackBuffer); V_RETURN(hr); // Créé la render target hr = m_pd3dDevice->CreateRenderTargetView(pBackBuffer, nullptr, &m_pScreenRTTargetView); pBackBuffer->Release(); V_RETURN(hr); return true; } bool D3D10Renderer::Frame() { Render(); return true; } void D3D10Renderer::Render() { m_pPerformanceTimer->Begin(); float fTimeSinceLastFrame = m_pPerformanceTimer->GetTimeSinceLastFrame(); static float afClearColor[4] = {0.5f, 0.5f, 0.5f, 1.0f }; // Efface la surface de rendu m_pd3dDevice->ClearDepthStencilView(m_pDepthStencilView, D3D10_CLEAR_DEPTH, 1.0f, 0 ); m_pd3dDevice->ClearRenderTargetView(m_pScreenRTTargetView, afClearColor); SCENE_MANAGER->DrawAll(fTimeSinceLastFrame); fastprint(fTimeSinceLastFrame); DrawTextInfo(); m_pSwapChain->Present(0, 0); SYSTEM->UpdateWindowTitle(); m_pPerformanceTimer->End(); } ID3D10Device* D3D10Renderer::GetDevice() { return m_pd3dDevice; } size_t32 D3D10Renderer::GetViewportWidth() { DXGI_SWAP_CHAIN_DESC swapChainDesc; ZeroMemory(&swapChainDesc, sizeof(swapChainDesc)); m_pSwapChain->GetDesc(&swapChainDesc); return swapChainDesc.BufferDesc.Width; } size_t32 D3D10Renderer::GetViewportHeight() { DXGI_SWAP_CHAIN_DESC swapChainDesc; ZeroMemory(&swapChainDesc, sizeof(swapChainDesc)); m_pSwapChain->GetDesc(&swapChainDesc); return swapChainDesc.BufferDesc.Height; } void D3D10Renderer::EnableZBuffer(bool bEnable) { D3D10_DEPTH_STENCIL_DESC pDesc; m_pDSState->GetDesc(&pDesc); pDesc.DepthEnable = bEnable; m_pd3dDevice->OMSetDepthStencilState(m_pDSState, 1); } void D3D10Renderer::CreateViewport() { // Création du viewport D3D10_VIEWPORT vp; vp.Width = m_iWidth; vp.Height = m_iHeight; vp.MinDepth = 0.0f; vp.MaxDepth = 1.0f; vp.TopLeftX = 0; vp.TopLeftY = 0; m_pd3dDevice->RSSetViewports(1, &vp); } bool D3D10Renderer::CreateSwapChain() { // Rectangle 2D pour les dimensions de la fenêtre RECT rc; // On obtient les dimensions de la fenêtre courante GetClientRect(m_hWnd, &rc); // Largeur de la fenêtre m_iWidth = (size_t) (rc.right - rc.left); // Hauteur de la fenêtre m_iHeight = (size_t) (rc.bottom - rc.top); // Paramètres de création du device UINT createDeviceFlags = 0; // Permet d'afficher les éventuelles erreurs de la création du device //createDeviceFlags |= D3D10_CREATE_DEVICE_DEBUG | D3D10_CREATE_DEVICE_SINGLETHREADED; createDeviceFlags |= D3D10_CREATE_DEVICE_DEBUG; // Création de la Swap Chain // c'est-à-dire création du front buffer et du back buffer DXGI_SWAP_CHAIN_DESC sd; ZeroMemory(&sd, sizeof(sd)); sd.BufferCount = 1; // Taille de la surface en pixels sd.BufferDesc.Width = m_iWidth; sd.BufferDesc.Height = m_iHeight; sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; // Format des couleurs sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; sd.BufferDesc.RefreshRate.Numerator = 60; sd.BufferDesc.RefreshRate.Denominator = 1; // L'hanbdle de la fenêtre que l'on va afficher dessus sd.OutputWindow = m_hWnd; sd.SampleDesc.Count = 1; sd.SampleDesc.Quality = m_bFSAA ? m_iFSAALevel : 0; // Fenêtré ou non sd.Windowed = !m_bFullscreen; sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; // On créé le device DirectX 10 et la Swap Chain HRESULT hr = D3D10CreateDeviceAndSwapChain(nullptr, D3D10_DRIVER_TYPE_HARDWARE, nullptr, createDeviceFlags, D3D10_SDK_VERSION, &sd, &m_pSwapChain, &m_pd3dDevice); if (FAILED(hr)) { ShowMessageBoxDXError(hr); return false; } return true; } bool D3D10Renderer::CreateDepthStencilView() { HRESULT hr = S_OK; D3D10_TEXTURE2D_DESC descDepth; ZeroMemory(&descDepth, sizeof(descDepth)); descDepth.Width = m_iWidth; descDepth.Height = m_iHeight; descDepth.MipLevels = 1; descDepth.ArraySize = 1; /* Make it compatible with both DXGI_FORMAT_D32_FLOAT (stencil view) and DXGI_FORMAT_R32_FLOAT (resource view) */ descDepth.Format = DXGI_FORMAT_D32_FLOAT; descDepth.SampleDesc.Count = m_bFSAA ? m_iFSAALevel : 1; descDepth.SampleDesc.Quality = 0; descDepth.Usage = D3D10_USAGE_DEFAULT; descDepth.BindFlags = D3D10_BIND_DEPTH_STENCIL; descDepth.CPUAccessFlags = 0; descDepth.MiscFlags = 0; hr = m_pd3dDevice->CreateTexture2D(&descDepth, nullptr, &m_pDepthStencilTexture); if (FAILED(hr)) { ShowMessageBoxDXError(hr); return false; } D3D10_DEPTH_STENCIL_VIEW_DESC descDSV; descDSV.Format = descDepth.Format; descDSV.ViewDimension = m_bFSAA ? D3D10_DSV_DIMENSION_TEXTURE2DMS : D3D10_DSV_DIMENSION_TEXTURE2D; descDSV.Texture2D.MipSlice = 0; hr = m_pd3dDevice->CreateDepthStencilView(m_pDepthStencilTexture, &descDSV, &m_pDepthStencilView); ResetDefaultRenderTarget(); if (FAILED(hr)) { ShowMessageBoxDXError(hr); return false; } return true; } bool D3D10Renderer::CreateRasterizerState() { D3D10_RASTERIZER_DESC rasterizerState; rasterizerState.CullMode = D3D10_CULL_BACK; rasterizerState.FillMode = D3D10_FILL_SOLID; rasterizerState.FrontCounterClockwise = false; rasterizerState.DepthBias = true; rasterizerState.DepthBiasClamp = 0; rasterizerState.SlopeScaledDepthBias = 0; rasterizerState.DepthClipEnable = false; rasterizerState.ScissorEnable = false; rasterizerState.MultisampleEnable = m_bFSAA ? true : false; rasterizerState.AntialiasedLineEnable = m_bFSAA ? true : false; HRESULT hr = m_pd3dDevice->CreateRasterizerState(&rasterizerState, &m_pRasterizerState); m_pd3dDevice->RSSetState(m_pRasterizerState); V_RETURN(hr); return true; } bool D3D10Renderer::CreateDepthStencilState() { D3D10_DEPTH_STENCIL_DESC pDesc; pDesc.DepthEnable = true; pDesc.DepthWriteMask = D3D10_DEPTH_WRITE_MASK_ALL; pDesc.DepthFunc = D3D10_COMPARISON_LESS; pDesc.StencilEnable = true; pDesc.StencilReadMask = 0xFF; pDesc.StencilWriteMask = 0xFF; pDesc.FrontFace.StencilFailOp = D3D10_STENCIL_OP_KEEP; pDesc.FrontFace.StencilDepthFailOp = D3D10_STENCIL_OP_INCR; pDesc.FrontFace.StencilPassOp = D3D10_STENCIL_OP_KEEP; pDesc.FrontFace.StencilFunc = D3D10_COMPARISON_ALWAYS; pDesc.BackFace.StencilFailOp = D3D10_STENCIL_OP_KEEP; pDesc.BackFace.StencilDepthFailOp = D3D10_STENCIL_OP_DECR; pDesc.BackFace.StencilPassOp = D3D10_STENCIL_OP_KEEP; pDesc.BackFace.StencilFunc = D3D10_COMPARISON_ALWAYS; HRESULT hr = m_pd3dDevice->CreateDepthStencilState(&pDesc, &m_pDSState); V_RETURN(hr); m_pd3dDevice->OMSetDepthStencilState(m_pDSState, 1); return true; } /* A mettre dans FrameListener ! void D3D10Renderer::OnKeyPressed(const KeyEvent& arg) { if (arg.keyCode == VK_ESCAPE) { SYSTEM->Quit(); } else if (arg.keyCode == VK_F1) { FPSCamera* pCameraFPS = reinterpret_cast<FPSCamera*> (SCENE_MANAGER->GetActiveCamera()); pCameraFPS->SetActive(!pCameraFPS->GetActive()); } } void D3D10Renderer::OnKeyReleased(const KeyEvent& arg) { } */ void D3D10Renderer::SetupTextInfo() { // Il faut créer un objet ID3DX10Sprite D3DX10CreateSprite(m_pd3dDevice, 0, &m_pSprite); /* Détaille les attributs de cette police d'affichage */ D3DX10_FONT_DESC fd; // Définit la hauteur d'un caractère de cette police fd.Height = 30; // Définit la largeur d'un caractère de cette police fd.Width = 13; fd.Weight = 3; fd.MipLevels = 0; // En italique ou non fd.Italic = false; fd.CharSet = OUT_DEFAULT_PRECIS; //fd.Quality = ANTIALIASED_QUALITY; fd.Quality = CLEARTYPE_QUALITY; fd.PitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; // Définit le nom de la police à utiliser wcscpy_s(fd.FaceName, L"Corbel"); D3DX10CreateFontIndirect(m_pd3dDevice, &fd, &m_pFont); } void D3D10Renderer::DrawTextInfo() { DrawTextSprite(m_sTextInfo, D3DXVECTOR2(5, 100), Colours::White); } void D3D10Renderer::DrawTextSprite(const std::wstring& sText, const D3DXVECTOR2& position, const D3DXCOLOR& color) { RECT rectangle; rectangle.left = (uint32) position.x; rectangle.bottom = (uint32) position.y; rectangle.right = 0; rectangle.top = 0; EnableZBuffer(false); m_pSprite->Begin(D3DX10_SPRITE_SORT_TEXTURE); m_pFont->DrawText(m_pSprite, sText.c_str(), -1, &rectangle, DT_NOCLIP, color); m_pSprite->End(); EnableZBuffer(true); } void D3D10Renderer::ResetDefaultRenderTarget() { m_pd3dDevice->OMSetRenderTargets(1, &m_pScreenRTTargetView, m_pDepthStencilView); } ID3D10DepthStencilView* D3D10Renderer::GetDepthStencilView() { return m_pDepthStencilView; } void D3D10Renderer::SetInfoText(const std::wstring& sText) { m_sTextInfo = sText; } D3DMeshSceneNode<D3D10>* D3D10Renderer::LoadMeshOBJ(const std::string& sFileName) { return OBJ_LOADER_MANAGER->LoadMesh<D3D10>(sFileName); } bool D3D10Renderer::SetSceneNodeData_Callback(const Callback::Parameter& param) { D3DMeshSceneNode<D3D10>* pMeshNode = param.GetReturnValue<D3DMeshSceneNode<D3D10>*>(); SceneManager::SceneNodeInfo* pMeshNodeInfo = param.GetParameterAsPointer<SceneManager::SceneNodeInfo*>(CALL_BACK_SCENE_NODE_INFO); if (pMeshNode && pMeshNodeInfo) { if (pMeshNodeInfo->sName != NONE) { pMeshNode->SetName(pMeshNodeInfo->sName); } // Doit être appelée en priorité face à SetPosition, SetScale() ! pMeshNode->CreateAABBLines(Colours::Red); pMeshNode->SetPosition(pMeshNodeInfo->position); pMeshNode->SetScale(pMeshNodeInfo->scale); pMeshNode->SetRotation(pMeshNodeInfo->rotation); pMeshNode->SetShaderTechnique(pMeshNodeInfo->pTechnique); if (pMeshNodeInfo->sTextureName != NONE) { ShaderTechnique::ShaderParameters param; param.SetParam(CUSTOM_SHADER_TEXTURE_NAME, pMeshNodeInfo->sTextureName); pMeshNode->PushCustomShaderParameter(param); } SCENE_MANAGER->AddMeshSceneNode(pMeshNode); return true; } else { return false; } } void D3D10Renderer::LoadMeshPrepared(const std::string& sFileName, const D3DXVECTOR3& pos, const D3DXVECTOR3& rot, const D3DXVECTOR3& scale, ShaderTechnique* pShaderTechnique, const std::string& sName, const std::string& sTextureName) { Callback* pCallback = new Callback(); pCallback->AddCallbackFunction(&D3D10Renderer::SetSceneNodeData_Callback, this); pCallback->AddCallbackFunction(&D3D10Renderer::LookAfterNodes_Callback, this); ThreadsWrapper::Thread* pT = nullptr; if (Utils::IsFileExtensionCorrect(sFileName, ".obj")) { pT = THREADS_WRAPPER->CreateThread("MeshLoaderOBJ", &D3D10Renderer::LoadMeshOBJ, this, sFileName); } if (pT) { SceneManager::SceneNodeInfo* pSceneNodeInfo = new SceneManager::SceneNodeInfo; pSceneNodeInfo->position = pos; pSceneNodeInfo->rotation = rot; pSceneNodeInfo->scale = scale; pSceneNodeInfo->pTechnique = pShaderTechnique; pSceneNodeInfo->sName = sName; pSceneNodeInfo->sTextureName = sTextureName; Callback::Parameter param; param.SetParam(CALL_BACK_SCENE_NODE_INFO, pSceneNodeInfo); pT->SetCallback(pCallback); pT->LinkParameters(param); std::thread::id id = THREADS_WRAPPER->LaunchThread(pT); } } void D3D10Renderer::LoadCustomCursor() { HINSTANCE hInst = (HINSTANCE)GetModuleHandle(NULL); HWND hwnd = SYSTEM->GetHwnd(); HCURSOR WoWCursor = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR_ARROW)); SetClassLong(hwnd, GCL_HCURSOR, (LONG)WoWCursor); } bool D3D10Renderer::LookAfterNodes_Callback(const Callback::Parameter& param) { D3DMeshSceneNode<D3D10>* pMeshNode = param.GetReturnValue<D3DMeshSceneNode<D3D10>*>(); SceneManager::SceneNodeInfo* pMeshNodeInfo = param.GetParameterAsPointer<SceneManager::SceneNodeInfo*>(CALL_BACK_SCENE_NODE_INFO); if (pMeshNodeInfo && pMeshNode) { std::string sNodeName = pMeshNodeInfo->sName; return true; } return false; } void D3D10Renderer::SetFSAAMaximumLevel() { HRESULT hr = S_OK; UINT maxQualityLevel = 1; for (uint32 iSampleCount = 1; iSampleCount <= D3D10_MAX_MULTISAMPLE_SAMPLE_COUNT; iSampleCount++) { hr = m_pd3dDevice->CheckMultisampleQualityLevels( DXGI_FORMAT_R8G8B8A8_UNORM, iSampleCount, &maxQualityLevel); if (hr != S_OK) { fastprint(Utils::Formater(L"CheckMultisampleQualityLevels a échoué.")); } if (maxQualityLevel > 0) { fastprint("MSAA " << iSampleCount << Utils::Formater(L"X supportée par la carte vidéo avec ") << maxQualityLevel << Utils::Formater(L" niveau(x) de qualité.")); } } } void D3D10Renderer::SetFullScreen() { m_bFullscreen = !m_bFullscreen; if (m_bFullscreen) { ResizeSwapChain(m_iWidth, m_iHeight); } m_pSwapChain->SetFullscreenState(m_bFullscreen, nullptr); } void D3D10Renderer::SetWindowResolutionMode(uint32 iMode) { // Largeur de la fenêtre uint32 iWidth = m_modes[iMode].Width; // Hauteur de la fenêtre uint32 iHeight = m_modes[iMode].Height; ResizeSwapChain(iWidth, iHeight); RECT rc; GetWindowRect(m_hWnd, &rc); SetWindowPos(m_hWnd, 0, rc.left, rc.top, iWidth, iHeight, SWP_SHOWWINDOW); } bool D3D10Renderer::ResizeSwapChain(const size_t32& iWidth, const size_t32& iHeight) { /* On décharge les précédents objets de rendu */ SAFE_RELEASE(m_pScreenRTTargetView); SAFE_RELEASE(m_pDepthStencilView); HRESULT hr = S_OK; hr = m_pSwapChain->ResizeBuffers(2, iWidth, iHeight, DXGI_FORMAT_R8G8B8A8_UNORM, 0); V_RETURN(hr); m_iWidth = iWidth; m_iHeight = iHeight; /* Puis on les recréer */ CreateRenderTarget(); CreateDepthStencilView(); //m_pCube->SetLens() CreateViewport(); return true; } bool D3D10Renderer::GetGPUInfo() { HRESULT hr = S_OK; uint32 iNumModes; IDXGIFactory* pDXGIFactory = nullptr; IDXGIAdapter* pDXGIAdapter = nullptr; IDXGIOutput* pDXGIAdapterOutput = nullptr; DXGI_MODE_DESC* pDisplayModeList = nullptr; DXGI_ADAPTER_DESC adapterDesc; // Créée une interface métier "factory" DirectX hr = CreateDXGIFactory(__uuidof(IDXGIFactory), (void**)&pDXGIFactory); V_RETURN(hr); // Utilise la "factory" hr = pDXGIFactory->EnumAdapters(0, &pDXGIAdapter); V_RETURN(hr); // Enumère l'adpatateur principal de l'écran hr = pDXGIAdapter->EnumOutputs(0, &pDXGIAdapterOutput); V_RETURN(hr); // Obtient le nombre de modes d'affichage qui corresppond à DXGI_FORMAT_R8G8B8A8_UNORM hr = pDXGIAdapterOutput->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_ENUM_MODES_INTERLACED, &iNumModes, nullptr); V_RETURN(hr); /* Créé une liste qui détient tous les modes d'affichage possibles pour cette carte graphique et le format d'affichage */ pDisplayModeList = new DXGI_MODE_DESC[iNumModes]; if (!pDisplayModeList) { return false; } // Remplie la précédente structure hr = pDXGIAdapterOutput->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_ENUM_MODES_INTERLACED, &iNumModes, pDisplayModeList); V_RETURN(hr); /* On parcourt tous les modes d'affichages possibles et on trouve celui qui correspond à la taille spécifiée en paramètre ; puis on enregistre le numérateur et le dénominateur du taux de rafraichissement de l'écran */ for (uint32 i = 0; i < iNumModes; i++) { if (pDisplayModeList[i].Width == (uint32)m_iWidth) { if (pDisplayModeList[i].Height == (uint32)m_iHeight) { uint32 iNumerator = pDisplayModeList[i].RefreshRate.Numerator; uint32 iDenominator = pDisplayModeList[i].RefreshRate.Denominator; } } DXGI_MODE_DESC desc = pDisplayModeList[i]; // On vérifie que ce mode n'a pas déjà été ajouté bool bAlreadyExist = false; for (uint32 i = 0; i < m_modes.size(); i++) { if (m_modes[i].Width == desc.Width && m_modes[i].Height == desc.Height) { bAlreadyExist = true; break; } } if (!bAlreadyExist) { m_modes.push_back(desc); } } hr = pDXGIAdapter->GetDesc(&adapterDesc); V_RETURN(hr); // On enregistre la taille de la mémoire vidéo en mégabytes m_iVideoCardMemory = (adapterDesc.DedicatedVideoMemory / 1024 / 1024); size_t32 iStringLength = 0; // Convertie le nom la carte vidéo dans une chaîne de caractères uint32 iError = wcstombs_s(&iStringLength, m_sVideoCardDescription, 128, adapterDesc.Description, 128); if (iError != 0) { return false; } SAFE_DELETE_ARRAY(pDisplayModeList); SAFE_RELEASE(pDXGIAdapterOutput); SAFE_RELEASE(pDXGIAdapter); SAFE_RELEASE(pDXGIFactory); return true; } D3DDevice* D3D10Renderer::GetPureDevice() { return (D3DDevice*)m_pd3dDevice; }