DX9/DX11: Workaround the viewpoint/EFB creation issues in e.g. SMG2 on NVIDIA hardwar...
[dolphin.git] / Source / Plugins / Plugin_VideoDX9 / Src / D3DUtil.cpp
blob9cc2dd19bac1a530441d64285bf2e57c3f65ac1f
1 // Copyright (C) 2003 Dolphin Project.
3 // This program is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, version 2.0.
7 // This program is distributed in the hope that it will be useful,
8 // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 // GNU General Public License 2.0 for more details.
12 // A copy of the GPL 2.0 should have been included with the program.
13 // If not, see http://www.gnu.org/licenses/
15 // Official SVN repository and contact information can be found at
16 // http://code.google.com/p/dolphin-emu/
18 #include "Common.h"
19 #include "StringUtil.h"
21 #include "D3DBase.h"
22 #include "D3DUtil.h"
23 #include "Render.h"
25 namespace D3D
27 CD3DFont font;
29 #define MAX_NUM_VERTICES 50*6
30 struct FONT2DVERTEX {
31 float x,y,z;
32 float rhw;
33 u32 color;
34 float tu, tv;
37 #define D3DFVF_FONT2DVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1)
38 #define D3DFVF_FONT3DVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_NORMAL|D3DFVF_TEX1)
40 inline FONT2DVERTEX InitFont2DVertex(float x, float y, u32 color, float tu, float tv)
42 FONT2DVERTEX v; v.x=x; v.y=y; v.z=0; v.rhw=1.0f; v.color = color; v.tu = tu; v.tv = tv;
43 return v;
46 CD3DFont::CD3DFont()
48 m_pTexture = NULL;
49 m_pVB = NULL;
52 enum {m_dwTexWidth = 512, m_dwTexHeight = 512};
54 int CD3DFont::Init()
56 // Create vertex buffer for the letters
57 HRESULT hr;
58 if (FAILED(hr = dev->CreateVertexBuffer(MAX_NUM_VERTICES*sizeof(FONT2DVERTEX),
59 D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC, 0, D3DPOOL_DEFAULT, &m_pVB, NULL)))
61 return hr;
63 m_fTextScale = 1.0f; // Draw fonts into texture without scaling
65 // Prepare to create a bitmap
66 int *pBitmapBits;
67 BITMAPINFO bmi;
68 ZeroMemory(&bmi.bmiHeader, sizeof(BITMAPINFOHEADER));
69 bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
70 bmi.bmiHeader.biWidth = (int)m_dwTexWidth;
71 bmi.bmiHeader.biHeight = -(int)m_dwTexHeight;
72 bmi.bmiHeader.biPlanes = 1;
73 bmi.bmiHeader.biCompression = BI_RGB;
74 bmi.bmiHeader.biBitCount = 32;
76 // Create a DC and a bitmap for the font
77 HDC hDC = CreateCompatibleDC(NULL);
78 HBITMAP hbmBitmap = CreateDIBSection(hDC, &bmi, DIB_RGB_COLORS, (VOID**)&pBitmapBits, NULL, 0);
79 SetMapMode(hDC, MM_TEXT);
81 // Create a font. By specifying ANTIALIASED_QUALITY, we might get an
82 // antialiased font, but this is not guaranteed.
83 // We definitely don't want to get it cleartype'd, anyway.
84 int m_dwFontHeight = 24;
85 int nHeight = -MulDiv(m_dwFontHeight, int(GetDeviceCaps(hDC, LOGPIXELSY) * m_fTextScale), 72);
86 int dwBold = FW_NORMAL; ///FW_BOLD
87 HFONT hFont = CreateFont(nHeight, 0, 0, 0, dwBold, 0,
88 FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
89 CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY,
90 VARIABLE_PITCH, _T("Tahoma"));
91 if (NULL == hFont)
92 return E_FAIL;
94 HGDIOBJ hOldbmBitmap = SelectObject(hDC, hbmBitmap);
95 HGDIOBJ hOldFont = SelectObject(hDC, hFont);
97 // Set text properties
98 SetTextColor(hDC, 0xFFFFFF);
99 SetBkColor (hDC, 0);
100 SetTextAlign(hDC, TA_TOP);
102 // Loop through all printable character and output them to the bitmap..
103 // Meanwhile, keep track of the corresponding tex coords for each character.
104 int x = 0, y = 0;
105 char str[2] = "\0";
106 for (int c = 0; c < 127 - 32; c++)
108 str[0] = c + 32;
109 SIZE size;
110 GetTextExtentPoint32A(hDC, str, 1, &size);
111 if ((int)(x+size.cx+1) > m_dwTexWidth)
113 x = 0;
114 y += size.cy + 1;
117 ExtTextOutA(hDC, x+1, y+0, ETO_OPAQUE | ETO_CLIPPED, NULL, str, 1, NULL);
118 m_fTexCoords[c][0] = ((float)(x+0))/m_dwTexWidth;
119 m_fTexCoords[c][1] = ((float)(y+0))/m_dwTexHeight;
120 m_fTexCoords[c][2] = ((float)(x+0+size.cx))/m_dwTexWidth;
121 m_fTexCoords[c][3] = ((float)(y+0+size.cy))/m_dwTexHeight;
123 x += size.cx + 3; //3 to work around annoying ij conflict (part of the j ends up with the i)
126 // Create a new texture for the font
127 hr = dev->CreateTexture(m_dwTexWidth, m_dwTexHeight, 1, D3DUSAGE_DYNAMIC,
128 D3DFMT_A4R4G4B4, D3DPOOL_DEFAULT, &m_pTexture, NULL);
129 if (FAILED(hr))
131 PanicAlert("Failed to create font texture");
132 return hr;
135 // Lock the surface and write the alpha values for the set pixels
136 D3DLOCKED_RECT d3dlr;
137 m_pTexture->LockRect(0, &d3dlr, 0, D3DLOCK_DISCARD);
138 int bAlpha; // 4-bit measure of pixel intensity
140 for (y = 0; y < m_dwTexHeight; y++)
142 u16 *pDst16 = (u16*)((u8 *)d3dlr.pBits + y * d3dlr.Pitch);
143 for (x = 0; x < m_dwTexWidth; x++)
145 bAlpha = ((pBitmapBits[m_dwTexWidth * y + x] & 0xff) >> 4);
146 pDst16[x] = (bAlpha << 12) | 0x0fff;
150 // Done updating texture, so clean up used objects
151 m_pTexture->UnlockRect(0);
153 SelectObject(hDC, hOldbmBitmap);
154 DeleteObject(hbmBitmap);
156 SelectObject(hDC, hOldFont);
157 DeleteObject(hFont);
159 return S_OK;
162 int CD3DFont::Shutdown()
164 m_pVB->Release();
165 m_pVB = NULL;
166 m_pTexture->Release();
167 m_pTexture = NULL;
168 return S_OK;
172 const int RS[6][2] =
174 {D3DRS_ALPHABLENDENABLE, TRUE},
175 {D3DRS_SRCBLEND, D3DBLEND_SRCALPHA},
176 {D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA},
177 {D3DRS_CULLMODE, D3DCULL_NONE},
178 {D3DRS_ZENABLE, FALSE},
179 {D3DRS_FOGENABLE, FALSE},
181 const int TS[6][2] =
183 {D3DTSS_COLOROP, D3DTOP_MODULATE},
184 {D3DTSS_COLORARG1, D3DTA_TEXTURE},
185 {D3DTSS_COLORARG2, D3DTA_DIFFUSE },
186 {D3DTSS_ALPHAOP, D3DTOP_MODULATE },
187 {D3DTSS_ALPHAARG1, D3DTA_TEXTURE },
188 {D3DTSS_ALPHAARG2, D3DTA_DIFFUSE },
191 bool DXCheck( std::wstring& msg )
193 HINSTANCE hDll = LoadLibrary(StringFromFormat( _T("d3dx9_%d.dll"), D3DX_SDK_VERSION).c_str());
194 if( !hDll )
196 msg = _T("Please make sure that you have the latest version of DirectX correctly installed.");
197 return false;
198 } else
199 msg = _T("DirectX is up to date and ready to be used!");
200 FreeLibrary( hDll );
201 return true;
204 static LPDIRECT3DPIXELSHADER9 ps_old = NULL;
205 static LPDIRECT3DVERTEXSHADER9 vs_old = NULL;
207 void RestoreShaders()
209 D3D::SetTexture(0, 0);
210 D3D::RefreshVertexDeclaration();
211 D3D::RefreshPixelShader();
212 D3D::RefreshVertexShader();
215 void RestoreRenderStates()
217 RestoreShaders();
218 for (int i = 0; i < 6; i++)
220 D3D::RefreshRenderState((_D3DRENDERSTATETYPE)RS[i][0]);
221 D3D::RefreshTextureStageState(0, (_D3DTEXTURESTAGESTATETYPE)int(TS[i][0]));
225 void CD3DFont::SetRenderStates()
227 D3D::SetTexture(0, m_pTexture);
229 dev->SetPixelShader(0);
230 dev->SetVertexShader(0);
232 dev->SetFVF(D3DFVF_FONT2DVERTEX);
234 for (int i = 0; i < 6; i++)
236 D3D::ChangeRenderState((_D3DRENDERSTATETYPE)RS[i][0], RS[i][1]);
237 D3D::ChangeTextureStageState(0, (_D3DTEXTURESTAGESTATETYPE)int(TS[i][0]), TS[i][1]);
242 int CD3DFont::DrawTextScaled(float x, float y, float fXScale, float fYScale, float spacing, u32 dwColor, const char* strText, bool center)
244 if (!m_pVB)
245 return 0;
247 SetRenderStates();
248 dev->SetStreamSource(0, m_pVB, 0, sizeof(FONT2DVERTEX));
250 float vpWidth = 1;
251 float vpHeight = 1;
253 float sx = x*vpWidth-0.5f;
254 float sy = y*vpHeight-0.5f;
256 float fStartX = sx;
258 float invLineHeight = 1.0f / ((m_fTexCoords[0][3] - m_fTexCoords[0][1]) * m_dwTexHeight);
259 // Fill vertex buffer
260 FONT2DVERTEX* pVertices;
261 int dwNumTriangles = 0L;
262 m_pVB->Lock(0, 0, (void**)&pVertices, D3DLOCK_DISCARD);
264 const char *oldstrText=strText;
265 //First, let's measure the text
266 float tw=0;
267 float mx=0;
268 float maxx=0;
270 while (*strText)
272 char c = *strText++;
274 if (c == ('\n'))
275 mx = 0;
276 if (c < (' '))
277 continue;
279 float tx1 = m_fTexCoords[c-32][0];
280 float tx2 = m_fTexCoords[c-32][2];
282 float w = (tx2-tx1)*m_dwTexWidth;
283 w *= (fXScale*vpHeight)*invLineHeight;
284 mx += w + spacing*fXScale*vpWidth;
285 if (mx > maxx) maxx = mx;
288 float offset = -maxx/2;
289 strText = oldstrText;
290 //Then let's draw it
291 if (center)
293 sx+=offset;
294 fStartX+=offset;
297 float wScale = (fXScale*vpHeight)*invLineHeight;
298 float hScale = (fYScale*vpHeight)*invLineHeight;
300 while (*strText)
302 char c = *strText++;
304 if (c == ('\n'))
306 sx = fStartX;
307 sy += fYScale*vpHeight;
309 if (c < (' '))
310 continue;
312 c-=32;
313 float tx1 = m_fTexCoords[c][0];
314 float ty1 = m_fTexCoords[c][1];
315 float tx2 = m_fTexCoords[c][2];
316 float ty2 = m_fTexCoords[c][3];
318 float w = (tx2-tx1)*m_dwTexWidth;
319 float h = (ty2-ty1)*m_dwTexHeight;
321 w *= wScale;
322 h *= hScale;
324 FONT2DVERTEX v[6];
325 v[0] = InitFont2DVertex(sx, sy+h, dwColor, tx1, ty2);
326 v[1] = InitFont2DVertex(sx, sy, dwColor, tx1, ty1);
327 v[2] = InitFont2DVertex(sx+w, sy+h, dwColor, tx2, ty2);
328 v[3] = InitFont2DVertex(sx+w, sy, dwColor, tx2, ty1);
329 v[4] = v[2];
330 v[5] = v[1];
332 memcpy(pVertices, v, 6*sizeof(FONT2DVERTEX));
334 pVertices+=6;
335 dwNumTriangles += 2;
337 if (dwNumTriangles * 3 > (MAX_NUM_VERTICES - 6))
339 // Unlock, render, and relock the vertex buffer
340 m_pVB->Unlock();
341 dev->DrawPrimitive(D3DPT_TRIANGLELIST, 0, dwNumTriangles);
342 m_pVB->Lock(0, 0, (void**)&pVertices, D3DLOCK_DISCARD);
343 dwNumTriangles = 0;
346 sx += w + spacing*fXScale*vpWidth;
349 // Unlock and render the vertex buffer
350 m_pVB->Unlock();
351 if (dwNumTriangles > 0)
352 dev->DrawPrimitive(D3DPT_TRIANGLELIST, 0, dwNumTriangles);
353 RestoreRenderStates();
354 return S_OK;
357 void quad2d(float x1, float y1, float x2, float y2, u32 color, float u1, float v1, float u2, float v2)
359 struct Q2DVertex { float x,y,z,rhw;u32 color;float u,v,w,h; } coords[4] = {
360 {x1-0.5f, y1-0.5f, 0, 1, color, u1, v1},
361 {x2-0.5f, y1-0.5f, 0, 1, color, u2, v1},
362 {x2-0.5f, y2-0.5f, 0, 1, color, u2, v2},
363 {x1-0.5f, y2-0.5f, 0, 1, color, u1, v2},
365 dev->SetPixelShader(0);
366 dev->SetVertexShader(0);
367 dev->SetVertexDeclaration(NULL);
368 dev->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1);
369 dev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, coords, sizeof(Q2DVertex));
370 RestoreShaders();
373 void drawShadedTexQuad(IDirect3DTexture9 *texture,
374 const RECT *rSource,
375 int SourceWidth,
376 int SourceHeight,
377 int DestWidth,
378 int DestHeight,
379 IDirect3DPixelShader9 *PShader,
380 IDirect3DVertexShader9 *Vshader)
382 float sw = 1.0f /(float) SourceWidth;
383 float sh = 1.0f /(float) SourceHeight;
384 float dw = 1.0f /(float) DestWidth;
385 float dh = 1.0f /(float) DestHeight;
386 float u1=((float)rSource->left) * sw;
387 float u2=((float)rSource->right) * sw;
388 float v1=((float)rSource->top) * sh;
389 float v2=((float)rSource->bottom) * sh;
391 struct Q2DVertex { float x,y,z,rhw,u,v,w,h,L,T,R,B; } coords[4] = {
392 {-1.0f - dw,-1.0f + dh, 0.0f,1.0f, u1, v2, sw, sh,u1,v1,u2,v2},
393 {-1.0f - dw, 1.0f + dh, 0.0f,1.0f, u1, v1, sw, sh,u1,v1,u2,v2},
394 { 1.0f - dw,-1.0f + dh, 0.0f,1.0f, u2, v2, sw, sh,u1,v1,u2,v2},
395 { 1.0f - dw, 1.0f + dh, 0.0f,1.0f, u2, v1, sw, sh,u1,v1,u2,v2}
397 dev->SetVertexShader(Vshader);
398 dev->SetPixelShader(PShader);
399 D3D::SetTexture(0, texture);
400 dev->SetFVF(D3DFVF_XYZW | D3DFVF_TEX3 | D3DFVF_TEXCOORDSIZE4(2));
401 dev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, coords, sizeof(Q2DVertex));
402 RestoreShaders();
405 void drawShadedTexSubQuad(IDirect3DTexture9 *texture,
406 const MathUtil::Rectangle<float> *rSource,
407 int SourceWidth,
408 int SourceHeight,
409 const MathUtil::Rectangle<float> *rDest,
410 int DestWidth,
411 int DestHeight,
412 IDirect3DPixelShader9 *PShader,
413 IDirect3DVertexShader9 *Vshader)
415 float sw = 1.0f /(float) SourceWidth;
416 float sh = 1.0f /(float) SourceHeight;
417 float dw = 1.0f /(float) DestWidth;
418 float dh = 1.0f /(float) DestHeight;
419 float u1= rSource->left * sw;
420 float u2= rSource->right * sw;
421 float v1= rSource->top * sh;
422 float v2= rSource->bottom * sh;
424 struct Q2DVertex { float x,y,z,rhw,u,v,w,h,L,T,R,B; } coords[4] = {
425 { rDest->left - dw , rDest->top + dh, 1.0f,1.0f, u1, v2, sw, sh,u1,v1,u2,v2},
426 { rDest->left - dw , rDest->bottom + dh, 1.0f,1.0f, u1, v1, sw, sh,u1,v1,u2,v2},
427 { rDest->right - dw , rDest->top + dh, 1.0f,1.0f, u2, v2, sw, sh,u1,v1,u2,v2},
428 { rDest->right - dw , rDest->bottom + dh, 1.0f,1.0f, u2, v1, sw, sh,u1,v1,u2,v2}
430 dev->SetVertexShader(Vshader);
431 dev->SetPixelShader(PShader);
432 D3D::SetTexture(0, texture);
433 dev->SetFVF(D3DFVF_XYZW | D3DFVF_TEX3 | D3DFVF_TEXCOORDSIZE4(2));
434 dev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, coords, sizeof(Q2DVertex));
435 RestoreShaders();
438 void drawClearQuad(u32 Color,float z,IDirect3DPixelShader9 *PShader,IDirect3DVertexShader9 *Vshader)
440 struct Q2DVertex { float x,y,z,rhw;u32 color;} coords[4] = {
441 {-1.0f, 1.0f, z, 1.0f, Color},
442 { 1.0f, 1.0f, z, 1.0f, Color},
443 { 1.0f, -1.0f, z, 1.0f, Color},
444 {-1.0f, -1.0f, z, 1.0f, Color}
446 dev->SetVertexShader(Vshader);
447 dev->SetPixelShader(PShader);
448 dev->SetFVF(D3DFVF_XYZW | D3DFVF_DIFFUSE);
449 dev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, coords, sizeof(Q2DVertex));
450 RestoreShaders();
454 } // namespace