text: 
  #include "Gwen/Renderers/DirectX9.h"
  #include "Gwen/Utility.h"
  #include "Gwen/Font.h"
  #include "Gwen/Texture.h"
  #include "Gwen/WindowProvider.h"
  
  #define D3DFVF_VERTEXFORMAT2D (D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1)
  
  struct FontData
  {
      ID3DXFont*  pFont;
      int iSpaceWidth;
  };
  
  
  namespace Gwen
  {
      namespace Renderer
      {
          DirectX9::DirectX9(IDirect3DDevice9* pDevice)
          {
              m_pD3D = NULL;
              m_pDevice = pDevice;
              m_iVertNum = 0;
  
              for (int i = 0; i < MaxVerts; i++)
              {
                  m_pVerts[ i ].z = 0.5f;
                  m_pVerts[ i ].rhw = 1.0f;
              }
          }
  
          DirectX9::~DirectX9()
          {
          }
  
          void DirectX9::Begin()
          {
              m_pDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
              m_pDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
              m_pDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
              m_pDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
              m_pDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
              m_pDevice->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_NONE);
              m_pDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
              m_pDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
              m_pDevice->SetTextureStageState(0, D3DTSS_COLOROP,     D3DTOP_MODULATE);
              m_pDevice->SetTextureStageState(0, D3DTSS_COLORARG1,   D3DTA_TEXTURE);
              m_pDevice->SetTextureStageState(0, D3DTSS_COLORARG2,   D3DTA_CURRENT);
              m_pDevice->SetTextureStageState(0, D3DTSS_ALPHAOP,     D3DTOP_MODULATE);
              m_pDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1,   D3DTA_TEXTURE);
              m_pDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2,   D3DTA_CURRENT);
              m_pDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
              m_pDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
          }
  
          void DirectX9::End()
          {
              Flush();
          }
  
          void DirectX9::Flush()
          {
              if (m_iVertNum > 0)
              {
                  m_pDevice->SetFVF(D3DFVF_VERTEXFORMAT2D);
                  m_pDevice->DrawPrimitiveUP(D3DPT_TRIANGLELIST, m_iVertNum/3, &m_pVerts[0],
                                             sizeof(VertexFormat));
                  m_iVertNum = 0;
              }
          }
  
          void DirectX9::AddVert(int x, int y)
          {
              if (m_iVertNum >= MaxVerts-1)
                  Flush();
  
              m_pVerts[ m_iVertNum ].x = (float)x;
              m_pVerts[ m_iVertNum ].y = (float)y;
              m_pVerts[ m_iVertNum ].color = m_Color;
              m_iVertNum++;
          }
  
          void DirectX9::AddVert(int x, int y, float u, float v)
          {
              if (m_iVertNum >= MaxVerts-1)
                  Flush();
  
              m_pVerts[ m_iVertNum ].x = -0.5f+(float)x;
              m_pVerts[ m_iVertNum ].y = -0.5f+(float)y;
              m_pVerts[ m_iVertNum ].u = u;
              m_pVerts[ m_iVertNum ].v = v;
              m_pVerts[ m_iVertNum ].color = m_Color;
              m_iVertNum++;
          }
  
          void DirectX9::DrawFilledRect(Gwen::Rect rect)
          {
              if (m_pCurrentTexture != NULL)
              {
                  Flush();
                  m_pDevice->SetTexture(0, NULL);
                  m_pCurrentTexture = NULL;
              }
  
              Translate(rect);
              AddVert(rect.x, rect.y);
              AddVert(rect.x+rect.w, rect.y);
              AddVert(rect.x, rect.y+rect.h);
              AddVert(rect.x+rect.w, rect.y);
              AddVert(rect.x+rect.w, rect.y+rect.h);
              AddVert(rect.x, rect.y+rect.h);
          }
  
          void DirectX9::SetDrawColor(Gwen::Color color)
          {
              m_Color = D3DCOLOR_ARGB(color.a, color.r, color.g, color.b);
          }
  
          void DirectX9::LoadFont(Gwen::Font* font)
          {
              m_FontList.push_back(font);
              // Scale the font according to canvas
              font->realsize = font->size*Scale();
              D3DXFONT_DESC fd;
              memset(&fd, 0, sizeof(fd));
              const std::wstring wfontname( Utility::Widen(font->facename) );
              wcscpy_s(fd.FaceName, LF_FACESIZE, wfontname.c_str());
              fd.Width = 0;
              fd.MipLevels = 1;
              fd.CharSet = DEFAULT_CHARSET;
              fd.Height = font->realsize* -1.0f;
              fd.OutputPrecision = OUT_DEFAULT_PRECIS;
              fd.Italic = 0;
              fd.Weight = font->bold ? FW_BOLD : FW_NORMAL;
  #ifdef CLEARTYPE_QUALITY
              fd.Quality = font->realsize < 14 ? DEFAULT_QUALITY : CLEARTYPE_QUALITY;
  #else
              fd.Quality = PROOF_QUALITY;
  #endif
              fd.PitchAndFamily = DEFAULT_PITCH|FF_DONTCARE;
              LPD3DXFONT pD3DXFont;
              HRESULT hr = D3DXCreateFontIndirect(m_pDevice, &fd, &pD3DXFont);
              FontData*   pFontData = new FontData();
              pFontData->pFont = pD3DXFont;
              // ID3DXFont doesn't measure trailing spaces, so we measure the
              // width of a space here and store it
              // in the font data - then we can add it to the width when we
              // measure text with trailing spaces.
              {
                  RECT rctA = {0, 0, 0, 0};
                  pFontData->pFont->DrawTextW(NULL, L"A", -1, &rctA,
                                              DT_CALCRECT|DT_LEFT|DT_TOP|DT_SINGLELINE, 0);
                  RECT rctSpc = {0, 0, 0, 0};
                  pFontData->pFont->DrawTextW(NULL, L"A A", -1, &rctSpc,
                                              DT_CALCRECT|DT_LEFT|DT_TOP|DT_SINGLELINE, 0);
                  pFontData->iSpaceWidth = rctSpc.right-rctA.right*2;
              }
              font->data = pFontData;
          }
  
          void DirectX9::FreeFont(Gwen::Font* pFont)
          {
              m_FontList.remove(pFont);
  
              if (!pFont->data)
                  return;
  
              FontData* pFontData = (FontData*)pFont->data;
  
              if (pFontData->pFont)
              {
                  pFontData->pFont->Release();
                  pFontData->pFont = NULL;
              }
  
              delete pFontData;
              pFont->data = NULL;
          }
  
          void DirectX9::RenderText(Gwen::Font* pFont, Gwen::Point pos,
                                    const Gwen::String& text)
          {
              Flush();
  
              // If the font doesn't exist, or the font size should be changed
              if (!pFont->data || fabs(pFont->realsize-pFont->size*Scale()) > 2)
              {
                  FreeFont(pFont);
                  LoadFont(pFont);
              }
  
              const std::wstring wideText(Utility::Widen(text));
  
              FontData* pFontData = (FontData*)pFont->data;
              Translate(pos.x, pos.y);
              RECT ClipRect = { pos.x, pos.y, 0, 0 };
              pFontData->pFont->DrawTextW(NULL,
                                          wideText.c_str(), -1, &ClipRect, DT_LEFT|DT_TOP|DT_NOCLIP|DT_SINGLELINE,
                                          m_Color);
          }
  
          Gwen::Point DirectX9::MeasureText(Gwen::Font* pFont, const Gwen::String& text)
          {
              // If the font doesn't exist, or the font size should be changed
              if (!pFont->data || fabs(pFont->realsize-pFont->size*Scale()) > 2)
              {
                  FreeFont(pFont);
                  LoadFont(pFont);
              }
  
              FontData* pFontData = (FontData*)pFont->data;
              Gwen::Point size;
  
              if (text.empty())
              {
                  RECT rct = {0, 0, 0, 0};
                  pFontData->pFont->DrawTextW(NULL, L"W", -1, &rct, DT_CALCRECT, 0);
                  return Gwen::Point(0, rct.bottom);
              }
  
              const std::wstring wideText(Utility::Widen(text));
  
              RECT rct = {0, 0, 0, 0};
              pFontData->pFont->DrawTextW(NULL,
                                          wideText.c_str(), -1, &rct, DT_CALCRECT|DT_LEFT|DT_TOP|DT_SINGLELINE,
                                          0);
  
              for (int i = wideText.length()-1; i >= 0 && wideText[i] == L' '; i--)
              {
                  rct.right += pFontData->iSpaceWidth;
              }
  
              return Gwen::Point(rct.right/Scale(), rct.bottom/Scale());
          }
  
          void DirectX9::StartClip()
          {
              Flush();
              m_pDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE);
              const Gwen::Rect& rect = ClipRegion();
              RECT r;
              r.left = ceil(((float)rect.x)*Scale());
              r.right = ceil(((float)(rect.x+rect.w))*Scale());
              r.top = ceil((float)rect.y*Scale());
              r.bottom = ceil(((float)(rect.y+rect.h))*Scale());
              m_pDevice->SetScissorRect(&r);
          }
  
          void DirectX9::EndClip()
          {
              Flush();
              m_pDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
          }
  
          void DirectX9::DrawTexturedRect(Gwen::Texture* pTexture, Gwen::Rect rect, float u1,
                                          float v1, float u2, float v2)
          {
              IDirect3DTexture9* pImage = (IDirect3DTexture9*)pTexture->data;
  
              // Missing image, not loaded properly?
              if (!pImage)
                  return DrawMissingImage(rect);
  
              Translate(rect);
  
              if (m_pCurrentTexture != pImage)
              {
                  Flush();
                  m_pDevice->SetTexture(0, pImage);
                  m_pCurrentTexture = pImage;
              }
  
              AddVert(rect.x, rect.y,            u1, v1);
              AddVert(rect.x+rect.w, rect.y,       u2, v1);
              AddVert(rect.x, rect.y+rect.h,   u1, v2);
              AddVert(rect.x+rect.w, rect.y,       u2, v1);
              AddVert(rect.x+rect.w, rect.y+rect.h, u2, v2);
              AddVert(rect.x, rect.y+rect.h, u1, v2);
          }
  
          void DirectX9::LoadTexture(Gwen::Texture* pTexture)
          {
              IDirect3DTexture9* ptr = NULL;
              D3DXIMAGE_INFO ImageInfo;
              const std::wstring wtexName( Utility::Widen(pTexture->name) );
              HRESULT hr = D3DXCreateTextureFromFileExW(m_pDevice,
                                                        wtexName.c_str(),
                                                        0, 0, D3DX_DEFAULT, 0, D3DFMT_UNKNOWN,
                                                        D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, &ImageInfo, NULL,
                                                        &ptr);
  
              if (hr != S_OK)
                  return;
  
              pTexture->data = ptr;
              pTexture->width = ImageInfo.Width;
              pTexture->height = ImageInfo.Height;
          }
  
          void DirectX9::FreeTexture(Gwen::Texture* pTexture)
          {
              IDirect3DTexture9* pImage = (IDirect3DTexture9*)pTexture->data;
  
              if (!pImage)
                  return;
  
              pImage->Release();
              pTexture->data = NULL;
          }
  
          Gwen::Color DirectX9::PixelColour(Gwen::Texture* pTexture, unsigned int x, unsigned int y,
                                            const Gwen::Color& col_default)
          {
              IDirect3DTexture9* pImage = (IDirect3DTexture9*)pTexture->data;
  
              if (!pImage)
                  return col_default;
  
              IDirect3DSurface9* pSurface = NULL;
  
              if (pImage->GetSurfaceLevel(0, &pSurface) != S_OK)
                  return col_default;
  
              if (!pSurface)
                  return col_default;
  
              D3DLOCKED_RECT lockedRect;
              pSurface->LockRect(&lockedRect, NULL, D3DLOCK_READONLY);
              DWORD* pixels = (DWORD*)lockedRect.pBits;
              D3DXCOLOR color = pixels[lockedRect.Pitch/sizeof(DWORD)*y+x];
              pSurface->UnlockRect();
              pSurface->Release();
              return Gwen::Color(color.r*255, color.g*255, color.b*255, color.a*255);
          }
  
          void DirectX9::Release()
          {
              Font::List::iterator it = m_FontList.begin();
  
              while (it != m_FontList.end())
              {
                  FreeFont(*it);
                  it = m_FontList.begin();
              }
          }
  
          void DirectX9::FillPresentParameters(Gwen::WindowProvider* pWindow,
                                               D3DPRESENT_PARAMETERS& Params)
          {
              HWND pHWND = (HWND)pWindow->GetWindow();
              RECT ClientRect;
              GetClientRect(pHWND, &ClientRect);
              ZeroMemory(&Params, sizeof(Params));
              Params.Windowed                     = true;
              Params.SwapEffect                   = D3DSWAPEFFECT_DISCARD;
              Params.BackBufferWidth              = ClientRect.right;
              Params.BackBufferHeight             = ClientRect.bottom;
              Params.FullScreen_RefreshRateInHz   = D3DPRESENT_RATE_DEFAULT;
              Params.BackBufferFormat             = D3DFMT_X8R8G8B8;
              Params.PresentationInterval         = D3DPRESENT_INTERVAL_IMMEDIATE;
          }
  
          bool DirectX9::InitializeContext(Gwen::WindowProvider* pWindow)
          {
              HWND pHWND = (HWND)pWindow->GetWindow();
              m_pD3D = Direct3DCreate9(D3D_SDK_VERSION);
  
              if (!m_pD3D)
                  return false;
  
              D3DCAPS9 D3DCaps;
              m_pD3D->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &D3DCaps);
              DWORD BehaviourFlags = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  
              if (D3DCaps.VertexProcessingCaps != 0)
                  BehaviourFlags = D3DCREATE_HARDWARE_VERTEXPROCESSING;
  
              D3DPRESENT_PARAMETERS Params;
              FillPresentParameters(pWindow, Params);
              HRESULT hr = m_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, pHWND,
                                                D3DCREATE_HARDWARE_VERTEXPROCESSING, &Params,
                                                &m_pDevice);
  
              if (FAILED(hr))
                  return false;
  
              return true;
          }
  
          bool DirectX9::ShutdownContext(Gwen::WindowProvider* pWindow)
          {
              if (m_pDevice)
              {
                  m_pDevice->Release();
                  m_pDevice = NULL;
              }
  
              if (m_pD3D)
              {
                  m_pD3D->Release();
                  m_pD3D = NULL;
              }
  
              return true;
          }
  
          bool DirectX9::PresentContext(Gwen::WindowProvider* pWindow)
          {
              m_pDevice->Present(NULL, NULL, NULL, NULL);
              return true;
          }
  
          bool DirectX9::ResizedContext(Gwen::WindowProvider* pWindow, int w, int h)
          {
              // Force setting the current texture again
              m_pCurrentTexture = NULL;
              // Free any unmanaged resources (fonts)
              Release();
              // Get the new window size from the HWND
              D3DPRESENT_PARAMETERS Params;
              FillPresentParameters(pWindow, Params);
              // And reset the device!
              m_pDevice->Reset(&Params);
              return true;
          }
  
          bool DirectX9::BeginContext(Gwen::WindowProvider* pWindow)
          {
              m_pDevice->BeginScene();
              m_pDevice->Clear(0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL, D3DCOLOR_XRGB(
                                   128, 128,
                                   128), 1, 0);
              return true;
          }
  
          bool DirectX9::EndContext(Gwen::WindowProvider* pWindow)
          {
              m_pDevice->EndScene();
              return true;
          }
  
      }
  }
  