Advertisement
Guest User

Untitled

a guest
May 30th, 2019
860
1
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 21.47 KB | None | 1 0
  1. //-----------------------------------------------------------------------------
  2. // File: D3DFont.cpp
  3. //
  4. // Desc: Texture-based font class
  5. //-----------------------------------------------------------------------------
  6.  
  7. #pragma once
  8. #include <cstdio>
  9. #include <cmath>
  10. #include <tchar.h>
  11. #include <corecrt_wstring.h>
  12. #include "D3DFont.h"
  13.  
  14.  
  15.  
  16.  
  17. //-----------------------------------------------------------------------------
  18. // Custom vertex types for rendering text
  19. //-----------------------------------------------------------------------------
  20. #define MAX_NUM_VERTICES (50*6)
  21.  
  22. struct FONT2DVERTEX
  23. {
  24.     D3DXVECTOR4 p;
  25.     DWORD       color;
  26.     FLOAT       tu, tv;
  27. };
  28.  
  29. struct FONT3DVERTEX
  30. {
  31.     D3DXVECTOR3 p;
  32.     D3DXVECTOR3 n;
  33.     FLOAT       tu, tv;
  34. };
  35.  
  36. #define D3DFVF_FONT2DVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1)
  37. #define D3DFVF_FONT3DVERTEX (D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1)
  38.  
  39. inline FONT2DVERTEX InitFont2DVertex(const D3DXVECTOR4& p, D3DCOLOR color, FLOAT tu, FLOAT tv)
  40. {
  41.     FONT2DVERTEX v;
  42.     v.p = p;
  43.     v.color = color;
  44.     v.tu = tu;
  45.     v.tv = tv;
  46.     return v;
  47. }
  48.  
  49. inline FONT3DVERTEX InitFont3DVertex(const D3DXVECTOR3& p, const D3DXVECTOR3& n, FLOAT tu, FLOAT tv)
  50. {
  51.     FONT3DVERTEX v;
  52.     v.p = p;
  53.     v.n = n;
  54.     v.tu = tu;
  55.     v.tv = tv;
  56.     return v;
  57. }
  58.  
  59.  
  60.  
  61.  
  62. //-----------------------------------------------------------------------------
  63. // Name: CD3DFont()
  64. // Desc: Font class constructor
  65. //-----------------------------------------------------------------------------
  66. CD3DFont::CD3DFont(const TCHAR* strFontName, DWORD dwHeight, DWORD dwWeight, DWORD dwFlags)
  67. {
  68.     wcsncpy_s(this->strFontName, strFontName, sizeof(this->strFontName) / sizeof(TCHAR));
  69.     this->strFontName[sizeof(this->strFontName) / sizeof(TCHAR) - 1] = _T('\0');
  70.     this->dwFontHeight = dwHeight;
  71.     this->dwFontWeight = dwWeight;
  72.     this->dwFontFlags = dwFlags;
  73.     this->dwSpacing = 0;
  74.  
  75.     this->pd3dDevice = NULL;
  76.     this->pTexture = NULL;
  77.     this->pVB = NULL;
  78.  
  79.     this->pStateBlockSaved = NULL;
  80.     this->pStateBlockDrawString = NULL;
  81. }
  82.  
  83.  
  84.  
  85.  
  86. //-----------------------------------------------------------------------------
  87. // Name: ~CD3DFont()
  88. // Desc: Font class destructor
  89. //-----------------------------------------------------------------------------
  90. CD3DFont::~CD3DFont()
  91. {
  92.     InvalidateDeviceObjects();
  93.     DeleteDeviceObjects();
  94. }
  95.  
  96.  
  97.  
  98.  
  99. //-----------------------------------------------------------------------------
  100. // Name: InitDeviceObjects()
  101. // Desc: Initializes device-dependent objects, including the vertex buffer used
  102. //       for rendering text and the texture map which stores the font image.
  103. //-----------------------------------------------------------------------------
  104. HRESULT CD3DFont::InitDeviceObjects(LPDIRECT3DDEVICE9 pd3dDevice)
  105. {
  106.     HRESULT hr;
  107.  
  108.     // Keep a local copy of the device
  109.     this->pd3dDevice = pd3dDevice;
  110.  
  111.     // Establish the font and texture size
  112.     this->fTextScale = 1.0f; // Draw fonts into texture without scaling
  113.  
  114.     // Large fonts need larger textures
  115.     if (this->dwFontHeight > 60)
  116.         this->dwTexWidth = this->dwTexHeight = 2048;
  117.     else if (this->dwFontHeight > 30)
  118.         this->dwTexWidth = this->dwTexHeight = 1024;
  119.     else if (this->dwFontHeight > 15)
  120.         this->dwTexWidth = this->dwTexHeight = 512;
  121.     else
  122.         this->dwTexWidth = this->dwTexHeight = 256;
  123.  
  124.     // If requested texture is too big, use a smaller texture and smaller font,
  125.     // and scale up when rendering.
  126.     D3DCAPS9 d3dCaps;
  127.     this->pd3dDevice->GetDeviceCaps(&d3dCaps);
  128.  
  129.     if (this->dwTexWidth > d3dCaps.MaxTextureWidth)
  130.     {
  131.         this->fTextScale = FLOAT(d3dCaps.MaxTextureWidth) / FLOAT(this->dwTexWidth);
  132.         this->dwTexWidth = this->dwTexHeight = d3dCaps.MaxTextureWidth;
  133.     }
  134.  
  135.     // Create a new texture for the font
  136.     hr = this->pd3dDevice->CreateTexture(this->dwTexWidth, this->dwTexHeight, 1, D3DUSAGE_DYNAMIC, D3DFMT_A4R4G4B4 ,D3DPOOL_DEFAULT, &this->pTexture, NULL);
  137.     if (FAILED(hr))
  138.         return hr;
  139.  
  140.     // Prepare to create a bitmap
  141.     DWORD*     pBitmapBits;
  142.     BITMAPINFO bmi;
  143.     ZeroMemory(&bmi.bmiHeader, sizeof(BITMAPINFOHEADER));
  144.     bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  145.     bmi.bmiHeader.biWidth = int(this->dwTexWidth);
  146.     bmi.bmiHeader.biHeight = -int(this->dwTexHeight);
  147.     bmi.bmiHeader.biPlanes = 1;
  148.     bmi.bmiHeader.biCompression = BI_RGB;
  149.     bmi.bmiHeader.biBitCount = 32;
  150.  
  151.     // Create a DC and a bitmap for the font
  152.     HDC     hDC = CreateCompatibleDC(NULL);
  153.     HBITMAP hbmBitmap = CreateDIBSection(hDC, &bmi, DIB_RGB_COLORS, (void**)&pBitmapBits, NULL, 0);
  154.  
  155.     // Sanity checks
  156.     if (hDC == NULL)
  157.         return E_FAIL;
  158.     if (hbmBitmap == NULL)
  159.         return E_FAIL;
  160.  
  161.     SetMapMode(hDC, MM_TEXT);
  162.  
  163.     // Create a font.  By specifying ANTIALIASED_QUALITY, we might get an
  164.     // antialiased font, but this is not guaranteed.
  165.     INT   nHeight = -MulDiv(this->dwFontHeight, (INT)(GetDeviceCaps(hDC, LOGPIXELSY) * this->fTextScale), 72);
  166.     DWORD dwItalic = (this->dwFontFlags & D3DFONT_ITALIC) ? TRUE : FALSE;
  167.     HFONT hFont = CreateFont(nHeight, 0, 0, 0, this->dwFontWeight, dwItalic, FALSE, FALSE, DEFAULT_CHARSET,
  168.         OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
  169.         this->dwFontHeight > 8 ? CLEARTYPE_NATURAL_QUALITY : ANTIALIASED_QUALITY, VARIABLE_PITCH,
  170.         this->strFontName);
  171.  
  172.     if (NULL == hFont)
  173.         return E_FAIL;
  174.  
  175.     HGDIOBJ hbmOld = SelectObject(hDC, hbmBitmap);
  176.     HGDIOBJ hFontOld = SelectObject(hDC, hFont);
  177.  
  178.     // Set text properties
  179.     SetTextColor(hDC, RGB(255, 255, 255));
  180.     SetBkColor(hDC, 0x00000000);
  181.     SetTextAlign(hDC, TA_TOP);
  182.  
  183.     // Loop through all printable character and output them to the bitmap..
  184.     // Meanwhile, keep track of the corresponding tex coords for each character.
  185.     DWORD x = 0;
  186.     DWORD y = 0;
  187.     TCHAR str[2] = _T("x");
  188.     SIZE  size;
  189.  
  190.     // Calculate the spacing between characters based on line height
  191.     GetTextExtentPoint32(hDC, TEXT(" "), 1, &size);
  192.     x = this->dwSpacing = (DWORD)ceil(size.cy * 0.3f);
  193.  
  194.     for (TCHAR c = 32; c < 127; c++)
  195.     {
  196.         str[0] = c;
  197.         GetTextExtentPoint32(hDC, str, 1, &size);
  198.  
  199.         if ((DWORD)(x + size.cx + this->dwSpacing) > this->dwTexWidth)
  200.         {
  201.             x = this->dwSpacing;
  202.             y += size.cy + 1;
  203.         }
  204.  
  205.         ExtTextOut(hDC, x + 0, y + 0, ETO_OPAQUE, NULL, str, 1, NULL);
  206.  
  207.         this->fTexCoords[c - 32][0] = ((FLOAT)(x + 0 - this->dwSpacing)) / this->dwTexWidth;
  208.         this->fTexCoords[c - 32][1] = ((FLOAT)(y + 0 + 0)) / this->dwTexHeight;
  209.         this->fTexCoords[c - 32][2] = ((FLOAT)(x + size.cx + this->dwSpacing)) / this->dwTexWidth;
  210.         this->fTexCoords[c - 32][3] = ((FLOAT)(y + size.cy + 0)) / this->dwTexHeight;
  211.  
  212.         x += size.cx + (2 * this->dwSpacing);
  213.     }
  214.  
  215.     // Lock the surface and write the alpha values for the set pixels
  216.     D3DLOCKED_RECT d3dlr;
  217.     this->pTexture->LockRect(0, &d3dlr, 0, 0);
  218.     BYTE* pDstRow = (BYTE*)d3dlr.pBits;
  219.     WORD* pDst16;
  220.     BYTE  bAlpha; // 4-bit measure of pixel intensity
  221.  
  222.     for (y = 0; y < this->dwTexHeight; y++)
  223.     {
  224.         pDst16 = (WORD*)pDstRow;
  225.         for (x = 0; x < this->dwTexWidth; x++)
  226.         {
  227.             bAlpha = (BYTE)((pBitmapBits[this->dwTexWidth * y + x] & 0xff) >> 4);
  228.             if (bAlpha > 0)
  229.             {
  230.                 *pDst16++ = (WORD)((bAlpha << 12) | 0x0fff);
  231.             }
  232.             else
  233.             {
  234.                 *pDst16++ = 0x0000;
  235.             }
  236.         }
  237.         pDstRow += d3dlr.Pitch;
  238.     }
  239.  
  240.     // Done updating texture, so clean up used objects
  241.     this->pTexture->UnlockRect(0);
  242.     SelectObject(hDC, hbmOld);
  243.     SelectObject(hDC, hFontOld);
  244.     DeleteObject(hbmBitmap);
  245.     DeleteObject(hFont);
  246.     DeleteDC(hDC);
  247.  
  248.     this->iHeight = static_cast<float>([this]()
  249.     {
  250.         SIZE size;
  251.         this->GetTextExtent("WJ", &size);
  252.         return size.cy;
  253.     }());
  254.  
  255.     this->iWidth = static_cast<float>([this]()
  256.     {
  257.         SIZE size;
  258.         this->GetTextExtent("WJ", &size);
  259.         return size.cx;
  260.     }());
  261.  
  262.     return S_OK;
  263. }
  264.  
  265.  
  266.  
  267.  
  268. //-----------------------------------------------------------------------------
  269. // Name: RestoreDeviceObjects()
  270. // Desc:
  271. //-----------------------------------------------------------------------------
  272. HRESULT CD3DFont::RestoreDeviceObjects()
  273. {
  274.     HRESULT hr;
  275.  
  276.     // Create vertex buffer for the letters
  277.     int vertexSize = max(sizeof(FONT2DVERTEX), sizeof(FONT3DVERTEX));
  278.     if (FAILED(hr = this->pd3dDevice->CreateVertexBuffer(MAX_NUM_VERTICES * vertexSize,
  279.         D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC, 0,
  280.         D3DPOOL_DEFAULT, &this->pVB, NULL)))
  281.     {
  282.         return hr;
  283.     }
  284.  
  285.     // Create the state blocks for rendering text
  286.     for (UINT which = 0; which < 2; which++)
  287.     {
  288.         this->pd3dDevice->BeginStateBlock();
  289.         this->pd3dDevice->SetTexture(0, this->pTexture);
  290.  
  291.         if (D3DFONT_ZENABLE & this->dwFontFlags)
  292.             this->pd3dDevice->SetRenderState(D3DRS_ZENABLE, TRUE);
  293.         else
  294.             this->pd3dDevice->SetRenderState(D3DRS_ZENABLE, FALSE);
  295.  
  296.         this->pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
  297.         this->pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
  298.         this->pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
  299.         this->pd3dDevice->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE);
  300.         this->pd3dDevice->SetRenderState(D3DRS_ALPHAREF, 0x08);
  301.         this->pd3dDevice->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL);
  302.         this->pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
  303.         this->pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
  304.         this->pd3dDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE);
  305.         this->pd3dDevice->SetRenderState(D3DRS_CLIPPING, TRUE);
  306.         this->pd3dDevice->SetRenderState(D3DRS_CLIPPLANEENABLE, FALSE);
  307.         this->pd3dDevice->SetRenderState(D3DRS_VERTEXBLEND, D3DVBF_DISABLE);
  308.         this->pd3dDevice->SetRenderState(D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE);
  309.         this->pd3dDevice->SetRenderState(D3DRS_FOGENABLE, FALSE);
  310.         this->pd3dDevice->SetRenderState(D3DRS_COLORWRITEENABLE,
  311.             D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN |
  312.             D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_ALPHA);
  313.         this->pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
  314.         this->pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
  315.         this->pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
  316.         this->pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
  317.         this->pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
  318.         this->pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
  319.         this->pd3dDevice->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 0);
  320.         this->pd3dDevice->SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE);
  321.         this->pd3dDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
  322.         this->pd3dDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
  323.         this->pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
  324.         this->pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
  325.         this->pd3dDevice->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_NONE);
  326.  
  327.         if (which == 0)
  328.             this->pd3dDevice->EndStateBlock(&this->pStateBlockSaved);
  329.         else
  330.             this->pd3dDevice->EndStateBlock(&this->pStateBlockDrawString);
  331.     }
  332.  
  333.     return S_OK;
  334. }
  335.  
  336.  
  337.  
  338.  
  339. //-----------------------------------------------------------------------------
  340. // Name: InvalidateDeviceObjects()
  341. // Desc: Destroys all device-dependent objects
  342. //-----------------------------------------------------------------------------
  343. HRESULT CD3DFont::InvalidateDeviceObjects()
  344. {
  345.     SAFE_RELEASE(this->pVB);
  346.     SAFE_RELEASE(this->pStateBlockSaved);
  347.     SAFE_RELEASE(this->pStateBlockDrawString);
  348.  
  349.     return S_OK;
  350. }
  351.  
  352.  
  353.  
  354.  
  355. //-----------------------------------------------------------------------------
  356. // Name: DeleteDeviceObjects()
  357. // Desc: Destroys all device-dependent objects
  358. //-----------------------------------------------------------------------------
  359. HRESULT CD3DFont::DeleteDeviceObjects()
  360. {
  361.     SAFE_RELEASE(this->pTexture);
  362.     this->pd3dDevice = NULL;
  363.  
  364.     return S_OK;
  365. }
  366.  
  367.  
  368.  
  369.  
  370. //-----------------------------------------------------------------------------
  371. // Name: GetTextExtent()
  372. // Desc: Get the dimensions of a text string
  373. //-----------------------------------------------------------------------------
  374. HRESULT CD3DFont::GetTextExtent(const char* strText, SIZE* pSize)
  375. {
  376.     if (NULL == strText || NULL == pSize)
  377.         return E_FAIL;
  378.  
  379.     FLOAT fRowWidth = 0.0f;
  380.     FLOAT fRowHeight = (this->fTexCoords[0][3] - this->fTexCoords[0][1]) * this->dwTexHeight;
  381.     FLOAT fWidth = 0.0f;
  382.     FLOAT fHeight = fRowHeight;
  383.  
  384.     while (*strText)
  385.     {
  386.         TCHAR c = *strText++;
  387.  
  388.         if (c == _T('\n'))
  389.         {
  390.             fRowWidth = 0.0f;
  391.             fHeight += fRowHeight;
  392.         }
  393.  
  394.         if ((c - 32) < 0 || (c - 32) >= 128 - 32)
  395.             continue;
  396.  
  397.         FLOAT tx1 = this->fTexCoords[c - 32][0];
  398.         FLOAT tx2 = this->fTexCoords[c - 32][2];
  399.  
  400.         fRowWidth += (tx2 - tx1) * this->dwTexWidth - 2 * this->dwSpacing;
  401.  
  402.         if (fRowWidth > fWidth)
  403.             fWidth = fRowWidth;
  404.     }
  405.  
  406.     pSize->cx = (int)fWidth;
  407.     pSize->cy = (int)fHeight;
  408.  
  409.     return S_OK;
  410. }
  411.  
  412.  
  413.  
  414.  
  415. //-----------------------------------------------------------------------------
  416. // Name: DrawStringScaled()
  417. // Desc: Draws scaled 2D text.  Note that x and y are in viewport coordinates
  418. //       (ranging from -1 to +1).  fXScale and fYScale are the size fraction
  419. //       relative to the entire viewport.  For example, a fXScale of 0.25 is
  420. //       1/8th of the screen width.  This allows you to output text at a fixed
  421. //       fraction of the viewport, even if the screen or window size changes.
  422. //-----------------------------------------------------------------------------
  423. HRESULT CD3DFont::DrawStringScaled(FLOAT x, FLOAT y, FLOAT fXScale, FLOAT fYScale, DWORD dwColor, const char* strText,
  424.     DWORD dwFlags)
  425. {
  426.     if (this->pd3dDevice == NULL)
  427.         return E_FAIL;
  428.  
  429.     // Set up renderstate
  430.     this->pStateBlockSaved->Capture();
  431.     this->pStateBlockDrawString->Apply();
  432.     this->pd3dDevice->SetFVF(D3DFVF_FONT2DVERTEX);
  433.     this->pd3dDevice->SetPixelShader(NULL);
  434.     this->pd3dDevice->SetStreamSource(0, this->pVB, 0, sizeof(FONT2DVERTEX));
  435.  
  436.     // Set filter states
  437.     if (dwFlags & CD3DFONT_FILTERED)
  438.     {
  439.         this->pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
  440.         this->pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
  441.     }
  442.  
  443.     D3DVIEWPORT9 vp;
  444.     this->pd3dDevice->GetViewport(&vp);
  445.     FLOAT fLineHeight = (this->fTexCoords[0][3] - this->fTexCoords[0][1]) * this->dwTexHeight;
  446.  
  447.     // Center the text block
  448.     if (dwFlags & CD3DFONT_CENTERED_X)
  449.     {
  450.         SIZE sz;
  451.         GetTextExtent(strText, &sz);
  452.         x = -(((FLOAT)sz.cx)) * 0.5f;
  453.         x = std::roundf(x);
  454.     }
  455.  
  456.     if (dwFlags & CD3DFONT_CENTERED_Y)
  457.     {
  458.         SIZE sz;
  459.         GetTextExtent(strText, &sz);
  460.         y = -(((FLOAT)sz.cy)) * 0.5f;
  461.         y = std::roundf(y);
  462.     }
  463.  
  464.     FLOAT sx = (x + 1.0f) * vp.Width / 2;
  465.     FLOAT sy = (y + 1.0f) * vp.Height / 2;
  466.  
  467.     // Adjust for character spacing
  468.     sx -= this->dwSpacing * (fXScale * vp.Height) / fLineHeight;
  469.     FLOAT fStartX = sx;
  470.  
  471.     // Fill vertex buffer
  472.     FONT2DVERTEX* pVertices;
  473.     DWORD         dwNumTriangles = 0L;
  474.     this->pVB->Lock(0, 0, (void**)&pVertices, D3DLOCK_DISCARD);
  475.  
  476.     while (*strText)
  477.     {
  478.         TCHAR c = *strText++;
  479.  
  480.         if (c == _T('\n'))
  481.         {
  482.             sx = fStartX;
  483.             sy += fYScale * vp.Height;
  484.         }
  485.  
  486.         if ((c - 32) < 0 || (c - 32) >= 128 - 32)
  487.             continue;
  488.  
  489.         FLOAT tx1 = this->fTexCoords[c - 32][0];
  490.         FLOAT ty1 = this->fTexCoords[c - 32][1];
  491.         FLOAT tx2 = this->fTexCoords[c - 32][2];
  492.         FLOAT ty2 = this->fTexCoords[c - 32][3];
  493.  
  494.         FLOAT w = (tx2 - tx1) * this->dwTexWidth;
  495.         FLOAT h = (ty2 - ty1) * this->dwTexHeight;
  496.  
  497.         w *= (fXScale * vp.Height) / fLineHeight;
  498.         h *= (fYScale * vp.Height) / fLineHeight;
  499.  
  500.         if (c != _T(' '))
  501.         {
  502.             if (dwFlags & CD3DFONT_DROPSHADOW)
  503.             {
  504.                 auto dropshadow_colour = D3DCOLOR_RGBA(1, 1, 1, get_a(dwColor));
  505.                 *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + 0 + 0.5f, sy + h + 0.5f, 1.0f, 1.0f), dropshadow_colour, tx1, ty2);
  506.                 *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + 0 + 0.5f, sy + 0 + 0.5f, 1.0f, 1.0f), dropshadow_colour, tx1, ty1);
  507.                 *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + w + 0.5f, sy + h + 0.5f, 1.0f, 1.0f), dropshadow_colour, tx2, ty2);
  508.                 *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + w + 0.5f, sy + 0 + 0.5f, 1.0f, 1.0f), dropshadow_colour, tx2, ty1);
  509.                 *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + w + 0.5f, sy + h + 0.5f, 1.0f, 1.0f), dropshadow_colour, tx2, ty2);
  510.                 *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + 0 + 0.5f, sy + 0 + 0.5f, 1.0f, 1.0f), dropshadow_colour, tx1, ty1);
  511.                 dwNumTriangles += 2;
  512.             }
  513.  
  514.             *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + 0 - 0.5f, sy + h - 0.5f, 1.0f, 1.0f), dwColor, tx1, ty2);
  515.             *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + 0 - 0.5f, sy + 0 - 0.5f, 1.0f, 1.0f), dwColor, tx1, ty1);
  516.             *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + w - 0.5f, sy + h - 0.5f, 1.0f, 1.0f), dwColor, tx2, ty2);
  517.             *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + w - 0.5f, sy + 0 - 0.5f, 1.0f, 1.0f), dwColor, tx2, ty1);
  518.             *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + w - 0.5f, sy + h - 0.5f, 1.0f, 1.0f), dwColor, tx2, ty2);
  519.             *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + 0 - 0.5f, sy + 0 - 0.5f, 1.0f, 1.0f), dwColor, tx1, ty1);
  520.             dwNumTriangles += 2;
  521.  
  522.             if (dwNumTriangles * 3 > (MAX_NUM_VERTICES - 6))
  523.             {
  524.                 // Unlock, render, and relock the vertex buffer
  525.                 this->pVB->Unlock();
  526.                 this->pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, dwNumTriangles);
  527.                 this->pVB->Lock(0, 0, (void**)&pVertices, D3DLOCK_DISCARD);
  528.                 dwNumTriangles = 0L;
  529.             }
  530.         }
  531.  
  532.         sx += w - (2 * this->dwSpacing) * (fXScale * vp.Height) / fLineHeight;
  533.     }
  534.  
  535.     // Unlock and render the vertex buffer
  536.     this->pVB->Unlock();
  537.     if (dwNumTriangles > 0)
  538.         this->pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, dwNumTriangles);
  539.  
  540.     // Restore the modified renderstates
  541.     this->pStateBlockSaved->Apply();
  542.  
  543.     return S_OK;
  544. }
  545.  
  546. //-----------------------------------------------------------------------------
  547. // Name: DrawString()
  548. // Desc: Draws 2D text. Note that sx and sy are in pixels
  549. //-----------------------------------------------------------------------------
  550. HRESULT CD3DFont::DrawString(FLOAT sx, FLOAT sy, DWORD dwColor, const char* strText, DWORD dwFlags)
  551. {
  552.     if (this->pd3dDevice == NULL)
  553.         return E_FAIL;
  554.  
  555.     // Setup renderstate
  556.     this->pStateBlockSaved->Capture();
  557.     this->pStateBlockDrawString->Apply();
  558.     this->pd3dDevice->SetFVF(D3DFVF_FONT2DVERTEX);
  559.     this->pd3dDevice->SetPixelShader(NULL);
  560.     this->pd3dDevice->SetStreamSource(0, this->pVB, 0, sizeof(FONT2DVERTEX));
  561.  
  562.     // Set filter states
  563.     if (dwFlags & CD3DFONT_FILTERED)
  564.     {
  565.         this->pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
  566.         this->pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
  567.     }
  568.  
  569.     // Center the text block
  570.     if (dwFlags & CD3DFONT_CENTERED_X)
  571.     {
  572.         SIZE sz;
  573.         GetTextExtent(strText, &sz);
  574.         sx -= (FLOAT)sz.cx * 0.5f;
  575.         sx = std::roundf(sx);
  576.     }
  577.  
  578.     if (dwFlags & CD3DFONT_CENTERED_Y)
  579.     {
  580.         SIZE sz;
  581.         GetTextExtent(strText, &sz);
  582.         sy -= (FLOAT)sz.cy * 0.5f;
  583.         sy = std::roundf(sy);
  584.     }
  585.  
  586.     // Adjust for character spacing
  587.     sx -= this->dwSpacing;
  588.     FLOAT fStartX = sx;
  589.  
  590.     // Fill vertex buffer
  591.     FONT2DVERTEX* pVertices = NULL;
  592.     DWORD         dwNumTriangles = 0;
  593.     this->pVB->Lock(0, 0, (void**)&pVertices, D3DLOCK_DISCARD);
  594.  
  595.     while (*strText)
  596.     {
  597.         TCHAR c = *strText++;
  598.  
  599.         if (c == _T('\n'))
  600.         {
  601.             sx = fStartX;
  602.             sy += (this->fTexCoords[0][3] - this->fTexCoords[0][1]) * this->dwTexHeight;
  603.         }
  604.  
  605.         if ((c - 32) < 0 || (c - 32) >= 128 - 32)
  606.             continue;
  607.  
  608.         FLOAT tx1 = this->fTexCoords[c - 32][0];
  609.         FLOAT ty1 = this->fTexCoords[c - 32][1];
  610.         FLOAT tx2 = this->fTexCoords[c - 32][2];
  611.         FLOAT ty2 = this->fTexCoords[c - 32][3];
  612.  
  613.         FLOAT w = (tx2 - tx1) * this->dwTexWidth / this->fTextScale;
  614.         FLOAT h = (ty2 - ty1) * this->dwTexHeight / this->fTextScale;
  615.  
  616.         if (c != _T(' '))
  617.         {
  618.             if (dwFlags & CD3DFONT_DROPSHADOW)
  619.             {
  620.                 auto dropshadow_colour = D3DCOLOR_RGBA(1, 1, 1, get_a(dwColor));
  621.                 *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + 0 + 0.5f, sy + h + 0.5f, 1.0f, 1.0f), dropshadow_colour, tx1, ty2);
  622.                 *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + 0 + 0.5f, sy + 0 + 0.5f, 1.0f, 1.0f), dropshadow_colour, tx1, ty1);
  623.                 *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + w + 0.5f, sy + h + 0.5f, 1.0f, 1.0f), dropshadow_colour, tx2, ty2);
  624.                 *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + w + 0.5f, sy + 0 + 0.5f, 1.0f, 1.0f), dropshadow_colour, tx2, ty1);
  625.                 *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + w + 0.5f, sy + h + 0.5f, 1.0f, 1.0f), dropshadow_colour, tx2, ty2);
  626.                 *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + 0 + 0.5f, sy + 0 + 0.5f, 1.0f, 1.0f), dropshadow_colour, tx1, ty1);
  627.                 dwNumTriangles += 2;
  628.             }
  629.  
  630.             *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + 0 - 0.5f, sy + h - 0.5f, 1.0f, 1.0f), dwColor, tx1, ty2);
  631.             *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + 0 - 0.5f, sy + 0 - 0.5f, 1.0f, 1.0f), dwColor, tx1, ty1);
  632.             *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + w - 0.5f, sy + h - 0.5f, 1.0f, 1.0f), dwColor, tx2, ty2);
  633.             *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + w - 0.5f, sy + 0 - 0.5f, 1.0f, 1.0f), dwColor, tx2, ty1);
  634.             *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + w - 0.5f, sy + h - 0.5f, 1.0f, 1.0f), dwColor, tx2, ty2);
  635.             *pVertices++ = InitFont2DVertex(D3DXVECTOR4(sx + 0 - 0.5f, sy + 0 - 0.5f, 1.0f, 1.0f), dwColor, tx1, ty1);
  636.             dwNumTriangles += 2;
  637.  
  638.             if (dwNumTriangles * 3 > (MAX_NUM_VERTICES - 6))
  639.             {
  640.                 // Unlock, render, and relock the vertex buffer
  641.                 if (pVB == nullptr)
  642.                     return false;
  643.  
  644.                 this->pVB->Unlock();
  645.                 this->pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, dwNumTriangles);
  646.                 pVertices = NULL;
  647.                 this->pVB->Lock(0, 0, (void**)&pVertices, D3DLOCK_DISCARD);
  648.                 dwNumTriangles = 0L;
  649.             }
  650.         }
  651.  
  652.         sx += w - (2 * this->dwSpacing);
  653.     }
  654.  
  655.     // Unlock and render the vertex buffer
  656.     this->pVB->Unlock();
  657.     if (dwNumTriangles > 0)
  658.         this->pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, dwNumTriangles);
  659.  
  660.     // Restore the modified renderstates
  661.     this->pStateBlockSaved->Apply();
  662.  
  663.     return S_OK;
  664. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement