Clean up some text rendering to avoid relying on deprecated GL matrix state.

Use scissor instead of deprecated clip planes for GUI text.
Remove unused support for generic font names.

This was SVN commit r10985.
This commit is contained in:
Ykkrosh 2012-01-29 20:04:21 +00:00
parent 8be430eb30
commit 04c63a4093
13 changed files with 289 additions and 178 deletions

View File

@ -63,12 +63,6 @@ lodbias = 0
; Opt-in online user reporting system
userreport.url = "http://feedback.wildfiregames.com/report/upload/v1/"
; Font mappings:
font.console = console
font.default = palatino12
font.misc = verdana16
; Colour of the sky (in "r g b" format)
skycolor = "0 0 0"

View File

@ -0,0 +1,117 @@
/* Copyright (C) 2012 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.h"
#include "TextRenderer.h"
#include "lib/ogl.h"
#include "lib/res/graphics/unifont.h"
#include "ps/Font.h"
extern int g_yres;
CTextRenderer::CTextRenderer()
{
ResetTransform();
Color(CColor(1.0f, 1.0f, 1.0f, 1.0f));
Font(L"sans-10");
}
void CTextRenderer::ResetTransform()
{
m_Transform.SetIdentity();
m_Transform.Scale(1.0f, -1.f, 1.0f);
m_Transform.Translate(0.0f, (float)g_yres, -1000.0f);
}
CMatrix3D CTextRenderer::GetTransform()
{
return m_Transform;
}
void CTextRenderer::SetTransform(const CMatrix3D& transform)
{
m_Transform = transform;
}
void CTextRenderer::Translate(float x, float y, float z)
{
CMatrix3D m;
m.SetTranslation(x, y, z);
m_Transform = m_Transform * m;
}
void CTextRenderer::Color(CColor& color)
{
m_Color = color;
}
void CTextRenderer::Font(const CStrW& font)
{
if (!m_Fonts[font])
m_Fonts[font] = shared_ptr<CFont>(new CFont(font));
m_Font = m_Fonts[font];
}
void CTextRenderer::Printf(const wchar_t* fmt, ...)
{
wchar_t buf[1024] = {0};
va_list args;
va_start(args, fmt);
int ret = vswprintf(buf, ARRAY_SIZE(buf)-1, fmt, args);
va_end(args);
if (ret < 0)
{
debug_printf(L"glwprintf failed (buffer size exceeded?) - return value %d, errno %d\n", ret, errno);
}
SBatch batch;
batch.transform = m_Transform;
batch.color = m_Color;
batch.font = m_Font;
batch.text = buf;
m_Batches.push_back(batch);
int w, h;
batch.font->CalculateStringSize(batch.text, w, h);
Translate((float)w, 0.0f, 0.0f);
}
void CTextRenderer::Render()
{
for (size_t i = 0; i < m_Batches.size(); ++i)
{
SBatch& batch = m_Batches[i];
batch.font->Bind();
glPushMatrix();
glLoadMatrixf(&batch.transform._11);
glColor4fv(batch.color.FloatArray());
glwprintf(L"%ls", batch.text.c_str());
glPopMatrix();
}
m_Batches.clear();
}

View File

@ -0,0 +1,64 @@
/* Copyright (C) 2012 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* 0 A.D. is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_TEXTRENDERER
#define INCLUDED_TEXTRENDERER
#include "maths/Matrix3D.h"
#include "ps/CStr.h"
#include "ps/Overlay.h"
class CFont;
class CTextRenderer
{
public:
CTextRenderer();
void ResetTransform();
void Translate(float x, float y, float z);
CMatrix3D GetTransform();
void SetTransform(const CMatrix3D& transform);
void Color(CColor& color);
void Font(const CStrW& font);
void Printf(const wchar_t* fmt, ...);
void Render();
private:
struct SBatch
{
CMatrix3D transform;
CColor color;
shared_ptr<CFont> font;
std::wstring text;
};
CMatrix3D m_Transform;
CColor m_Color;
shared_ptr<CFont> m_Font;
std::map<CStrW, shared_ptr<CFont> > m_Fonts;
std::vector<SBatch> m_Batches;
};
#endif // INCLUDED_TEXTRENDERER

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2011 Wildfire Games.
/* Copyright (C) 2012 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -43,26 +43,26 @@ CGUI
#include "MiniMap.h"
#include "scripting/JSInterface_GUITypes.h"
#include "ps/XML/Xeromyces.h"
#include "ps/Font.h"
#include "ps/Pyrogenesis.h"
#include "graphics/TextRenderer.h"
#include "lib/input.h"
#include "lib/bits.h"
#include "lib/timer.h"
#include "lib/sysdep/sysdep.h"
// TODO Gee: Whatever include CRect/CPos/CSize
#include "ps/Overlay.h"
#include "ps/Profile.h"
#include "scripting/ScriptingHost.h"
#include "scriptinterface/ScriptInterface.h"
#include "ps/CLogger.h"
#include "ps/Filesystem.h"
#include "ps/Font.h"
#include "ps/Hotkey.h"
#include "ps/Globals.h"
#include "ps/Filesystem.h"
#include "ps/Overlay.h"
#include "ps/Profile.h"
#include "ps/Pyrogenesis.h"
#include "ps/XML/Xeromyces.h"
#include "scripting/ScriptingHost.h"
#include "scriptinterface/ScriptInterface.h"
extern int g_yres;
const double SELECT_DBLCLICK_RATE = 0.5;
#include "ps/CLogger.h"
void CGUI::ScriptingInit()
{
@ -443,9 +443,6 @@ void CGUI::Draw()
// Clear the depth buffer, so the GUI is
// drawn on top of everything else
glClear(GL_DEPTH_BUFFER_BIT);
glPushMatrix();
guiLoadIdentity();
try
{
@ -457,7 +454,6 @@ void CGUI::Draw()
{
LOGERROR(L"GUI draw error: %hs", e.what());
}
glPopMatrix();
}
void CGUI::DrawSprite(const CGUISpriteInstance& Sprite,
@ -472,13 +468,7 @@ void CGUI::DrawSprite(const CGUISpriteInstance& Sprite,
// TODO: Clipping?
glPushMatrix();
glTranslatef(0.0f, 0.0f, Z);
Sprite.Draw(Rect, CellID, m_Sprites);
glPopMatrix();
Sprite.Draw(Rect, CellID, m_Sprites, Z);
}
void CGUI::Destroy()
@ -927,23 +917,11 @@ void CGUI::DrawText(SGUIText &Text, const CColor &DefaultColor,
if (clipping != CRect())
{
double eq[4][4] =
{
{ 0.0, 1.0, 0.0, -clipping.top },
{ 1.0, 0.0, 0.0, -clipping.left },
{ 0.0, -1.0, 0.0, clipping.bottom },
{ -1.0, 0.0, 0.0, clipping.right }
};
for (int i=0; i<4; ++i)
{
glClipPlane(GL_CLIP_PLANE0+i, eq[i]);
glEnable(GL_CLIP_PLANE0+i);
}
glEnable(GL_SCISSOR_TEST);
glScissor(clipping.left, g_yres - clipping.bottom, clipping.GetWidth(), clipping.GetHeight());
}
CFont* font = NULL;
CStrW LastFontName;
CTextRenderer textRenderer;
for (std::vector<SGUIText::STextCall>::const_iterator it = Text.m_TextCalls.begin();
it != Text.m_TextCalls.end();
@ -953,30 +931,16 @@ void CGUI::DrawText(SGUIText &Text, const CColor &DefaultColor,
if (it->m_pSpriteCall)
continue;
// Switch fonts when necessary, but remember the last one used
if (it->m_Font != LastFontName)
{
delete font;
font = new CFont(it->m_Font);
font->Bind();
LastFontName = it->m_Font;
}
CColor color = it->m_UseCustomColor ? it->m_Color : DefaultColor;
glPushMatrix();
// TODO Gee: (2004-09-04) Why are font corrupted if inputted float value?
glTranslatef((GLfloat)int(pos.x+it->m_Pos.x), (GLfloat)int(pos.y+it->m_Pos.y), z);
glColor4fv(color.FloatArray());
glwprintf(L"%ls", it->m_String.c_str()); // "%ls" is necessary in case m_String contains % symbols
glPopMatrix();
textRenderer.ResetTransform();
textRenderer.Translate((float)(int)(pos.x+it->m_Pos.x), (float)(int)(pos.y+it->m_Pos.y), z);
textRenderer.Color(color);
textRenderer.Font(it->m_Font);
textRenderer.Printf(L"%ls", it->m_String.c_str()); // "%ls" is necessary in case m_String contains % symbols
}
if (font)
delete font;
textRenderer.Render();
for (std::list<SGUIText::SSpriteCall>::iterator it=Text.m_SpriteCalls.begin();
it!=Text.m_SpriteCalls.end();
@ -985,15 +949,10 @@ void CGUI::DrawText(SGUIText &Text, const CColor &DefaultColor,
DrawSprite(it->m_Sprite, it->m_CellID, z, it->m_Area + pos);
}
// TODO To whom it may concern: Thing were not reset, so
// I added this line, modify if incorrect --
if (clipping != CRect())
{
for (int i=0; i<4; ++i)
glDisable(GL_CLIP_PLANE0+i);
}
glDisable(GL_SCISSOR_TEST);
glDisable(GL_TEXTURE_2D);
// -- GL
}
bool CGUI::GetPreDefinedColor(const CStr& name, CColor &Output)

View File

@ -18,7 +18,7 @@
#include "precompiled.h"
#include "CGUISprite.h"
void CGUISpriteInstance::Draw(CRect Size, int CellID, std::map<CStr, CGUISprite> &Sprites) const
void CGUISpriteInstance::Draw(CRect Size, int CellID, std::map<CStr, CGUISprite> &Sprites, float Z) const
{
if (m_CachedSize != Size || m_CachedCellID != CellID)
{
@ -26,7 +26,7 @@ void CGUISpriteInstance::Draw(CRect Size, int CellID, std::map<CStr, CGUISprite>
m_CachedSize = Size;
m_CachedCellID = CellID;
}
GUIRenderer::Draw(m_DrawCallCache);
GUIRenderer::Draw(m_DrawCallCache, Z);
}
void CGUISpriteInstance::Invalidate()

View File

@ -177,7 +177,7 @@ public:
CGUISpriteInstance(const CStr& SpriteName);
CGUISpriteInstance(const CGUISpriteInstance &Sprite);
CGUISpriteInstance &operator=(const CStr& SpriteName);
void Draw(CRect Size, int CellID, std::map<CStr, CGUISprite> &Sprites) const;
void Draw(CRect Size, int CellID, std::map<CStr, CGUISprite> &Sprites, float Z) const;
void Invalidate();
bool IsEmpty() const;
const CStr& GetName() { return m_SpriteName; }

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2010 Wildfire Games.
/* Copyright (C) 2012 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -24,18 +24,19 @@ CInput
#include "CInput.h"
#include "CGUIScrollBarVertical.h"
#include "ps/Font.h"
#include "graphics/TextRenderer.h"
#include "lib/ogl.h"
#include "lib/res/graphics/unifont.h"
#include "lib/sysdep/clipboard.h"
#include "ps/Hotkey.h"
#include "ps/CLogger.h"
#include "ps/Font.h"
#include "ps/Globals.h"
#include "ps/Hotkey.h"
#include <sstream>
extern int g_yres;
//-------------------------------------------------------------------
// Constructor / Destructor
//-------------------------------------------------------------------
@ -1031,20 +1032,9 @@ void CInput::Draw()
scroll = GetScrollBar(0).GetPos();
}
glEnable(GL_TEXTURE_2D);
glDisable(GL_CULL_FACE);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
glDisable(GL_ALPHA_TEST);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
CFont font(font_name);
font.Bind();
glPushMatrix();
// We'll have to setup clipping manually, since we're doing the rendering manually.
CRect cliparea(m_CachedActualSize);
@ -1066,19 +1056,8 @@ void CInput::Draw()
if (cliparea != CRect())
{
double eq[4][4] =
{
{ 0.0, 1.0, 0.0, -cliparea.top },
{ 1.0, 0.0, 0.0, -cliparea.left },
{ 0.0, -1.0, 0.0, cliparea.bottom },
{ -1.0, 0.0, 0.0, cliparea.right }
};
for (int i=0; i<4; ++i)
{
glClipPlane(GL_CLIP_PLANE0+i, eq[i]);
glEnable(GL_CLIP_PLANE0+i);
}
glEnable(GL_SCISSOR_TEST);
glScissor(cliparea.left, g_yres - cliparea.bottom, cliparea.GetWidth(), cliparea.GetHeight());
}
// These are useful later.
@ -1099,12 +1078,15 @@ void CInput::Draw()
float h = (float)font.GetHeight();
float ls = (float)font.GetLineSpacing();
CTextRenderer textRenderer;
textRenderer.Font(font_name);
// Set the Z to somewhat more, so we can draw a selected area between the
// the control and the text.
glTranslatef((GLfloat)int(m_CachedActualSize.left) + buffer_zone,
(GLfloat)int(m_CachedActualSize.top+h) + buffer_zone, bz+0.1f);
//glColor4f(1.f, 1.f, 1.f, 1.f);
textRenderer.Translate(
(float)(int)(m_CachedActualSize.left) + buffer_zone,
(float)(int)(m_CachedActualSize.top+h) + buffer_zone,
bz+0.1f);
// U+FE33: PRESENTATION FORM FOR VERTICAL LOW LINE
// (sort of like a | which is aligned to the left of most characters)
@ -1234,20 +1216,8 @@ void CInput::Draw()
rect.right = m_CachedActualSize.right;
}
glPushMatrix();
guiLoadIdentity();
glEnable(GL_BLEND);
glDisable(GL_TEXTURE_2D);
if (sprite_selectarea)
GetGUI()->DrawSprite(*sprite_selectarea, cell_id, bz+0.05f, rect);
// Blend can have been reset
glEnable(GL_BLEND);
glEnable(GL_TEXTURE_2D);
glDisable(GL_ALPHA_TEST);
glPopMatrix();
}
if (i < (int)it->m_ListOfX.size())
@ -1271,7 +1241,15 @@ void CInput::Draw()
buffered_y = -scroll;
// Setup initial color (then it might change and change back, when drawing selected area)
glColor4f(color.r, color.g, color.b, color.a);
textRenderer.Color(color);
// Setup state for text rendering
glEnable(GL_TEXTURE_2D);
glDisable(GL_CULL_FACE);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
bool using_selected_color = false;
@ -1287,13 +1265,13 @@ void CInput::Draw()
break;
}
glPushMatrix();
CMatrix3D savedTransform = textRenderer.GetTransform();
// Text must always be drawn in integer values. So we have to convert scroll
if (multiline)
glTranslatef(0.f, -(float)(int)scroll, 0.f);
textRenderer.Translate(0.f, -(float)(int)scroll, 0.f);
else
glTranslatef(-(float)(int)m_HorizontalScroll, 0.f, 0.f);
textRenderer.Translate(-(float)(int)m_HorizontalScroll, 0.f, 0.f);
// We might as well use 'i' here, because we need it
// (often compared against ints, so don't make it size_t)
@ -1305,9 +1283,9 @@ void CInput::Draw()
{
// We still need to translate the OpenGL matrix
if (i == 0)
glTranslatef(it->m_ListOfX[i], 0.f, 0.f);
textRenderer.Translate(it->m_ListOfX[i], 0.f, 0.f);
else
glTranslatef(it->m_ListOfX[i] - it->m_ListOfX[i-1], 0.f, 0.f);
textRenderer.Translate(it->m_ListOfX[i] - it->m_ListOfX[i-1], 0.f, 0.f);
continue;
}
@ -1318,16 +1296,16 @@ void CInput::Draw()
it->m_ListStart + i == VirtualTo)
{
using_selected_color = false;
glColor4f(color.r, color.g, color.b, color.a);
textRenderer.Color(color);
}
if (i != (int)it->m_ListOfX.size() &&
it->m_ListStart + i == m_iBufferPos)
{
// selecting only one, then we need only to draw a cursor.
glPushMatrix();
glwprintf(L"_");
glPopMatrix();
CMatrix3D t = textRenderer.GetTransform();
textRenderer.Printf(L"_");
textRenderer.SetTransform(t);
}
// Drawing selected area
@ -1337,11 +1315,11 @@ void CInput::Draw()
using_selected_color == false)
{
using_selected_color = true;
glColor4f(color_selected.r, color_selected.g, color_selected.b, color_selected.a);
textRenderer.Color(color_selected);
}
if (i != (int)it->m_ListOfX.size())
glwprintf(L"%lc", (*pCaption)[it->m_ListStart + i]);
textRenderer.Printf(L"%lc", (*pCaption)[it->m_ListStart + i]);
// check it's now outside a one-liner, then we'll break
if (!multiline && i < (int)it->m_ListOfX.size())
@ -1353,25 +1331,26 @@ void CInput::Draw()
if (it->m_ListStart + (int)it->m_ListOfX.size() == m_iBufferPos)
{
glColor4f(color.r, color.g, color.b, color.a);
glwprintf(L"_");
textRenderer.Color(color);
textRenderer.Printf(L"_");
if (using_selected_color)
{
glColor4f(color_selected.r, color_selected.g, color_selected.b, color_selected.a);
textRenderer.Color(color_selected);
}
}
glPopMatrix();
textRenderer.SetTransform(savedTransform);
}
glTranslatef(0.f, ls, 0.f);
textRenderer.Translate(0.f, ls, 0.f);
}
glPopMatrix();
textRenderer.Render();
if (cliparea != CRect())
glDisable(GL_SCISSOR_TEST);
// Disable clipping
for (int i=0; i<4; ++i)
glDisable(GL_CLIP_PLANE0+i);
glDisable(GL_TEXTURE_2D);
}
}

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2011 Wildfire Games.
/* Copyright (C) 2012 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -367,7 +367,7 @@ void GUIRenderer::UpdateDrawCallCache(DrawCalls &Calls, const CStr& SpriteName,
// If this object has zero size, there's nothing to render. (This happens
// with e.g. tooltips that have zero size before they're first drawn, so
// it isn't necessarily an error.)
if (Size.left==Size.right && Size.top==Size.bottom)
if (Size.left == Size.right && Size.top == Size.bottom)
return;
@ -594,10 +594,15 @@ CRect SDrawCall::ComputeTexCoords() const
return TexCoords;
}
void GUIRenderer::Draw(DrawCalls &Calls)
void GUIRenderer::Draw(DrawCalls &Calls, float Z)
{
// Called every frame, to draw the object (based on cached calculations)
glPushMatrix();
CMatrix3D matrix = GetDefaultGuiMatrix();
matrix.Translate(0, 0, Z);
glLoadMatrixf(&matrix._11);
glDisable(GL_BLEND);
// Set LOD bias so mipmapped textures are prettier
@ -682,4 +687,6 @@ void GUIRenderer::Draw(DrawCalls &Calls)
}
glTexEnvf(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, 0.f);
glPopMatrix();
}

View File

@ -79,7 +79,7 @@ namespace GUIRenderer
{
void UpdateDrawCallCache(DrawCalls &Calls, const CStr& SpriteName, const CRect& Size, int CellID, std::map<CStr, CGUISprite> &Sprites);
void Draw(DrawCalls &Calls);
void Draw(DrawCalls &Calls, float Z);
}
#endif // GUIRenderer_h

View File

@ -22,6 +22,7 @@ GUI utilities
#include "precompiled.h"
#include "GUI.h"
#include "GUIManager.h"
#include "maths/Matrix3D.h"
#include "ps/Parser.h"
extern int g_yres;
@ -249,11 +250,13 @@ bool __ParseString<CGUIList>(const CStrW& UNUSED(Value), CGUIList& UNUSED(Output
//--------------------------------------------------------
void guiLoadIdentity()
CMatrix3D GetDefaultGuiMatrix()
{
glLoadIdentity();
glTranslatef(0.0f, (GLfloat)g_yres, -1000.0f);
glScalef(1.0f, -1.f, 1.0f);
CMatrix3D m;
m.SetIdentity();
m.Scale(1.0f, -1.f, 1.0f);
m.Translate(0.0f, (float)g_yres, -1000.0f);
return m;
}
//--------------------------------------------------------

View File

@ -50,14 +50,13 @@ GUI util
class CClientArea;
class CGUIString;
class CMatrix3D;
template <typename T>
bool __ParseString(const CStrW& Value, T &tOutput);
// Load Identity matrix and
// adapt (origio) to being in top left corner and down
// just like the mouse position
void guiLoadIdentity();
// Matrix with (0,0) in top-left of screen
CMatrix3D GetDefaultGuiMatrix();
//--------------------------------------------------------
// Forward declarations

View File

@ -299,6 +299,10 @@ void CMiniMap::Draw()
RebuildTerrainTexture();
}
glPushMatrix();
CMatrix3D matrix = GetDefaultGuiMatrix();
glLoadMatrixf(&matrix._11);
const float x = m_CachedActualSize.left, y = m_CachedActualSize.bottom;
const float x2 = m_CachedActualSize.right, y2 = m_CachedActualSize.top;
const float z = GetBufferedZ();
@ -417,6 +421,8 @@ void CMiniMap::Draw()
glPopMatrix();
glPopMatrix();
// Reset everything back to normal
glPointSize(1.0f);
glEnable(GL_TEXTURE_2D);

View File

@ -31,33 +31,16 @@ const wchar_t* DefaultFont = L"sans-10";
CFont::CFont(const CStrW& name)
{
// TODO perhaps: cache the resultant filename (or Handle) for each
// font name; but it's nice to allow run-time alteration of the fonts
h = unifont_load(g_VFS, name);
std::string fontFilename;
// Found it
if (h > 0)
return;
CStr fontName = "font." + name.ToUTF8();
// See if the config value can be loaded
CConfigValue* fontFilenameVar = g_ConfigDB.GetValue(CFG_USER, fontName);
if (fontFilenameVar && fontFilenameVar->GetString(fontFilename))
{
h = unifont_load(g_VFS, CStr(fontFilename).FromUTF8());
}
else
{
// Not found in the config file -- try it as a simple filename
h = unifont_load(g_VFS, name);
// Found it
if (h > 0)
return;
// Not found as a font -- give up and use the default.
LOGERROR(L"Failed to find font '%ls'", name.c_str());
h = unifont_load(g_VFS, DefaultFont);
// Assume this worked
}
// Not found as a font -- give up and use the default.
LOGERROR(L"Failed to find font '%ls'", name.c_str());
h = unifont_load(g_VFS, DefaultFont);
// Assume this worked
}
CFont::~CFont()