diff --git a/Source/Plugins/Plugin_VideoDX9/Src/D3DBase.cpp b/Source/Plugins/Plugin_VideoDX9/Src/D3DBase.cpp index 6792b3418b..7b09a588f8 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/D3DBase.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/D3DBase.cpp @@ -89,191 +89,191 @@ void EnableAlphaToCoverage() D3D::SetRenderState(D3DRS_ADAPTIVETESS_Y, (D3DFORMAT)MAKEFOURCC('A', 'T', 'O', 'C')); } - void InitPP(int adapter, int f, int aa_mode, D3DPRESENT_PARAMETERS *pp) +void InitPP(int adapter, int f, int aa_mode, D3DPRESENT_PARAMETERS *pp) +{ + int FSResX = adapters[adapter].resolutions[resolution].xres; + int FSResY = adapters[adapter].resolutions[resolution].yres; + + ZeroMemory(pp, sizeof(D3DPRESENT_PARAMETERS)); + pp->hDeviceWindow = hWnd; + if (auto_depth_stencil) { - int FSResX = adapters[adapter].resolutions[resolution].xres; - int FSResY = adapters[adapter].resolutions[resolution].yres; + pp->EnableAutoDepthStencil = TRUE; + pp->AutoDepthStencilFormat = D3DFMT_D24S8; + } else { + pp->EnableAutoDepthStencil = FALSE; + pp->AutoDepthStencilFormat = D3DFMT_UNKNOWN; + } + pp->BackBufferFormat = D3DFMT_A8R8G8B8; + if (aa_mode >= (int)adapters[adapter].aa_levels.size()) + aa_mode = 0; - ZeroMemory(pp, sizeof(D3DPRESENT_PARAMETERS)); - pp->hDeviceWindow = hWnd; - if (auto_depth_stencil) - { - pp->EnableAutoDepthStencil = TRUE; - pp->AutoDepthStencilFormat = D3DFMT_D24S8; - } else { - pp->EnableAutoDepthStencil = FALSE; - pp->AutoDepthStencilFormat = D3DFMT_UNKNOWN; - } - pp->BackBufferFormat = D3DFMT_A8R8G8B8; - if (aa_mode >= (int)adapters[adapter].aa_levels.size()) - aa_mode = 0; + pp->MultiSampleType = adapters[adapter].aa_levels[aa_mode].ms_setting; + pp->MultiSampleQuality = adapters[adapter].aa_levels[aa_mode].qual_setting; + + pp->Flags = auto_depth_stencil ? D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL : 0; + if (fullScreen) + { + xres = pp->BackBufferWidth = FSResX; + yres = pp->BackBufferHeight = FSResY; + pp->SwapEffect = D3DSWAPEFFECT_DISCARD; + pp->Windowed = FALSE; + } + else + { + RECT client; + GetClientRect(hWnd, &client); + xres = pp->BackBufferWidth = client.right - client.left; + yres = pp->BackBufferHeight = client.bottom - client.top; + pp->SwapEffect = D3DSWAPEFFECT_DISCARD; + pp->PresentationInterval = g_Config.bVSync ? D3DPRESENT_INTERVAL_DEFAULT : D3DPRESENT_INTERVAL_IMMEDIATE; + pp->Windowed = TRUE; + } +} - pp->MultiSampleType = adapters[adapter].aa_levels[aa_mode].ms_setting; - pp->MultiSampleQuality = adapters[adapter].aa_levels[aa_mode].qual_setting; +void Enumerate() +{ + numAdapters = D3D::D3D->GetAdapterCount(); + for (int i = 0; i < std::min(MAX_ADAPTERS, numAdapters); i++) + { + Adapter &a = adapters[i]; + D3D::D3D->GetAdapterIdentifier(i, 0, &a.ident); + bool isNvidia = a.ident.VendorId == VENDOR_NVIDIA; + + // Add multisample modes + a.aa_levels.push_back(AALevel("None", D3DMULTISAMPLE_NONE, 0)); + + DWORD qlevels = 0; + if (D3DERR_NOTAVAILABLE != D3D::D3D->CheckDeviceMultiSampleType( + i, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, TRUE, D3DMULTISAMPLE_2_SAMPLES, &qlevels)) + if (qlevels > 0) + a.aa_levels.push_back(AALevel("2x MSAA", D3DMULTISAMPLE_2_SAMPLES, 0)); - pp->Flags = auto_depth_stencil ? D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL : 0; - if (fullScreen) - { - xres = pp->BackBufferWidth = FSResX; - yres = pp->BackBufferHeight = FSResY; - pp->SwapEffect = D3DSWAPEFFECT_DISCARD; - pp->Windowed = FALSE; - } - else - { - RECT client; - GetClientRect(hWnd, &client); - xres = pp->BackBufferWidth = client.right - client.left; - yres = pp->BackBufferHeight = client.bottom - client.top; - pp->SwapEffect = D3DSWAPEFFECT_DISCARD; - pp->PresentationInterval = g_Config.bVSync ? D3DPRESENT_INTERVAL_DEFAULT : D3DPRESENT_INTERVAL_IMMEDIATE; - pp->Windowed = TRUE; - } - } + if (D3DERR_NOTAVAILABLE != D3D::D3D->CheckDeviceMultiSampleType( + i, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, TRUE, D3DMULTISAMPLE_2_SAMPLES, &qlevels)) + if (qlevels > 0) + a.aa_levels.push_back(AALevel("4x MSAA", D3DMULTISAMPLE_4_SAMPLES, 0)); - void Enumerate() - { - numAdapters = D3D::D3D->GetAdapterCount(); - for (int i = 0; i < std::min(MAX_ADAPTERS, numAdapters); i++) + if (D3DERR_NOTAVAILABLE != D3D::D3D->CheckDeviceMultiSampleType( + i, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, TRUE, D3DMULTISAMPLE_8_SAMPLES, &qlevels)) + if (qlevels > 0) + a.aa_levels.push_back(AALevel("8x MSAA", D3DMULTISAMPLE_8_SAMPLES, 0)); + + if (isNvidia) { - Adapter &a = adapters[i]; - D3D::D3D->GetAdapterIdentifier(i, 0, &a.ident); - bool isNvidia = a.ident.VendorId == VENDOR_NVIDIA; - - // Add multisample modes - a.aa_levels.push_back(AALevel("None", D3DMULTISAMPLE_NONE, 0)); - - DWORD qlevels = 0; + // CSAA support if (D3DERR_NOTAVAILABLE != D3D::D3D->CheckDeviceMultiSampleType( - i, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, TRUE, D3DMULTISAMPLE_2_SAMPLES, &qlevels)) - if (qlevels > 0) - a.aa_levels.push_back(AALevel("2x MSAA", D3DMULTISAMPLE_2_SAMPLES, 0)); + i, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, TRUE, D3DMULTISAMPLE_4_SAMPLES, &qlevels)) + { + if (qlevels > 2) + { + // 8x, 8xQ are available + // See http://developer.nvidia.com/object/coverage-sampled-aa.html + a.aa_levels.push_back(AALevel("8x CSAA", D3DMULTISAMPLE_4_SAMPLES, 2)); + a.aa_levels.push_back(AALevel("8xQ CSAA", D3DMULTISAMPLE_8_SAMPLES, 0)); + } + } + if (D3DERR_NOTAVAILABLE != D3D::D3D->CheckDeviceMultiSampleType( + i, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, TRUE, D3DMULTISAMPLE_8_SAMPLES, &qlevels)) + { + if (qlevels > 2) + { + // 16x, 16xQ are available + // See http://developer.nvidia.com/object/coverage-sampled-aa.html + a.aa_levels.push_back(AALevel("16x CSAA", D3DMULTISAMPLE_4_SAMPLES, 4)); + a.aa_levels.push_back(AALevel("16xQ CSAA", D3DMULTISAMPLE_8_SAMPLES, 2)); + } + } + } + if (a.aa_levels.size() == 1) + { + strcpy(a.aa_levels[0].name, "(Not supported on this device)"); + } + int numModes = D3D::D3D->GetAdapterModeCount(i, D3DFMT_X8R8G8B8); + for (int m = 0; m < numModes; m++) + { + D3DDISPLAYMODE mode; + D3D::D3D->EnumAdapterModes(i, D3DFMT_X8R8G8B8, m, &mode); - if (D3DERR_NOTAVAILABLE != D3D::D3D->CheckDeviceMultiSampleType( - i, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, TRUE, D3DMULTISAMPLE_2_SAMPLES, &qlevels)) - if (qlevels > 0) - a.aa_levels.push_back(AALevel("4x MSAA", D3DMULTISAMPLE_4_SAMPLES, 0)); - - if (D3DERR_NOTAVAILABLE != D3D::D3D->CheckDeviceMultiSampleType( - i, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, TRUE, D3DMULTISAMPLE_8_SAMPLES, &qlevels)) - if (qlevels > 0) - a.aa_levels.push_back(AALevel("8x MSAA", D3DMULTISAMPLE_8_SAMPLES, 0)); - - if (isNvidia) + int found = -1; + for (int x = 0; x < (int)a.resolutions.size(); x++) { - // CSAA support - if (D3DERR_NOTAVAILABLE != D3D::D3D->CheckDeviceMultiSampleType( - i, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, TRUE, D3DMULTISAMPLE_4_SAMPLES, &qlevels)) + if (a.resolutions[x].xres == mode.Width && a.resolutions[x].yres == mode.Height) { - if (qlevels > 2) - { - // 8x, 8xQ are available - // See http://developer.nvidia.com/object/coverage-sampled-aa.html - a.aa_levels.push_back(AALevel("8x CSAA", D3DMULTISAMPLE_4_SAMPLES, 2)); - a.aa_levels.push_back(AALevel("8xQ CSAA", D3DMULTISAMPLE_8_SAMPLES, 0)); - } - } - if (D3DERR_NOTAVAILABLE != D3D::D3D->CheckDeviceMultiSampleType( - i, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, TRUE, D3DMULTISAMPLE_8_SAMPLES, &qlevels)) - { - if (qlevels > 2) - { - // 16x, 16xQ are available - // See http://developer.nvidia.com/object/coverage-sampled-aa.html - a.aa_levels.push_back(AALevel("16x CSAA", D3DMULTISAMPLE_4_SAMPLES, 4)); - a.aa_levels.push_back(AALevel("16xQ CSAA", D3DMULTISAMPLE_8_SAMPLES, 2)); - } + found = x; + break; } } - if (a.aa_levels.size() == 1) - { - strcpy(a.aa_levels[0].name, "(Not supported on this device)"); - } - int numModes = D3D::D3D->GetAdapterModeCount(i, D3DFMT_X8R8G8B8); - for (int m = 0; m < numModes; m++) - { - D3DDISPLAYMODE mode; - D3D::D3D->EnumAdapterModes(i, D3DFMT_X8R8G8B8, m, &mode); - - int found = -1; - for (int x = 0; x < (int)a.resolutions.size(); x++) - { - if (a.resolutions[x].xres == mode.Width && a.resolutions[x].yres == mode.Height) - { - found = x; - break; - } - } - Resolution temp; - Resolution &r = found==-1 ? temp : a.resolutions[found]; - - sprintf(r.name, "%ix%i", mode.Width, mode.Height); - r.bitdepths.insert(mode.Format); - r.refreshes.insert(mode.RefreshRate); - if (found == -1 && mode.Width >= 640 && mode.Height >= 480) - { - r.xres = mode.Width; - r.yres = mode.Height; - a.resolutions.push_back(r); - } + Resolution temp; + Resolution &r = found==-1 ? temp : a.resolutions[found]; + + sprintf(r.name, "%ix%i", mode.Width, mode.Height); + r.bitdepths.insert(mode.Format); + r.refreshes.insert(mode.RefreshRate); + if (found == -1 && mode.Width >= 640 && mode.Height >= 480) + { + r.xres = mode.Width; + r.yres = mode.Height; + a.resolutions.push_back(r); } } } +} - HRESULT Create(int adapter, HWND wnd, bool _fullscreen, int _resolution, int aa_mode, bool auto_depth) +HRESULT Create(int adapter, HWND wnd, bool _fullscreen, int _resolution, int aa_mode, bool auto_depth) +{ + hWnd = wnd; + fullScreen = _fullscreen; + nextFullScreen = _fullscreen; + multisample = aa_mode; + resolution = _resolution; + auto_depth_stencil = auto_depth; + cur_adapter = adapter; + D3DPRESENT_PARAMETERS d3dpp; + InitPP(adapter, resolution, aa_mode, &d3dpp); + + if (FAILED(D3D->CreateDevice( + adapter, + D3DDEVTYPE_HAL, + wnd, + D3DCREATE_HARDWARE_VERTEXPROCESSING, + &d3dpp, &dev))) { - hWnd = wnd; - fullScreen = _fullscreen; - nextFullScreen = _fullscreen; - multisample = aa_mode; - resolution = _resolution; - auto_depth_stencil = auto_depth; - cur_adapter = adapter; - D3DPRESENT_PARAMETERS d3dpp; - InitPP(adapter, resolution, aa_mode, &d3dpp); - + MessageBox(wnd, + _T("Sorry, but it looks like your 3D accelerator is too old,\n") + _T("or doesn't support features that Dolphin requires.\n") + _T("Falling back to software vertex processing.\n"), + _T("Dolphin Direct3D plugin"), MB_OK | MB_ICONERROR); if (FAILED(D3D->CreateDevice( adapter, D3DDEVTYPE_HAL, wnd, - D3DCREATE_HARDWARE_VERTEXPROCESSING, + D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_MULTITHREADED, + // |D3DCREATE_MULTITHREADED /* | D3DCREATE_PUREDEVICE*/, + //D3DCREATE_SOFTWARE_VERTEXPROCESSING , &d3dpp, &dev))) { MessageBox(wnd, - _T("Sorry, but it looks like your 3D accelerator is too old,\n") - _T("or doesn't support features that Dolphin requires.\n") - _T("Falling back to software vertex processing.\n"), + _T("Software VP failed too. Upgrade your graphics card."), _T("Dolphin Direct3D plugin"), MB_OK | MB_ICONERROR); - if (FAILED(D3D->CreateDevice( - adapter, - D3DDEVTYPE_HAL, - wnd, - D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_MULTITHREADED, - // |D3DCREATE_MULTITHREADED /* | D3DCREATE_PUREDEVICE*/, - //D3DCREATE_SOFTWARE_VERTEXPROCESSING , - &d3dpp, &dev))) - { - MessageBox(wnd, - _T("Software VP failed too. Upgrade your graphics card."), - _T("Dolphin Direct3D plugin"), MB_OK | MB_ICONERROR); - return E_FAIL; - } + return E_FAIL; } - dev->GetDeviceCaps(&caps); - dev->GetRenderTarget(0, &back_buffer); - if (dev->GetDepthStencilSurface(&back_buffer_z) == D3DERR_NOTFOUND) - back_buffer_z = NULL; - - // Device state would normally be set here - return S_OK; } + dev->GetDeviceCaps(&caps); + dev->GetRenderTarget(0, &back_buffer); + if (dev->GetDepthStencilSurface(&back_buffer_z) == D3DERR_NOTFOUND) + back_buffer_z = NULL; - void Close() - { - dev->Release(); - dev = 0; - } + // Device state would normally be set here + return S_OK; +} + +void Close() +{ + dev->Release(); + dev = 0; +} const D3DCAPS9 &GetCaps() { @@ -318,86 +318,96 @@ void ShowD3DError(HRESULT err) } } - void Reset() +void Reset() +{ + if (dev) { - if (dev) - { - // Can't keep a pointer around to the backbuffer surface when resetting. - if (back_buffer_z) - back_buffer_z->Release(); + ForgetCachedState(); + + // Can't keep a pointer around to the backbuffer surface when resetting. + if (back_buffer_z) + back_buffer_z->Release(); + back_buffer_z = NULL; + back_buffer->Release(); + back_buffer = NULL; + + D3DPRESENT_PARAMETERS d3dpp; + InitPP(cur_adapter, resolution, multisample, &d3dpp); + HRESULT hr = dev->Reset(&d3dpp); + ShowD3DError(hr); + + dev->GetRenderTarget(0, &back_buffer); + if (dev->GetDepthStencilSurface(&back_buffer_z) == D3DERR_NOTFOUND) back_buffer_z = NULL; - back_buffer->Release(); - back_buffer = NULL; - - D3DPRESENT_PARAMETERS d3dpp; - InitPP(cur_adapter, resolution, multisample, &d3dpp); - HRESULT hr = dev->Reset(&d3dpp); - ShowD3DError(hr); - - dev->GetRenderTarget(0, &back_buffer); - if (dev->GetDepthStencilSurface(&back_buffer_z) == D3DERR_NOTFOUND) - back_buffer_z = NULL; - } } +} - bool IsFullscreen() +bool IsFullscreen() +{ + return fullScreen; +} + +int GetBackBufferWidth() +{ + return xres; +} + +int GetBackBufferHeight() +{ + return yres; +} + +void SwitchFullscreen(bool fullscreen) +{ + nextFullScreen = fullscreen; +} + +bool BeginFrame() +{ + if (bFrameInProgress) { - return fullScreen; + PanicAlert("BeginFrame WTF"); + return false; } - - int GetBackBufferWidth() + bFrameInProgress = true; + if (dev) { - return xres; + dev->BeginScene(); + return true; } + else + return false; +} - int GetBackBufferHeight() +void EndFrame() +{ + if (!bFrameInProgress) { - return yres; + PanicAlert("EndFrame WTF"); + return; } + bFrameInProgress = false; - void SwitchFullscreen(bool fullscreen) + if (dev) { - nextFullScreen = fullscreen; + dev->EndScene(); + dev->Present(NULL, NULL, NULL, NULL); } - bool BeginFrame() + if (fullScreen != nextFullScreen) { - if (bFrameInProgress) - { - PanicAlert("BeginFrame WTF"); - return false; - } - bFrameInProgress = true; - if (dev) - { - dev->BeginScene(); - return true; - } - else - return false; + fullScreen = nextFullScreen; + Reset(); } +} - void EndFrame() - { - if (!bFrameInProgress) - { - PanicAlert("EndFrame WTF"); - return; - } - bFrameInProgress = false; - - if (dev) - { - dev->EndScene(); - dev->Present(NULL, NULL, NULL, NULL); - } - - if (fullScreen != nextFullScreen) - { - fullScreen = nextFullScreen; - Reset(); - } - } +void ForgetCachedState() +{ + memset(m_Textures, 0, sizeof(m_Textures)); + memset(m_RenderStates, 0xFF, sizeof(m_RenderStates)); + memset(m_TextureStageStates, 0xFF, sizeof(m_TextureStageStates)); + memset(m_SamplerStates, 0xFF, sizeof(m_SamplerStates)); +} void SetTexture(DWORD Stage, LPDIRECT3DBASETEXTURE9 pTexture) { diff --git a/Source/Plugins/Plugin_VideoDX9/Src/D3DBase.h b/Source/Plugins/Plugin_VideoDX9/Src/D3DBase.h index 1d8cecadc9..c92168a9cf 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/D3DBase.h +++ b/Source/Plugins/Plugin_VideoDX9/Src/D3DBase.h @@ -57,6 +57,7 @@ void SetTexture(DWORD Stage, IDirect3DBaseTexture9 *pTexture); void SetRenderState(D3DRENDERSTATETYPE State, DWORD Value); void SetTextureStageState(DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD Value); void SetSamplerState(DWORD Sampler, D3DSAMPLERSTATETYPE Type, DWORD Value); +void ForgetCachedState(); // Utility functions for vendor specific hacks. So far, just the one. void EnableAlphaToCoverage(); diff --git a/Source/Plugins/Plugin_VideoDX9/Src/D3DUtil.cpp b/Source/Plugins/Plugin_VideoDX9/Src/D3DUtil.cpp index 9b664858cf..600c470fc9 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/D3DUtil.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/D3DUtil.cpp @@ -23,352 +23,353 @@ namespace D3D { - CD3DFont font; +CD3DFont font; #define MAX_NUM_VERTICES 50*6 - struct FONT2DVERTEX { - float x,y,z; - float rhw; - u32 color; - float tu, tv; - }; +struct FONT2DVERTEX { + float x,y,z; + float rhw; + u32 color; + float tu, tv; +}; #define D3DFVF_FONT2DVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1) #define D3DFVF_FONT3DVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_NORMAL|D3DFVF_TEX1) - inline FONT2DVERTEX InitFont2DVertex(float x, float y, u32 color, float tu, float tv) +inline FONT2DVERTEX InitFont2DVertex(float x, float y, u32 color, float tu, float tv) +{ + FONT2DVERTEX v; v.x=x; v.y=y; v.z=0; v.rhw=1.0f; v.color = color; v.tu = tu; v.tv = tv; + return v; +} + +CD3DFont::CD3DFont() +{ + m_pTexture = NULL; + m_pVB = NULL; +} + +enum {m_dwTexWidth = 512, m_dwTexHeight = 512}; + +int CD3DFont::Init() +{ + // Create vertex buffer for the letters + HRESULT hr; + if (FAILED(hr = dev->CreateVertexBuffer(MAX_NUM_VERTICES*sizeof(FONT2DVERTEX), + D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC, 0, D3DPOOL_DEFAULT, &m_pVB, NULL))) { - FONT2DVERTEX v; v.x=x; v.y=y; v.z=0; v.rhw=1.0f; v.color = color; v.tu = tu; v.tv = tv; - return v; + return hr; } + m_fTextScale = 1.0f; // Draw fonts into texture without scaling - CD3DFont::CD3DFont() + // Prepare to create a bitmap + int *pBitmapBits; + BITMAPINFO bmi; + ZeroMemory(&bmi.bmiHeader, sizeof(BITMAPINFOHEADER)); + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi.bmiHeader.biWidth = (int)m_dwTexWidth; + bmi.bmiHeader.biHeight = -(int)m_dwTexHeight; + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biCompression = BI_RGB; + bmi.bmiHeader.biBitCount = 32; + + // Create a DC and a bitmap for the font + HDC hDC = CreateCompatibleDC(NULL); + HBITMAP hbmBitmap = CreateDIBSection(hDC, &bmi, DIB_RGB_COLORS, (VOID**)&pBitmapBits, NULL, 0); + SetMapMode(hDC, MM_TEXT); + + // Create a font. By specifying ANTIALIASED_QUALITY, we might get an + // antialiased font, but this is not guaranteed. + // We definitely don't want to get it cleartype'd, anyway. + int m_dwFontHeight = 24; + int nHeight = -MulDiv(m_dwFontHeight, int(GetDeviceCaps(hDC, LOGPIXELSY) * m_fTextScale), 72); + int dwBold = FW_NORMAL; ///FW_BOLD + HFONT hFont = CreateFont(nHeight, 0, 0, 0, dwBold, 0, + FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, + CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, + VARIABLE_PITCH, _T("Tahoma")); + if (NULL == hFont) + return E_FAIL; + + HGDIOBJ hOldbmBitmap = SelectObject(hDC, hbmBitmap); + HGDIOBJ hOldFont = SelectObject(hDC, hFont); + + // Set text properties + SetTextColor(hDC, 0xFFFFFF); + SetBkColor (hDC, 0); + SetTextAlign(hDC, TA_TOP); + + // Loop through all printable character and output them to the bitmap.. + // Meanwhile, keep track of the corresponding tex coords for each character. + int x = 0, y = 0; + char str[2] = "\0"; + for (int c = 0; c < 127 - 32; c++) { - m_pTexture = NULL; - m_pVB = NULL; - } - enum {m_dwTexWidth = 512, m_dwTexHeight = 512}; - - int CD3DFont::Init() - { - // Create vertex buffer for the letters - HRESULT hr; - if (FAILED(hr = dev->CreateVertexBuffer(MAX_NUM_VERTICES*sizeof(FONT2DVERTEX), - D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC, 0, D3DPOOL_DEFAULT, &m_pVB, NULL))) + str[0] = c + 32; + SIZE size; + GetTextExtentPoint32A(hDC, str, 1, &size); + if ((int)(x+size.cx+1) > m_dwTexWidth) { - return hr; - } - m_fTextScale = 1.0f; // Draw fonts into texture without scaling - - // Prepare to create a bitmap - int *pBitmapBits; - BITMAPINFO bmi; - ZeroMemory(&bmi.bmiHeader, sizeof(BITMAPINFOHEADER)); - bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - bmi.bmiHeader.biWidth = (int)m_dwTexWidth; - bmi.bmiHeader.biHeight = -(int)m_dwTexHeight; - bmi.bmiHeader.biPlanes = 1; - bmi.bmiHeader.biCompression = BI_RGB; - bmi.bmiHeader.biBitCount = 32; - - // Create a DC and a bitmap for the font - HDC hDC = CreateCompatibleDC(NULL); - HBITMAP hbmBitmap = CreateDIBSection(hDC, &bmi, DIB_RGB_COLORS, (VOID**)&pBitmapBits, NULL, 0); - SetMapMode(hDC, MM_TEXT); - - // Create a font. By specifying ANTIALIASED_QUALITY, we might get an - // antialiased font, but this is not guaranteed. - // We definitely don't want to get it cleartype'd, anyway. - int m_dwFontHeight = 24; - int nHeight = -MulDiv(m_dwFontHeight, int(GetDeviceCaps(hDC, LOGPIXELSY) * m_fTextScale), 72); - int dwBold = FW_NORMAL; ///FW_BOLD - HFONT hFont = CreateFont(nHeight, 0, 0, 0, dwBold, 0, - FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, - CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, - VARIABLE_PITCH, _T("Tahoma")); - if (NULL == hFont) - return E_FAIL; - - HGDIOBJ hOldbmBitmap = SelectObject(hDC, hbmBitmap); - HGDIOBJ hOldFont = SelectObject(hDC, hFont); - - // Set text properties - SetTextColor(hDC, 0xFFFFFF); - SetBkColor (hDC, 0); - SetTextAlign(hDC, TA_TOP); - - // Loop through all printable character and output them to the bitmap.. - // Meanwhile, keep track of the corresponding tex coords for each character. - int x = 0, y = 0; - char str[2] = "\0"; - for (int c = 0; c < 127 - 32; c++) - { - str[0] = c + 32; - SIZE size; - GetTextExtentPoint32A(hDC, str, 1, &size); - if ((int)(x+size.cx+1) > m_dwTexWidth) - { - x = 0; - y += size.cy + 1; - } - - ExtTextOutA(hDC, x+1, y+0, ETO_OPAQUE | ETO_CLIPPED, NULL, str, 1, NULL); - m_fTexCoords[c][0] = ((float)(x+0))/m_dwTexWidth; - m_fTexCoords[c][1] = ((float)(y+0))/m_dwTexHeight; - m_fTexCoords[c][2] = ((float)(x+0+size.cx))/m_dwTexWidth; - m_fTexCoords[c][3] = ((float)(y+0+size.cy))/m_dwTexHeight; - - x += size.cx + 3; //3 to work around annoying ij conflict (part of the j ends up with the i) + x = 0; + y += size.cy + 1; } - // Create a new texture for the font - hr = dev->CreateTexture(m_dwTexWidth, m_dwTexHeight, 1, D3DUSAGE_DYNAMIC, - D3DFMT_A4R4G4B4, D3DPOOL_DEFAULT, &m_pTexture, NULL); - if (FAILED(hr)) - { - PanicAlert("Failed to create font texture"); - return hr; - } + ExtTextOutA(hDC, x+1, y+0, ETO_OPAQUE | ETO_CLIPPED, NULL, str, 1, NULL); + m_fTexCoords[c][0] = ((float)(x+0))/m_dwTexWidth; + m_fTexCoords[c][1] = ((float)(y+0))/m_dwTexHeight; + m_fTexCoords[c][2] = ((float)(x+0+size.cx))/m_dwTexWidth; + m_fTexCoords[c][3] = ((float)(y+0+size.cy))/m_dwTexHeight; - // Lock the surface and write the alpha values for the set pixels - D3DLOCKED_RECT d3dlr; - m_pTexture->LockRect(0, &d3dlr, 0, D3DLOCK_DISCARD); - int bAlpha; // 4-bit measure of pixel intensity - - for (y = 0; y < m_dwTexHeight; y++) - { - u16 *pDst16 = (u16*)((u8 *)d3dlr.pBits + y * d3dlr.Pitch); - for (x = 0; x < m_dwTexWidth; x++) - { - bAlpha = ((pBitmapBits[m_dwTexWidth * y + x] & 0xff) >> 4); - pDst16[x] = (bAlpha << 12) | 0x0fff; - } - } - - // Done updating texture, so clean up used objects - m_pTexture->UnlockRect(0); - - SelectObject(hDC, hOldbmBitmap); - DeleteObject(hbmBitmap); - - SelectObject(hDC, hOldFont); - DeleteObject(hFont); - - return S_OK; + x += size.cx + 3; //3 to work around annoying ij conflict (part of the j ends up with the i) } - int CD3DFont::Shutdown() + // Create a new texture for the font + hr = dev->CreateTexture(m_dwTexWidth, m_dwTexHeight, 1, D3DUSAGE_DYNAMIC, + D3DFMT_A4R4G4B4, D3DPOOL_DEFAULT, &m_pTexture, NULL); + if (FAILED(hr)) { - m_pVB->Release(); - m_pVB = NULL; - m_pTexture->Release(); - m_pTexture = NULL; - return S_OK; + PanicAlert("Failed to create font texture"); + return hr; } + // Lock the surface and write the alpha values for the set pixels + D3DLOCKED_RECT d3dlr; + m_pTexture->LockRect(0, &d3dlr, 0, D3DLOCK_DISCARD); + int bAlpha; // 4-bit measure of pixel intensity - const int RS[6][2] = + for (y = 0; y < m_dwTexHeight; y++) { - {D3DRS_ALPHABLENDENABLE, TRUE}, - {D3DRS_SRCBLEND, D3DBLEND_SRCALPHA}, - {D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA}, - {D3DRS_CULLMODE, D3DCULL_NONE}, - {D3DRS_ZENABLE, FALSE}, - {D3DRS_FOGENABLE, FALSE}, - }; - const int TS[6][2] = - { - {D3DTSS_COLOROP, D3DTOP_MODULATE}, - {D3DTSS_COLORARG1, D3DTA_TEXTURE}, - {D3DTSS_COLORARG2, D3DTA_DIFFUSE }, - {D3DTSS_ALPHAOP, D3DTOP_MODULATE }, - {D3DTSS_ALPHAARG1, D3DTA_TEXTURE }, - {D3DTSS_ALPHAARG2, D3DTA_DIFFUSE }, - }; - - static DWORD RS_old[6]; - static DWORD TS_old[6]; - static LPDIRECT3DBASETEXTURE9 texture_old; - static LPDIRECT3DPIXELSHADER9 ps_old; - static LPDIRECT3DVERTEXSHADER9 vs_old; - - void SaveRenderStates() - { - // TODO: Get rid of these Gets so we can potentially switch to Pure Device - for (int i = 0; i < 6; i++) + u16 *pDst16 = (u16*)((u8 *)d3dlr.pBits + y * d3dlr.Pitch); + for (x = 0; x < m_dwTexWidth; x++) { - dev->GetRenderState((_D3DRENDERSTATETYPE)RS[i][0], &(RS_old[i])); - dev->GetTextureStageState(0, (_D3DTEXTURESTAGESTATETYPE)int(TS[i][0]), &(TS_old[i])); - } - dev->GetTexture(0, &texture_old); - dev->GetPixelShader(&ps_old); - dev->GetVertexShader(&vs_old); - } - - void RestoreRenderStates() - { - D3D::SetTexture(0, texture_old); - - dev->SetPixelShader(ps_old); - dev->SetVertexShader(vs_old); - - for (int i = 0; i < 6; i++) - { - D3D::SetRenderState((_D3DRENDERSTATETYPE)RS[i][0], RS_old[i]); - D3D::SetTextureStageState(0, (_D3DTEXTURESTAGESTATETYPE)int(TS[i][0]), TS_old[i]); + bAlpha = ((pBitmapBits[m_dwTexWidth * y + x] & 0xff) >> 4); + pDst16[x] = (bAlpha << 12) | 0x0fff; } } - void CD3DFont::SetRenderStates() + // Done updating texture, so clean up used objects + m_pTexture->UnlockRect(0); + + SelectObject(hDC, hOldbmBitmap); + DeleteObject(hbmBitmap); + + SelectObject(hDC, hOldFont); + DeleteObject(hFont); + + return S_OK; +} + +int CD3DFont::Shutdown() +{ + m_pVB->Release(); + m_pVB = NULL; + m_pTexture->Release(); + m_pTexture = NULL; + return S_OK; +} + + +const int RS[6][2] = +{ + {D3DRS_ALPHABLENDENABLE, TRUE}, + {D3DRS_SRCBLEND, D3DBLEND_SRCALPHA}, + {D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA}, + {D3DRS_CULLMODE, D3DCULL_NONE}, + {D3DRS_ZENABLE, FALSE}, + {D3DRS_FOGENABLE, FALSE}, +}; +const int TS[6][2] = +{ + {D3DTSS_COLOROP, D3DTOP_MODULATE}, + {D3DTSS_COLORARG1, D3DTA_TEXTURE}, + {D3DTSS_COLORARG2, D3DTA_DIFFUSE }, + {D3DTSS_ALPHAOP, D3DTOP_MODULATE }, + {D3DTSS_ALPHAARG1, D3DTA_TEXTURE }, + {D3DTSS_ALPHAARG2, D3DTA_DIFFUSE }, +}; + +static DWORD RS_old[6]; +static DWORD TS_old[6]; +static LPDIRECT3DBASETEXTURE9 texture_old; +static LPDIRECT3DPIXELSHADER9 ps_old; +static LPDIRECT3DVERTEXSHADER9 vs_old; + +void SaveRenderStates() +{ + // TODO: Get rid of these Gets so we can potentially switch to Pure Device + for (int i = 0; i < 6; i++) { - D3D::SetTexture(0, m_pTexture); + dev->GetRenderState((_D3DRENDERSTATETYPE)RS[i][0], &(RS_old[i])); + dev->GetTextureStageState(0, (_D3DTEXTURESTAGESTATETYPE)int(TS[i][0]), &(TS_old[i])); + } + dev->GetTexture(0, &texture_old); + dev->GetPixelShader(&ps_old); + dev->GetVertexShader(&vs_old); +} - dev->SetPixelShader(0); - dev->SetVertexShader(0); - - dev->SetFVF(D3DFVF_FONT2DVERTEX); +void RestoreRenderStates() +{ + D3D::SetTexture(0, texture_old); - for (int i = 0; i < 6; i++) - { - D3D::SetRenderState((_D3DRENDERSTATETYPE)RS[i][0], RS[i][1]); - D3D::SetTextureStageState(0, (_D3DTEXTURESTAGESTATETYPE)int(TS[i][0]), TS[i][1]); - } + dev->SetPixelShader(ps_old); + dev->SetVertexShader(vs_old); + + for (int i = 0; i < 6; i++) + { + D3D::SetRenderState((_D3DRENDERSTATETYPE)RS[i][0], RS_old[i]); + D3D::SetTextureStageState(0, (_D3DTEXTURESTAGESTATETYPE)int(TS[i][0]), TS_old[i]); + } +} + +void CD3DFont::SetRenderStates() +{ + D3D::SetTexture(0, m_pTexture); + + dev->SetPixelShader(0); + dev->SetVertexShader(0); + + dev->SetFVF(D3DFVF_FONT2DVERTEX); + + for (int i = 0; i < 6; i++) + { + D3D::SetRenderState((_D3DRENDERSTATETYPE)RS[i][0], RS[i][1]); + D3D::SetTextureStageState(0, (_D3DTEXTURESTAGESTATETYPE)int(TS[i][0]), TS[i][1]); + } +} + + +int CD3DFont::DrawTextScaled(float x, float y, float fXScale, float fYScale, float spacing, u32 dwColor, const char* strText, bool center) +{ + if (!m_pVB) + return 0; + + SaveRenderStates(); + SetRenderStates(); + dev->SetStreamSource(0, m_pVB, 0, sizeof(FONT2DVERTEX)); + + float vpWidth = 1; + float vpHeight = 1; + + float sx = x*vpWidth-0.5f; + float sy = y*vpHeight-0.5f; + + float fStartX = sx; + + float invLineHeight = 1.0f / ((m_fTexCoords[0][3] - m_fTexCoords[0][1]) * m_dwTexHeight); + // Fill vertex buffer + FONT2DVERTEX* pVertices; + int dwNumTriangles = 0L; + m_pVB->Lock(0, 0, (void**)&pVertices, D3DLOCK_DISCARD); + + const char *oldstrText=strText; + //First, let's measure the text + float tw=0; + float mx=0; + float maxx=0; + + while (*strText) + { + char c = *strText++; + + if (c == ('\n')) + mx = 0; + if (c < (' ')) + continue; + + float tx1 = m_fTexCoords[c-32][0]; + float tx2 = m_fTexCoords[c-32][2]; + + float w = (tx2-tx1)*m_dwTexWidth; + w *= (fXScale*vpHeight)*invLineHeight; + mx += w + spacing*fXScale*vpWidth; + if (mx > maxx) maxx = mx; } - - int CD3DFont::DrawTextScaled(float x, float y, float fXScale, float fYScale, float spacing, u32 dwColor, const char* strText, bool center) + float offset = -maxx/2; + strText = oldstrText; + //Then let's draw it + if (center) { - if (!m_pVB) - return 0; + sx+=offset; + fStartX+=offset; + } - SaveRenderStates(); - SetRenderStates(); - dev->SetStreamSource(0, m_pVB, 0, sizeof(FONT2DVERTEX)); + float wScale = (fXScale*vpHeight)*invLineHeight; + float hScale = (fYScale*vpHeight)*invLineHeight; - float vpWidth = 1; - float vpHeight = 1; + while (*strText) + { + char c = *strText++; - float sx = x*vpWidth-0.5f; - float sy = y*vpHeight-0.5f; - - float fStartX = sx; - - float invLineHeight = 1.0f / ((m_fTexCoords[0][3] - m_fTexCoords[0][1]) * m_dwTexHeight); - // Fill vertex buffer - FONT2DVERTEX* pVertices; - int dwNumTriangles = 0L; - m_pVB->Lock(0, 0, (void**)&pVertices, D3DLOCK_DISCARD); - - const char *oldstrText=strText; - //First, let's measure the text - float tw=0; - float mx=0; - float maxx=0; - - while (*strText) + if (c == ('\n')) { - char c = *strText++; - - if (c == ('\n')) - mx = 0; - if (c < (' ')) - continue; - - float tx1 = m_fTexCoords[c-32][0]; - float tx2 = m_fTexCoords[c-32][2]; - - float w = (tx2-tx1)*m_dwTexWidth; - w *= (fXScale*vpHeight)*invLineHeight; - mx += w + spacing*fXScale*vpWidth; - if (mx > maxx) maxx = mx; + sx = fStartX; + sy += fYScale*vpHeight; } + if (c < (' ')) + continue; - float offset = -maxx/2; - strText = oldstrText; - //Then let's draw it - if (center) + c-=32; + float tx1 = m_fTexCoords[c][0]; + float ty1 = m_fTexCoords[c][1]; + float tx2 = m_fTexCoords[c][2]; + float ty2 = m_fTexCoords[c][3]; + + float w = (tx2-tx1)*m_dwTexWidth; + float h = (ty2-ty1)*m_dwTexHeight; + + w *= wScale; + h *= hScale; + + FONT2DVERTEX v[6]; + v[0] = InitFont2DVertex(sx, sy+h, dwColor, tx1, ty2); + v[1] = InitFont2DVertex(sx, sy, dwColor, tx1, ty1); + v[2] = InitFont2DVertex(sx+w, sy+h, dwColor, tx2, ty2); + v[3] = InitFont2DVertex(sx+w, sy, dwColor, tx2, ty1); + v[4] = v[2]; + v[5] = v[1]; + + memcpy(pVertices, v, 6*sizeof(FONT2DVERTEX)); + + pVertices+=6; + dwNumTriangles += 2; + + if (dwNumTriangles * 3 > (MAX_NUM_VERTICES - 6)) { - sx+=offset; - fStartX+=offset; - } - - float wScale = (fXScale*vpHeight)*invLineHeight; - float hScale = (fYScale*vpHeight)*invLineHeight; - - while (*strText) - { - char c = *strText++; - - if (c == ('\n')) - { - sx = fStartX; - sy += fYScale*vpHeight; - } - if (c < (' ')) - continue; - - c-=32; - float tx1 = m_fTexCoords[c][0]; - float ty1 = m_fTexCoords[c][1]; - float tx2 = m_fTexCoords[c][2]; - float ty2 = m_fTexCoords[c][3]; - - float w = (tx2-tx1)*m_dwTexWidth; - float h = (ty2-ty1)*m_dwTexHeight; - - w *= wScale; - h *= hScale; - - FONT2DVERTEX v[6]; - v[0] = InitFont2DVertex(sx, sy+h, dwColor, tx1, ty2); - v[1] = InitFont2DVertex(sx, sy, dwColor, tx1, ty1); - v[2] = InitFont2DVertex(sx+w, sy+h, dwColor, tx2, ty2); - v[3] = InitFont2DVertex(sx+w, sy, dwColor, tx2, ty1); - v[4] = v[2]; - v[5] = v[1]; - - memcpy(pVertices, v, 6*sizeof(FONT2DVERTEX)); - - pVertices+=6; - dwNumTriangles += 2; - - if (dwNumTriangles * 3 > (MAX_NUM_VERTICES - 6)) - { - // Unlock, render, and relock the vertex buffer - m_pVB->Unlock(); - dev->DrawPrimitive(D3DPT_TRIANGLELIST, 0, dwNumTriangles); - m_pVB->Lock(0, 0, (void**)&pVertices, D3DLOCK_DISCARD); - dwNumTriangles = 0; - } - - sx += w + spacing*fXScale*vpWidth; - } - - // Unlock and render the vertex buffer - m_pVB->Unlock(); - if (dwNumTriangles > 0) + // Unlock, render, and relock the vertex buffer + m_pVB->Unlock(); dev->DrawPrimitive(D3DPT_TRIANGLELIST, 0, dwNumTriangles); - RestoreRenderStates(); - return S_OK; + m_pVB->Lock(0, 0, (void**)&pVertices, D3DLOCK_DISCARD); + dwNumTriangles = 0; + } + + sx += w + spacing*fXScale*vpWidth; } - void quad2d(float x1, float y1, float x2, float y2, u32 color, float u1, float v1, float u2, float v2) - { - SaveRenderStates(); - struct Q2DVertex { float x,y,z,rhw; u32 color; float u, v; } coords[4] = { - {x1-0.5f, y1-0.5f, 0, 1, color, u1, v1}, - {x2-0.5f, y1-0.5f, 0, 1, color, u2, v1}, - {x2-0.5f, y2-0.5f, 0, 1, color, u2, v2}, - {x1-0.5f, y2-0.5f, 0, 1, color, u1, v2}, - }; - dev->SetPixelShader(0); - dev->SetVertexShader(0); - dev->SetVertexDeclaration(0); - - dev->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1); - dev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, coords, sizeof(Q2DVertex)); - - RestoreRenderStates(); - } + // Unlock and render the vertex buffer + m_pVB->Unlock(); + if (dwNumTriangles > 0) + dev->DrawPrimitive(D3DPT_TRIANGLELIST, 0, dwNumTriangles); + RestoreRenderStates(); + return S_OK; +} + +void quad2d(float x1, float y1, float x2, float y2, u32 color, float u1, float v1, float u2, float v2) +{ + SaveRenderStates(); + struct Q2DVertex { float x,y,z,rhw; u32 color; float u, v; } coords[4] = { + {x1-0.5f, y1-0.5f, 0, 1, color, u1, v1}, + {x2-0.5f, y1-0.5f, 0, 1, color, u2, v1}, + {x2-0.5f, y2-0.5f, 0, 1, color, u2, v2}, + {x1-0.5f, y2-0.5f, 0, 1, color, u1, v2}, + }; + dev->SetPixelShader(0); + dev->SetVertexShader(0); + dev->SetVertexDeclaration(0); + + dev->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1); + dev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, coords, sizeof(Q2DVertex)); + + RestoreRenderStates(); +} } // namespace