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/
19 #include "StringUtil.h"
29 #define MAX_NUM_VERTICES 50*6
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
;
52 enum {m_dwTexWidth
= 512, m_dwTexHeight
= 512};
56 // Create vertex buffer for the letters
58 if (FAILED(hr
= dev
->CreateVertexBuffer(MAX_NUM_VERTICES
*sizeof(FONT2DVERTEX
),
59 D3DUSAGE_WRITEONLY
| D3DUSAGE_DYNAMIC
, 0, D3DPOOL_DEFAULT
, &m_pVB
, NULL
)))
63 m_fTextScale
= 1.0f
; // Draw fonts into texture without scaling
65 // Prepare to create a bitmap
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"));
94 HGDIOBJ hOldbmBitmap
= SelectObject(hDC
, hbmBitmap
);
95 HGDIOBJ hOldFont
= SelectObject(hDC
, hFont
);
97 // Set text properties
98 SetTextColor(hDC
, 0xFFFFFF);
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.
106 for (int c
= 0; c
< 127 - 32; c
++)
110 GetTextExtentPoint32A(hDC
, str
, 1, &size
);
111 if ((int)(x
+size
.cx
+1) > m_dwTexWidth
)
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
);
131 PanicAlert("Failed to create font texture");
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
);
162 int CD3DFont::Shutdown()
166 m_pTexture
->Release();
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
},
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());
196 msg
= _T("Please make sure that you have the latest version of DirectX correctly installed.");
199 msg
= _T("DirectX is up to date and ready to be used!");
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()
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
)
248 dev
->SetStreamSource(0, m_pVB
, 0, sizeof(FONT2DVERTEX
));
253 float sx
= x
*vpWidth
-0.5f
;
254 float sy
= y
*vpHeight
-0.5f
;
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
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
;
297 float wScale
= (fXScale
*vpHeight
)*invLineHeight
;
298 float hScale
= (fYScale
*vpHeight
)*invLineHeight
;
307 sy
+= fYScale
*vpHeight
;
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
;
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
);
332 memcpy(pVertices
, v
, 6*sizeof(FONT2DVERTEX
));
337 if (dwNumTriangles
* 3 > (MAX_NUM_VERTICES
- 6))
339 // Unlock, render, and relock the vertex buffer
341 dev
->DrawPrimitive(D3DPT_TRIANGLELIST
, 0, dwNumTriangles
);
342 m_pVB
->Lock(0, 0, (void**)&pVertices
, D3DLOCK_DISCARD
);
346 sx
+= w
+ spacing
*fXScale
*vpWidth
;
349 // Unlock and render the vertex buffer
351 if (dwNumTriangles
> 0)
352 dev
->DrawPrimitive(D3DPT_TRIANGLELIST
, 0, dwNumTriangles
);
353 RestoreRenderStates();
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
));
373 void drawShadedTexQuad(IDirect3DTexture9
*texture
,
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
));
405 void drawShadedTexSubQuad(IDirect3DTexture9
*texture
,
406 const MathUtil::Rectangle
<float> *rSource
,
409 const MathUtil::Rectangle
<float> *rDest
,
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
));
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
));