1
0
forked from mirrors/0ad

Font builder code

This was SVN commit r527.
This commit is contained in:
Ykkrosh
2004-06-17 19:32:04 +00:00
parent fd91c74a23
commit b65d35ea2e
27 changed files with 2741 additions and 0 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

+76
View File
@@ -0,0 +1,76 @@
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#define APSTUDIO_HIDDEN_SYMBOLS
#include "windows.h"
#undef APSTUDIO_HIDDEN_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
/////////////////////////////////////////////////////////////////////////////
//
// Icon
//
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_ICON1 ICON "FontBuilder.ico"
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#define APSTUDIO_HIDDEN_SYMBOLS\r\n"
"#include ""windows.h""\r\n"
"#undef APSTUDIO_HIDDEN_SYMBOLS\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED
+30
View File
@@ -0,0 +1,30 @@
Microsoft Visual Studio Solution File, Format Version 8.00
Project("{EAF909A5-FA59-4C3D-9431-0FCC20D5BCF9}") = "FontBuilder", "FontBuilder.icproj", "{CFCF18FF-C3A4-4E76-BFA1-C5DB476E4687}"
ProjectSection(ProjectDependencies) = postProject
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfiguration) = preSolution
Debug = Debug
OldRelease = OldRelease
Release = Release
EndGlobalSection
GlobalSection(ProjectConfiguration) = postSolution
{CFCF18FF-C3A4-4E76-BFA1-C5DB476E4687}.Debug.ActiveCfg = Debug|Win32
{CFCF18FF-C3A4-4E76-BFA1-C5DB476E4687}.Debug.Build.0 = Debug|Win32
{CFCF18FF-C3A4-4E76-BFA1-C5DB476E4687}.OldRelease.ActiveCfg = Release|Win32
{CFCF18FF-C3A4-4E76-BFA1-C5DB476E4687}.OldRelease.Build.0 = Release|Win32
{CFCF18FF-C3A4-4E76-BFA1-C5DB476E4687}.Release.ActiveCfg = Release|Win32
{CFCF18FF-C3A4-4E76-BFA1-C5DB476E4687}.Release.Build.0 = Release|Win32
{277A0C35-0B44-48FC-81FD-119AD97194EA}.Release.Build.0 = Release|Win32
{277A0C35-0B44-48FC-81FD-119AD97194EA}.Release.ActiveCfg = Release|Win32
{277A0C35-0B44-48FC-81FD-119AD97194EA}.OldRelease.Build.0 = Release|Win32
{277A0C35-0B44-48FC-81FD-119AD97194EA}.OldRelease.ActiveCfg = Release|Win32
{277A0C35-0B44-48FC-81FD-119AD97194EA}.Debug.Build.0 = Debug|Win32
{277A0C35-0B44-48FC-81FD-119AD97194EA}.Debug.ActiveCfg = Debug|Win32
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
EndGlobalSection
GlobalSection(ExtensibilityAddIns) = postSolution
EndGlobalSection
EndGlobal
+262
View File
@@ -0,0 +1,262 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.10"
Name="FontBuilder"
OwnerKey="{EAF909A5-FA59-4C3D-9431-0FCC20D5BCF9}"
ProjectGUID="{277A0C35-0B44-48FC-81FD-119AD97194EA}"
RootNamespace="FontBuilder"
Keyword="Win32Proj">
<Platforms>
<Platform
Name="Win32"/>
</Platforms>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="Debug"
IntermediateDirectory="Debug"
ConfigurationType="1"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="&quot;E:\wx\wxWindows-2.4.2\include&quot;;&quot;E:\wx\wxWindows-2.4.2\lib\mswud&quot;;&quot;E:\freetype\freetype-2.1.8\include&quot;;E:\wx\pretends"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;__WXDEBUG__;_UNICODE;UNICODE;wxUSE_UNICODE=1"
MinimalRebuild="TRUE"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
BufferSecurityCheck="TRUE"
EnableFunctionLevelLinking="TRUE"
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="3"
WarningLevel="4"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="wxmswud.lib freetype218MT_D.lib comctl32.lib ws2_32.lib rpcrt4.lib"
OutputFile="$(OutDir)/FontBuilder.exe"
LinkIncremental="2"
SuppressStartupBanner="TRUE"
AdditionalLibraryDirectories="&quot;E:\wx\wxWindows-2.4.2\lib&quot;;&quot;E:\freetype\freetype-2.1.8\objs&quot;"
GenerateDebugInformation="TRUE"
ProgramDatabaseFile="$(OutDir)/FontBuilder.pdb"
SubSystem="2"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="Release"
IntermediateDirectory="Release"
ConfigurationType="1"
CharacterSet="2"
WholeProgramOptimization="FALSE">
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="-Qinline_debug_info "
Optimization="1"
GlobalOptimizations="FALSE"
InlineFunctionExpansion="1"
EnableIntrinsicFunctions="FALSE"
FavorSizeOrSpeed="2"
OmitFramePointers="FALSE"
EnableFiberSafeOptimizations="FALSE"
OptimizeForProcessor="2"
OptimizeForWindowsApplication="FALSE"
AdditionalIncludeDirectories="E:\wx\wxWindows-2.4.2\include;E:\wx\wxWindows-2.4.2\lib\mswu;E:\freetype\freetype-2.1.8\include"
PreprocessorDefinitions="_STATIC_CPPLIB;WIN32;NDEBUG;_WINDOWS;_UNICODE;UNICODE;wxUSE_UNICODE=1"
StringPooling="TRUE"
RuntimeLibrary="2"
StructMemberAlignment="0"
BufferSecurityCheck="FALSE"
EnableEnhancedInstructionSet="0"
ForceConformanceInForLoopScope="TRUE"
UsePrecompiledHeader="3"
WarningLevel="4"
Detect64BitPortabilityProblems="FALSE"
DebugInformationFormat="3"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="wxmswu.lib freetype218MT.lib comctl32.lib ws2_32.lib rpcrt4.lib"
OutputFile="$(OutDir)/FontBuilder.exe"
LinkIncremental="1"
SuppressStartupBanner="TRUE"
AdditionalLibraryDirectories="E:\wx\wxWindows-2.4.2\lib;E:\freetype\freetype-2.1.8\objs;e:\icc80\compiler80\ia32\lib"
IgnoreDefaultLibraryNames="libmmd"
GenerateDebugInformation="FALSE"
SubSystem="2"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"
CommandLine="rem upx --best $(TargetPath)"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
<File
RelativePath=".\filemanip.cpp">
</File>
<File
RelativePath=".\font.cpp">
</File>
<File
RelativePath=".\imagemanip.cpp">
</File>
<File
RelativePath=".\packer.cpp">
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool"
Optimization="2"
InlineFunctionExpansion="2"
EnableIntrinsicFunctions="TRUE"
FavorSizeOrSpeed="1"
OmitFramePointers="TRUE"/>
</FileConfiguration>
</File>
<File
RelativePath=".\stdafx.cpp">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"/>
</FileConfiguration>
</File>
<File
RelativePath=".\wxapp.cpp">
</File>
<File
RelativePath=".\wxconfig.cpp">
</File>
<File
RelativePath=".\wxframe.cpp">
</File>
<Filter
Name="platform"
Filter="">
<File
RelativePath=".\platform\msw\fontselect.cpp">
</File>
</Filter>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
<File
RelativePath=".\filemanip.h">
</File>
<File
RelativePath=".\font.h">
</File>
<File
RelativePath=".\imagemanip.h">
</File>
<File
RelativePath=".\packer.h">
</File>
<File
RelativePath=".\Resource.h">
</File>
<File
RelativePath=".\stdafx.h">
</File>
<File
RelativePath=".\wxconfig.h">
</File>
<File
RelativePath=".\wxframe.h">
</File>
<File
RelativePath=".\wxspinner.h">
</File>
<Filter
Name="platform"
Filter="">
<File
RelativePath=".\platform\fontselect.h">
</File>
</Filter>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
<File
RelativePath=".\FontBuilder.ico">
</File>
<File
RelativePath=".\FontBuilder.rc">
</File>
</Filter>
<File
RelativePath=".\fileformat.txt">
</File>
<File
RelativePath=".\readme.html">
</File>
<File
RelativePath=".\todo.txt">
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>
+41
View File
@@ -0,0 +1,41 @@
$Id: fileformat.txt,v 1.1 2004/06/17 19:32:04 philip Exp $
Fonts consist of
fontname.fnt
fontname.tga
and you load fonts by just specifying the "path/fontname" part.
The .tga is an 8-bit greyscale image, used for alpha-blending the text.
(DXTC allows 0.5 bytes/pixel at best, which isn't much better than
TGA's 1 byte/pixel, and DXTC's lossiness is almost noticeable.)
The .fnt file is something like:
100
512 256
3
16
32 0 0 10 10 12
33 10 0 6 10 7
3300 16 0 6 10 7
First line = version number of file, for slightly better error
detection if people leave old ones hanging around.
Second line = size of texture (width/height).
Third line = number of glyphs in the font.
Fourth line = line spacing (pixels between each baseline)
Each subsequent line is
<code point> <x> <y> <width> <height> <x offset> <y offset> <advance>
0 <= Code point < 2^16.
x, y, width, height are in pixels on the texture.
x/y offset are the position of the texture relative to the glyph's origin.
advance is the number of pixels to move along for the next character.
Currently no support for kerning.
+126
View File
@@ -0,0 +1,126 @@
// $Id: filemanip.cpp,v 1.1 2004/06/17 19:32:04 philip Exp $
#include "stdafx.h"
#include "filemanip.h"
// Ensure there's no padding added into the struct,
// in a very non-portable way
#pragma pack(push)
#pragma pack(1)
// For gcc, use "} TGA_HEADER __attribute__ ((packed));" instead of this
typedef struct
{
char identsize; // size of ID field that follows 18 byte header (0 usually)
char colourmaptype; // type of colour map 0=none, 1=has palette
char imagetype; // type of image 0=none,1=indexed,2=rgb,3=grey,+8=rle packed
short colourmapstart; // first colour map entry in palette
short colourmaplength; // number of colours in palette
char colourmapbits; // number of bits per palette entry 15,16,24,32
short xstart; // image x origin
short ystart; // image y origin
short width; // image width in pixels
short height; // image height in pixels
char bits; // image bits per pixel 8,16,24,32
char descriptor; // image descriptor bits (vh flip bits)
} TGA_HEADER;
#pragma pack(pop)
// Convert the RGB image to 8-bit greyscale and output
void RGB_OutputGreyscaleTGA(unsigned char* image_data, int width, int height, int pitch, wxFFile& file)
{
assert(sizeof(TGA_HEADER) == 18);
TGA_HEADER header;
header.identsize = 0;
header.colourmaptype = 0;
header.imagetype = 3;
header.xstart = 0;
header.ystart = 0;
header.width = (short)width;
header.height = (short)height;
header.bits = 8;
header.descriptor = 0;
file.Write(&header, sizeof(header));
// Start from the bottom, so things look the right way up
image_data += height*pitch;
for (int y = 0; y < height; ++y)
{
image_data -= pitch;
for (int x = 0; x < width; ++x)
file.Write(&image_data[x*3], 1);
}
}
std::set<wchar_t> AnalyseChars(wxString filename)
{
wxFFile File (filename, "rb");
if (! File.IsOpened())
throw "Cannot open file";
enum {
UNKNOWN,
UTF8,
UTF16SE, // same-endian as this machine
UTF16DE // different-endian
} Format = UNKNOWN;
unsigned short BOM;
File.Read(&BOM, 2);
if (BOM == 0xFEFF)
Format = UTF16SE;
else if (BOM == 0xFFFE)
Format = UTF16DE;
else {
// Make an educated guess based on the first byte
// If it's like "_\0" it's probably little-endian,
// if it's like "\0_" it's probably big-endian
if ((BOM & 0xFF00) == 0)
Format = UTF16SE;
else if ((BOM & 0x00FF) == 0)
Format = UTF16DE;
else
throw "Can't determine endianness of source file - make sure it's UTF16 and starts with a simple letter";
// (Maybe it's UTF8, but I don't want to bother with that)
File.Seek(0); // Make sure the first character is included in the list
}
std::set<wchar_t> Chars;
if (Format == UTF16SE)
{
wchar_t c;
while (! File.Eof())
{
File.Read(&c, 2);
if (c != '\r' && c != '\n')
Chars.insert(c);
}
}
else if (Format == UTF16DE)
{
unsigned short c;
while (! File.Eof())
{
if (File.Read(&c, 2) != 2) break; // abort if failed (i.e. eof)
c = (c>>8)|((c&0xff)<<8); // swap bytes
if (c != '\r' && c != '\n')
Chars.insert(c);
}
}
else
{
throw "Internal error - invalid file format";
}
return Chars;
}
+6
View File
@@ -0,0 +1,6 @@
// $Id: filemanip.h,v 1.1 2004/06/17 19:32:04 philip Exp $
#include <set>
void RGB_OutputGreyscaleTGA(unsigned char* image_data, int width, int height, int pitch, wxFFile& file);
std::set<wchar_t> AnalyseChars(wxString filename);
+305
View File
@@ -0,0 +1,305 @@
// $Id: font.cpp,v 1.1 2004/06/17 19:32:04 philip Exp $
#include "stdafx.h"
#include "font.h"
#include <math.h>
FontRenderer::FontRenderer(const char* filename0, const char* filename1, int ptsize)
{
int error;
error = FT_Init_FreeType(&FontLibrary0);
if (error)
{
throw "Error initialising FreeType";
}
error = FT_Init_FreeType(&FontLibrary1);
if (error)
{
FT_Done_FreeType(FontLibrary0);
throw "Error initialising FreeType";
}
error = FT_New_Face(
FontLibrary0,
filename0,
0, // index of face inside font file
&FontFace0
);
if (error)
{
FT_Done_FreeType(FontLibrary0);
FT_Done_FreeType(FontLibrary1);
throw "Error loading primary font";
}
error = FT_New_Face(
FontLibrary1,
filename1,
0, // index of face inside font file
&FontFace1
);
if (error)
{
FT_Done_Face(FontFace0);
FT_Done_FreeType(FontLibrary0);
FT_Done_FreeType(FontLibrary1);
throw "Error loading secondary font face";
}
error = FT_Set_Char_Size(
FontFace0,
0, // char_width in 1/64th of points
ptsize*64, // char_height in 1/64th of points
72, // horizontal device resolution
72 // vertical device resolution
);
if (error)
{
FT_Done_Face(FontFace0);
FT_Done_Face(FontFace1);
FT_Done_FreeType(FontLibrary0);
FT_Done_FreeType(FontLibrary1);
throw "Error loading scalable character from primary font - is this a TrueType font?";
}
error = FT_Set_Char_Size(
FontFace1,
0, // char_width in 1/64th of points
ptsize*64, // char_height in 1/64th of points
72, // horizontal device resolution
72 // vertical device resolution
);
if (error)
{
FT_Done_Face(FontFace0);
FT_Done_Face(FontFace1);
FT_Done_FreeType(FontLibrary0);
FT_Done_FreeType(FontLibrary1);
throw "Error loading scalable character from secondary font - is this a TrueType font?";
}
Boldness = 0;
Italicness = 0;
Tracking = 0;
Leading = 0;
}
FontRenderer::~FontRenderer()
{
FT_Done_Face(FontFace0);
FT_Done_Face(FontFace1);
FT_Done_FreeType(FontLibrary0);
FT_Done_FreeType(FontLibrary1);
}
#define deg2rad(a) ((double)a * 3.14159265358979323846 / 180.0)
void FontRenderer::LoadGlyph(const int charcode)
{
FT_Face FontFace = FontFace0;
int glyph_index = FT_Get_Char_Index(FontFace0, charcode);
Missing = false;
if (glyph_index == 0)
{
// Can't find glyph in primary font - switch to secondary
FontFace = FontFace1;
glyph_index = FT_Get_Char_Index(FontFace1, charcode);
// Still can't find it - use the missing glyph symbol
if (glyph_index == 0)
{
glyph_index = FT_Get_Char_Index(FontFace1, 0xFFFD);
Missing = true;
}
}
int error;
if (Italicness)
{
// Start with identity matrix (rotations could be added in here easily)
FT_Matrix mat;
mat.xx = mat.yy = (FT_Fixed)(0x10000L);
mat.xy = mat.yx = (FT_Fixed)(0x00000L);
// Apply shear
FT_Fixed f = (FT_Fixed)(tan(deg2rad(Italicness)) * 0x10000L);
mat.xy += FT_MulFix(f, mat.xx);
mat.yy += FT_MulFix(f, mat.yx);
FT_Set_Transform(FontFace, &mat, 0);
}
error = FT_Load_Glyph(FontFace, glyph_index, FT_LOAD_DEFAULT);
if (error)
throw "Error loading glyph";
if (Outline)
{
wxLogFatalError(wxT("Can't do this yet"));
/*
// Outline renderer which doesn't actually work:
assert(FontFace->glyph->format == FT_GLYPH_FORMAT_OUTLINE);
//FT_Outline *FontOutline = new FT_Outline;
//error = FT_Outline_New(FontLibrary, 1024, 1024, FontOutline);
//assert(!error);
FT_Outline *FontOutline = &FontFace->glyph->outline;
FT_BBox BBox;
error = FT_Outline_Get_BBox(FontOutline, &BBox);
assert(!error);
// Translate back to (0,0)
FT_Outline_Translate(FontOutline, -BBox.xMin, -BBox.yMin);
FT_Bitmap *Bmp = new FT_Bitmap;
Bmp->pixel_mode = FT_PIXEL_MODE_GRAY;
Bmp->num_grays = 256;
FontFace->glyph->bitmap_left = (BBox.xMin) >> 6;
FontFace->glyph->bitmap_top = (BBox.yMax + 31) >> 6;
Bmp->width = (BBox.xMax - BBox.xMin) >> 6;
Bmp->pitch = 3*Bmp->width;
Bmp->rows = (BBox.yMax - BBox.yMin) >> 6;
Bmp->buffer = new unsigned char[Bmp->pitch * Bmp->rows];
memset(Bmp->buffer, 0, sizeof(unsigned char) * Bmp->pitch * Bmp->rows);
error = FT_Outline_Get_Bitmap(FontLibrary, FontOutline, Bmp);
assert(!error);
FontFace->glyph->bitmap = *Bmp;
error = FT_Outline_Done(FontLibrary, FontOutline);
assert(!error);
*/
}
else
{
// Simple version:
error = FT_Render_Glyph(FontFace->glyph, FT_RENDER_MODE_NORMAL);
if (error)
throw "Error rendering glyph";
}
LastFontFace = FontFace;
}
void FontRenderer::GetBoundingBox(int& width, int& height)
{
FT_Bitmap* bmp = &LastFontFace->glyph->bitmap;
width = bmp->width + Boldness;
height = bmp->rows;
}
void FontRenderer::RenderGlyph(unsigned char* rgb_buffer, int& pos_left, int& pos_top, int width, int height, int pitch, bool single_glyph)
{
FT_Face FontFace = LastFontFace;
// This function only tries to work on 8-bit greyscale glyphs
if (FontFace->glyph->bitmap.pixel_mode != FT_PIXEL_MODE_GRAY)
throw "Error - invalid bitmap format";
// Add desired spacing, but not after zero-width combining glyphs
if (!single_glyph && FontFace->glyph->advance.x)
pos_left += Tracking;
FT_Bitmap* bmp = &FontFace->glyph->bitmap;
// Pointers to the appropriate row of pixel data
unsigned char* ImageRow = rgb_buffer;
unsigned char* GlyphRow = bmp->buffer;
int Left = pos_left;
int Top = pos_top;
if (!single_glyph)
{
Left += FontFace->glyph->bitmap_left;
Top -= FontFace->glyph->bitmap_top;
}
// Point to the first line that needs to be drawn
if (Top >= 0)
ImageRow += Top*pitch;
for (int GlyphY = 0; GlyphY < bmp->rows; ++GlyphY)
{
// Clip vertically
if (Top+GlyphY < 0 || Top+GlyphY >= height)
{
GlyphRow += bmp->pitch;
continue;
}
for (int GlyphX = -Boldness; GlyphX < bmp->width+Boldness; ++GlyphX)
{
// Clip horizontally
if (Left+GlyphX < 0 || Left+GlyphX >= width)
continue;
int value = 0;
if (! Boldness)
{
value = GlyphRow[GlyphX];
}
else
{
// Pretend to be bold - add lots of adjacent images
// Calculate value =~ sum(in[x-n] .. in[x+n])
// Work out valid limits for summing
// (with weird shifts so that it does precisely
// Boldness pixels)
int min = GlyphX - ( Boldness >> 1);
if (min < 0) min = 0;
int max = GlyphX + ( (Boldness+1) >> 1) + 1;
if (max > bmp->width) max = bmp->width;
for (int x = min; x < max; ++x)
value += GlyphRow[x];
}
// Additive composition of pixel onto image buffer
value += ImageRow[(Left+GlyphX)*3];
ImageRow[(Left+GlyphX)*3 ] =
ImageRow[(Left+GlyphX)*3+1] =
ImageRow[(Left+GlyphX)*3+2] = (unsigned char)(value > 255 ? 255 : value);
}
// Point everything at the next line
ImageRow += pitch;
GlyphRow += bmp->pitch;
}
if (!single_glyph)
{
// Advance the drawing-cursor ( >>6 due to 26.6-bit number format)
pos_left += FontFace->glyph->advance.x >> 6;
pos_top += FontFace->glyph->advance.y >> 6;
}
}
int FontRenderer::GetLineSpacing()
{
return Leading + (FontFace0->size->metrics.height >> 6);
}
void FontRenderer::GetMetrics(int& offset_x, int& offset_y, int& advance)
{
offset_x = LastFontFace->glyph->bitmap_left;
offset_y = LastFontFace->glyph->bitmap_top;
advance = LastFontFace->glyph->advance.x >> 6;
if (advance)
offset_x += Tracking;
}
+90
View File
@@ -0,0 +1,90 @@
// $Id: font.h,v 1.1 2004/06/17 19:32:04 philip Exp $
#ifndef _FONT_H_
#define _FONT_H_
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_OUTLINE_H
#include FT_BBOX_H
// XXX: Kerning ( = hard? got to store giant table for OpenGL to use)
// XXX: Right-to-left text
// Make my IDE a little happier:
#if 0
#include "freetype/freetype.h"
#include "freetype/freetype_defs.h"
#include "freetype/ftimage.h"
#include "freetype/fttypes.h"
#include "freetype/ftbbox.h"
#include "freetype/ftoutln.h"
#endif
class FontRenderer
{
public:
// Two fonts are required - a primary (0) font which will be used first,
// and a secondary (1) font for filling in missing glyphs.
// (The secondary font should usually be Arial Unicode MS).
FontRenderer(const char* filename0, const char* filename1, int ptsize);
~FontRenderer();
// Generate the glyph for the given Unicode code point
void LoadGlyph(const int charcode);
// Put the appropriate pixel sizes into width and height
void GetBoundingBox(int& width, int& height);
// Copy the glyph onto a 24-bit RGB image buffer
// pos_left / pos_top: Position to put the origin (usually bottom left corner) of the glyph.
// Altered by the function to point towards the next character.
// width / height: of bitmap, to do clipping
// pitch: Bytes per row, including any padding
// single_glyph: If true, doesn't update the cursor and draws with the bounding box at pos_left/top
void RenderGlyph(unsigned char* rgb_buffer, int& pos_left, int& pos_top, int width, int height, int pitch, bool single_glyph);
// Returns baseline-to-baseline distance, including the desired leading
int GetLineSpacing();
// Supplies some information for positioning glyphs
void GetMetrics(int& offset_x, int& offset_y, int& advance);
// Set by LoadGlyph if it can't find the right glyph
bool Missing;
/////////////////////////////////////////////////////////
// Font settings, set by users and used by this class:
// Shear angle (in degrees) for fake italics
int Italicness;
// 0 for standard; otherwise draws n+1 overlapping copies of the text
int Boldness;
// Additional spacing between each non-zero-width glyph and the next
int Tracking;
// Additional spacing between lines
int Leading;
// Whether to draw an outlined font
bool Outline;
private:
FT_Library FontLibrary0;
FT_Library FontLibrary1;
FT_Face FontFace0;
FT_Face FontFace1;
FT_Face LastFontFace; // = FontFace(0|1), depending on the last LoadGlyph
};
#endif // _FONT_H_
+224
View File
@@ -0,0 +1,224 @@
<?xml version="1.0" encoding="windows-1252"?>
<VisualStudioProject
ProjectType="Intel C++ Project"
Version="7.1"
Name="FontBuilder"
VCNestedProjectGUID="{277A0C35-0B44-48FC-81FD-119AD97194EA}"
VCNestedProjectFileName="FontBuilder.vcproj">
<Configurations>
<Configuration
Name="Debug|Win32">
<IntelOptions
CompilerName="1"/>
<Tool
Name="VCCLCompilerTool">
<IntelOptions
Optimization="0"
MinimalRebuild="1"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
BufferSecurityCheck="1"
EnableFunctionLevelLinking="1"
ForceConformanceInForLoopScope="1"/>
</Tool>
</Configuration>
<Configuration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool">
<IntelOptions
Optimization="1"
InlineFunctionExpansion="1"
FavorSizeOrSpeed="2"
OptimizeForProcessor="3"
LoopUnrolling=""
StringPooling="1"
RuntimeLibrary="2"
BufferSecurityCheck="0"
ForceConformanceInForLoopScope="1"
OpenMPDirectives="1"/>
</Tool>
</Configuration>
</Configurations>
<Files>
<File
RelativePath=".\filemanip.cpp">
<FileConfiguration
Name="Debug|Win32"/>
<FileConfiguration
Name="Release|Win32"/>
</File>
<File
RelativePath=".\font.cpp">
<FileConfiguration
Name="Debug|Win32"/>
<FileConfiguration
Name="Release|Win32"/>
</File>
<File
RelativePath=".\imagemanip.cpp">
<FileConfiguration
Name="Debug|Win32"/>
<FileConfiguration
Name="Release|Win32"/>
</File>
<File
RelativePath=".\packer.cpp">
<FileConfiguration
Name="Debug|Win32"/>
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool">
<IntelOptions
Optimization="1000"
InlineFunctionExpansion="2"
EnableIntrinsicFunctions="1"
FavorSizeOrSpeed="1"
OmitFramePointers="1"/>
</Tool>
</FileConfiguration>
</File>
<File
RelativePath=".\stdafx.cpp">
<FileConfiguration
Name="Debug|Win32"/>
<FileConfiguration
Name="Release|Win32"/>
</File>
<File
RelativePath=".\wxapp.cpp">
<FileConfiguration
Name="Debug|Win32"/>
<FileConfiguration
Name="Release|Win32"/>
</File>
<File
RelativePath=".\wxconfig.cpp">
<FileConfiguration
Name="Debug|Win32"/>
<FileConfiguration
Name="Release|Win32"/>
</File>
<File
RelativePath=".\wxframe.cpp">
<FileConfiguration
Name="Debug|Win32"/>
<FileConfiguration
Name="Release|Win32"/>
</File>
<File
RelativePath=".\platform\msw\fontselect.cpp">
<FileConfiguration
Name="Debug|Win32"/>
<FileConfiguration
Name="Release|Win32"/>
</File>
<File
RelativePath=".\filemanip.h">
<FileConfiguration
Name="Debug|Win32"/>
<FileConfiguration
Name="Release|Win32"/>
</File>
<File
RelativePath=".\font.h">
<FileConfiguration
Name="Debug|Win32"/>
<FileConfiguration
Name="Release|Win32"/>
</File>
<File
RelativePath=".\imagemanip.h">
<FileConfiguration
Name="Debug|Win32"/>
<FileConfiguration
Name="Release|Win32"/>
</File>
<File
RelativePath=".\packer.h">
<FileConfiguration
Name="Debug|Win32"/>
<FileConfiguration
Name="Release|Win32"/>
</File>
<File
RelativePath=".\resource.h">
<FileConfiguration
Name="Debug|Win32"/>
<FileConfiguration
Name="Release|Win32"/>
</File>
<File
RelativePath=".\stdafx.h">
<FileConfiguration
Name="Debug|Win32"/>
<FileConfiguration
Name="Release|Win32"/>
</File>
<File
RelativePath=".\wxconfig.h">
<FileConfiguration
Name="Debug|Win32"/>
<FileConfiguration
Name="Release|Win32"/>
</File>
<File
RelativePath=".\wxframe.h">
<FileConfiguration
Name="Debug|Win32"/>
<FileConfiguration
Name="Release|Win32"/>
</File>
<File
RelativePath=".\wxspinner.h">
<FileConfiguration
Name="Debug|Win32"/>
<FileConfiguration
Name="Release|Win32"/>
</File>
<File
RelativePath=".\platform\fontselect.h">
<FileConfiguration
Name="Debug|Win32"/>
<FileConfiguration
Name="Release|Win32"/>
</File>
<File
RelativePath=".\FontBuilder.ico">
<FileConfiguration
Name="Debug|Win32"/>
<FileConfiguration
Name="Release|Win32"/>
</File>
<File
RelativePath=".\FontBuilder.rc">
<FileConfiguration
Name="Debug|Win32"/>
<FileConfiguration
Name="Release|Win32"/>
</File>
<File
RelativePath=".\fileformat.txt">
<FileConfiguration
Name="Debug|Win32"/>
<FileConfiguration
Name="Release|Win32"/>
</File>
<File
RelativePath=".\readme.html">
<FileConfiguration
Name="Debug|Win32"/>
<FileConfiguration
Name="Release|Win32"/>
</File>
<File
RelativePath=".\todo.txt">
<FileConfiguration
Name="Debug|Win32"/>
<FileConfiguration
Name="Release|Win32"/>
</File>
</Files>
</VisualStudioProject>
+24
View File
@@ -0,0 +1,24 @@
// $Id: imagemanip.cpp,v 1.1 2004/06/17 19:32:04 philip Exp $
#include "stdafx.h"
#include "math.h"
unsigned char* GenerateImage(int width, int height)
{
unsigned char* ImageData = new unsigned char[width*height*3];
for (int y = 0; y < height; ++y)
{
for (int x = 0; x < width; ++x)
{
// Slightly off black, so you can see the bounding boxes
// by playing in some paint program
ImageData[(x+y*width)*3+0] = 0;
ImageData[(x+y*width)*3+1] = 0;
ImageData[(x+y*width)*3+2] = 1;
}
}
return ImageData;
}
+4
View File
@@ -0,0 +1,4 @@
// $Id: imagemanip.h,v 1.1 2004/06/17 19:32:04 philip Exp $
unsigned char* GenerateImage(int width, int height);
unsigned char* GreyscaleToRGB(int width, int height, unsigned char* grey);
+415
View File
@@ -0,0 +1,415 @@
// $Id: packer.cpp,v 1.1 2004/06/17 19:32:04 philip Exp $
#include "stdafx.h"
#include "packer.h"
#include <list>
#include <vector>
#include <math.h>
PackedFont::PackedFont(FontRenderer* font, std::set<wchar_t> chars)
{
TextureData = NULL;
TextureWidth = TextureHeight = 0;
Font = font;
Chars = chars;
}
PackedFont::~PackedFont()
{
delete[] TextureData;
}
class GlyphInfo {
public:
GlyphInfo() { c = 0; w = h = size = -1; }
GlyphInfo(wchar_t _c, int _w, int _h) { c=_c; w=_w; h=_h; size=(w*w)+(h*h); }
wchar_t c;
int w, h;
int x, y; // of top-left corner
bool operator<(GlyphInfo& b) { return size > b.size; } // sort biggest first
private:
int size; // used for sorting
};
typedef std::vector<GlyphInfo> GlyphsInfo;
struct GlyphCharSort : public std::binary_function<GlyphInfo&, GlyphInfo&, bool> {
bool operator()(GlyphInfo& x, GlyphInfo& y) { return x.c < y.c; }
};
int next_power_of_two(int x)
{
// See something like http://bob.allegronetwork.com/prog/tricks.html for an explanation
x |= (x >> 1);
x |= (x >> 2);
x |= (x >> 4);
x |= (x >> 8);
x |= (x >> 16);
return x+1;
}
// To avoid a few ugly gotos. Returns true on collision.
inline bool TryFittingInternal(const int &x, const int &y, GlyphsInfo& glyphs, const GlyphsInfo::iterator& ThisGlyph)
{
for (GlyphsInfo::iterator OtherGlyph = glyphs.begin(); OtherGlyph != ThisGlyph; ++OtherGlyph)
{
// Test for collisions - effectively trying to find a line that
// can fit between the two rectangles
if (x <= OtherGlyph->x+OtherGlyph->w
&& x+ThisGlyph->w >= OtherGlyph->x
&& y <= OtherGlyph->y+OtherGlyph->h
&& y+ThisGlyph->h >= OtherGlyph->y) return true;
}
return false;
}
bool TryFitting(const int packing_precision, const int texture_width, const int texture_height, const bool randomness, GlyphsInfo& glyphs, bool ProgressCallback(float, wxString, void*), void* CallbackData)
{
// A roughly O(n^3) algorithm, but with lots of attempted
// optimisations that do occasionally work.
int count = 0;
int ProgressCurrent = 0;
int ProgressMax = (int)glyphs.size();
GlyphInfo* LastGlyph = NULL;
for (GlyphsInfo::iterator ThisGlyph = glyphs.begin(); ThisGlyph != glyphs.end(); ++ThisGlyph, ++count)
{
if (ProgressCallback != NULL)
{
// Squaring makes the bar increase at a more constant rate
float Progress = powf((float)ProgressCurrent++ / (float)ProgressMax, 2.0f);
if (ProgressCallback(Progress, wxT("Fitting"), CallbackData))
throw "Aborted";
}
// After the first few easy ones, try sticking things in randomly
// and see if it turns out adequately.
if (randomness && count > 32)
{
/*
// except this is quite rubbish, so don't bother
bool fitted = false;
for (int i = 0; i < 16; ++i) // try several times
{
int x = 1 + rand() % (texture_width-ThisGlyph->w-1);
int y = 1 + rand() % (texture_height-ThisGlyph->h-1);
for (GlyphsInfo::iterator OtherGlyph = glyphs.begin(); OtherGlyph != ThisGlyph; ++OtherGlyph)
if (box_collide(x, y, x+ThisGlyphRef.w, y+ThisGlyphRef.h, OtherGlyph->x, OtherGlyph->y, OtherGlyph->x+OtherGlyph->w, OtherGlyph->y+OtherGlyph->h))
goto randomly_collided;
ThisGlyph->x = x;
ThisGlyph->y = y;
goto fitted;
randomly_collided: ;
}
*/
}
bool fitted = false;
int starty, stepy;
// Check whether this glyph is no smaller than the previous one
if (LastGlyph && LastGlyph->w <= ThisGlyph->w && LastGlyph->h <= ThisGlyph->h)
{
// If so, carry on the fitting from where the last glyph left off,
// because we've already discovered that there's no more
// space above.
--count;
if (count & 1)
stepy = -packing_precision;
else
stepy = packing_precision;
starty = LastGlyph->y;
}
else
{
// Alternate between fitting glyphs at the top and bottom
// to make things go a bit faster by minimising collisions
if (count & 1)
starty = texture_height-ThisGlyph->h-1, stepy = -packing_precision;
else
starty = 1, stepy = packing_precision;
}
for (int y = starty; y > 0 && y < texture_height-ThisGlyph->h; y += stepy)
{
// and alternate between left and right
int startx, stepx;
if (count & 2)
startx = 1, stepx = packing_precision;
else
startx = texture_width-ThisGlyph->w-1, stepx = -packing_precision;
int x;
/* If you have a multiple-processor machine and the Intel C++ compiler,
// this parallel version might be a little faster. (It's only a few
// tens of percents slower on a hyperthreaded computer)
// [Assuming it works at all, which it probably doesn't because I haven't
// tried compiling it recently]
if (startx == 1)
{
int max = texture_width-ThisGlyph->w;
#pragma omp parallel shared(startx, texture_width, ThisGlyph, stepx, glyphs)
{
#pragma omp for schedule(static) nowait
for (x = startx; x < max; x += stepx)
{
if (! TryFittingInternal(x, y, glyphs, ThisGlyph))
{
ThisGlyph->x = x;
stepx = 1e9; // Ugly hack so the threads finish at the same time
}
}
}
}
else
{
#pragma omp parallel shared(startx, texture_width, ThisGlyph, stepx, glyphs)
{
#pragma omp for schedule(static) nowait
for (x = startx; x > 0; x += stepx)
{
if (! TryFittingInternal(x, y, glyphs, ThisGlyph))
{
ThisGlyph->x = x;
stepx = -1e9;
}
}
}
}
if (stepx == 1e9 || stepx == -1e9)
{
ThisGlyph->y = y;
goto fitted;
}
*/
if (startx == 1)
{
for (x = startx; x < texture_width-ThisGlyph->w; x += stepx)
{
if (! TryFittingInternal(x, y, glyphs, ThisGlyph))
{
ThisGlyph->x = x;
fitted = true;
break;
}
}
}
else
{
for (x = startx; x > 0; x += stepx)
{
if (! TryFittingInternal(x, y, glyphs, ThisGlyph))
{
ThisGlyph->x = x;
fitted = true;
}
}
}
if (fitted)
{
ThisGlyph->y = y;
break;
}
}
if (!fitted)
// Couldn't fit glyph anywhere - give up
return false;
//fitted: ; // for lazy people who just want to goto
LastGlyph = &*ThisGlyph;
}
return true;
}
bool TryFittingLots(int& texture_width, int& texture_height, GlyphsInfo& glyphs, bool ProgressCallback(float, wxString, void*), void* CallbackData)
{
// Try the fairly fast method
if (TryFitting(16, texture_width, texture_height, false, glyphs, ProgressCallback, CallbackData))
return true;
// Go a bit more carefully
if (TryFitting(8, texture_width, texture_height, false, glyphs, ProgressCallback, CallbackData))
return true;
// Maybe it just needs a little more precision?
if (TryFitting(2, texture_width, texture_height, false, glyphs, ProgressCallback, CallbackData))
return true;
// This takes a long time and doesn't usually achieve much, but try it anyway
if (TryFitting(1, texture_width, texture_height, false, glyphs, ProgressCallback, CallbackData))
return true;
// Try swapping the dimensions if it's currently rectangular
if (texture_width != texture_height)
{
std::swap(texture_width, texture_height);
if (TryFitting(1, texture_width, texture_height, false, glyphs, ProgressCallback, CallbackData))
return true;
// Didn't work, swap back again
std::swap(texture_width, texture_height);
}
// Double the size and try again
if (texture_height == texture_width)
texture_width *= 2;
else
texture_height *= 2;
if (TryFitting(32, texture_width, texture_height, true, glyphs, ProgressCallback, CallbackData))
return true;
// How much space can it need?!
if (TryFitting(4, texture_width, texture_height, false, glyphs, ProgressCallback, CallbackData))
return true;
// Give up
return false;
}
void PackedFont::Generate(bool ProgressCallback(float, wxString, void*) = NULL, void* CallbackData = NULL)
{
GlyphsInfo glyphs;
int total_area = 0;
std::vector<wchar_t> MissingGlyphs;
int ProgressCurrent = 0;
int ProgressMax = (int)Chars.size();
std::list<GlyphInfo> SortableGlyphs;
for (std::set<wchar_t>::iterator c = Chars.begin(); c != Chars.end(); ++c)
{
if (ProgressCallback != NULL)
if (ProgressCallback((float)ProgressCurrent++ / (float)ProgressMax, wxT("Measuring"), CallbackData))
throw "Aborted";
int w, h;
Font->LoadGlyph(*c);
if (Font->Missing)
{
// Was the missing glyph missing?
if (*c == 0xFFFD)
{
// Just use a question mark. (Surely *every* font has a question mark...)
Font->LoadGlyph('?');
if (Font->Missing)
throw "Can't find either a missing glyph symbol or a question mark!";
Font->GetBoundingBox(w, h);
SortableGlyphs.push_back( GlyphInfo('?', w, h) );
total_area += w*h;
}
else
{
MissingGlyphs.push_back(*c);
}
}
else
{
Font->GetBoundingBox(w, h);
SortableGlyphs.push_back( GlyphInfo(*c, w, h) );
total_area += w*h;
}
}
SortableGlyphs.sort();
// Convert into a vector for a little more speed
for (std::list<GlyphInfo>::iterator i = SortableGlyphs.begin(); i != SortableGlyphs.end(); ++i)
{
glyphs.push_back(*i);
}
// Calculate minimum size square to hold all glyphs
int texture_width, texture_height;
texture_width = texture_height = next_power_of_two(int( sqrt((double)total_area) ));
// See if a smaller rectangle ought to still fit
if (texture_width*texture_height > total_area*2)
texture_height /= 2;
if (! TryFittingLots(texture_width, texture_height, glyphs, ProgressCallback, CallbackData))
throw "Failed to fit all the glyphs, too many times.";
TextureData = new unsigned char[texture_width*texture_height*3];
memset(TextureData, 0, texture_width*texture_height*3);
TextureWidth = texture_width;
TextureHeight = texture_height;
FontDefinition = wxEmptyString;
FontDefinition += wxT("100\n"); // version number
FontDefinition << TextureWidth << wxT(" ") << TextureHeight << wxT("\n"); // size of texture
FontDefinition << (int)glyphs.size() << wxT("\n"); // number of glyphs
FontDefinition << Font->GetLineSpacing() << wxT("\n");
SortableGlyphs.clear();
for (GlyphsInfo::iterator i = glyphs.begin(); i != glyphs.end(); ++i)
{
SortableGlyphs.push_back(*i);
}
SortableGlyphs.sort(GlyphCharSort());
ProgressCurrent = 0;
ProgressMax = (int)glyphs.size();
for (std::list<GlyphInfo>::iterator ThisGlyph = SortableGlyphs.begin(); ThisGlyph != SortableGlyphs.end(); ++ThisGlyph)
{
if (ProgressCallback != NULL)
if (ProgressCallback((float)ProgressCurrent++ / (float)ProgressMax, wxT("Rendering"), CallbackData))
throw "Aborted";
Font->LoadGlyph(ThisGlyph->c);
Font->RenderGlyph(TextureData, ThisGlyph->x, ThisGlyph->y, texture_width, texture_height, texture_width*3, true);
int offset_x, offset_y, advance;
Font->GetMetrics(offset_x, offset_y, advance);
FontDefinition << (int)ThisGlyph->c
<< wxT(" ") << ThisGlyph->x
<< wxT(" ") << (TextureHeight - ThisGlyph->y) // because it's stored upside-down
<< wxT(" ") << ThisGlyph->w
<< wxT(" ") << ThisGlyph->h
<< wxT(" ") << offset_x
<< wxT(" ") << offset_y
<< wxT(" ") << advance
<< wxT("\n");
}
if (MissingGlyphs.size())
{
wxString Error = wxString::Format(wxT("WARNING: %d glyphs were missing: "), MissingGlyphs.size());
for (size_t i = 0; i < MissingGlyphs.size(); ++i)
{
if (i) Error += wxT(", ");
if (i == 20)
{
Error += wxT("...");
break;
}
Error += wxString::Format(wxT("%d"), MissingGlyphs[i]);
}
wxLogWarning(Error);
}
}
+28
View File
@@ -0,0 +1,28 @@
// $Id: packer.h,v 1.1 2004/06/17 19:32:04 philip Exp $
#include "font.h"
#include <set>
class PackedFont
{
public:
PackedFont(FontRenderer* font, std::set<wchar_t> chars);
~PackedFont();
void Generate(bool ProgressCallback(float, wxString, void*), void* CallbackData);
// Sizes are always a power of two
int TextureWidth;
int TextureHeight;
// 24-bit (RGB) but greyscale image
unsigned char* TextureData;
// For the text file describing how to read all the glyphs
wxString FontDefinition;
private:
FontRenderer* Font;
std::set<wchar_t> Chars;
};
+24
View File
@@ -0,0 +1,24 @@
// $Id: fontselect.h,v 1.1 2004/06/17 19:32:04 philip Exp $
class FontSelectorDialog : public wxDialog
{
public:
FontSelectorDialog(wxWindow* parent);
~FontSelectorDialog();
wxString FontName;
wxString FontFilename;
void OnFontSelect(wxCommandEvent& event);
void OnOK(wxCommandEvent& event);
static void DefaultFonts(wxString& Name0, wxString& Filename0, wxString& Name1, wxString& Filename1);
private:
wxArrayString FontNames;
wxCharBuffer** FontFilenames;
DECLARE_EVENT_TABLE()
};
+136
View File
@@ -0,0 +1,136 @@
// $Id: fontselect.cpp,v 1.1 2004/06/17 19:32:04 philip Exp $
#include "stdafx.h"
#include "../fontselect.h"
#include "wx/msw/registry.h"
enum
{
ID_FontList = wxID_HIGHEST+1,
ID_FontPreview
};
BEGIN_EVENT_TABLE(FontSelectorDialog, wxDialog)
EVT_LISTBOX(ID_FontList, FontSelectorDialog::OnFontSelect)
EVT_BUTTON(wxID_OK, FontSelectorDialog::OnOK)
END_EVENT_TABLE()
FontSelectorDialog::FontSelectorDialog(wxWindow* parent)
: wxDialog(parent, -1, wxString(wxT("Font selector")), wxDefaultPosition, wxSize(400, 200), wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
{
wxBoxSizer* MainSizer = new wxBoxSizer(wxVERTICAL);
wxString PreviewString;
PreviewString += wxT("Aa");
PreviewString += (wchar_t)0x0105; // LATIN SMALL LETTER A WITH OGONEK
PreviewString += wxT("\nBb");
PreviewString += (wchar_t)0x00DF; // LATIN SMALL LETTER SHARP S
PreviewString += wxT("\nCc");
PreviewString += (wchar_t)0x00E7; // LATIN SMALL LETTER C WITH CEDILLA
PreviewString += (wchar_t)0x033F; // COMBINING DOUBLE OVERLINE
PreviewString += wxT("\n");
PreviewString += (wchar_t)0xFB4E; // HEBREW LETTER PE WITH RAFE
PreviewString += (wchar_t)0xFB6B; // ARABIC LETTER VEH FINAL FORM
PreviewString += (wchar_t)0xF915; // CJK COMPATIBILITY IDEOGRAPH-F915
PreviewString += (wchar_t)0x3342; // SQUARE HOON
wxBoxSizer* TopSizer = new wxBoxSizer(wxHORIZONTAL);
wxListBox* FontListBox = new wxListBox(this, ID_FontList, wxDefaultPosition, wxSize(200, 100));
TopSizer->Add(FontListBox, 0, wxGROW);
TopSizer->Add(new wxStaticText(this, ID_FontPreview, PreviewString), 1, wxGROW);
MainSizer->Add(TopSizer, 1);
wxBoxSizer* ButtonSizer = new wxBoxSizer(wxHORIZONTAL);
ButtonSizer->Add(new wxButton(this, wxID_OK, wxT("OK")), 0, wxALL, 10);
ButtonSizer->Add(new wxButton(this, wxID_CANCEL, wxT("Cancel")), 0, wxALL, 10);
MainSizer->Add(ButtonSizer, 0, wxALIGN_CENTER);
SetSizer(MainSizer);
// Get a list of all the fonts installed on the system
wxRegKey FontKey (wxT("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"));
// Get the list of keys (= font names)
wxString ValueName;
long ValueIndex;
FontKey.GetFirstValue(ValueName, ValueIndex);
do {
if (! ValueName.IsEmpty())
FontNames.Add(ValueName);
} while (FontKey.GetNextValue(ValueName, ValueIndex));
FontNames.Sort();
// Get all the filenames, and store in the listbox's client data
FontFilenames = new wxCharBuffer*[FontNames.Count()];
for (size_t i = 0; i < FontNames.Count(); ++i)
{
wxString t;
FontKey.QueryValue(FontNames[i], t);
wxCharBuffer* b = new wxCharBuffer(t.mb_str());
FontFilenames[i] = b;
}
FontListBox->Set(FontNames, (void**)FontFilenames);
}
FontSelectorDialog::~FontSelectorDialog()
{
for (size_t i = 0; i < FontNames.Count(); ++i)
delete FontFilenames[i];
delete[] FontFilenames;
}
void FontSelectorDialog::OnOK(wxCommandEvent& WXUNUSED(event))
{
// Find where the fonts are on the disk
wxRegKey FontPathKey (wxT("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"));
wxString FontPath;
FontPathKey.QueryValue(wxT("Fonts"), FontPath);
wxListBox* FontList = (wxListBox*)wxWindow::FindWindowById(ID_FontList);
int Selection = FontList->GetSelection();
FontFilename = FontPath + wxT("\\");
FontFilename += wxString::FromAscii( ((wxCharBuffer*) FontList->GetClientData(Selection))->data() );
FontName = FontList->GetStringSelection();
EndModal(wxID_OK);
}
void FontSelectorDialog::OnFontSelect(wxCommandEvent& event)
{
wxString FontName = event.GetString();
// Translate "Arial (TrueType)" into "Arial", etc
wxRegEx ThingyRemove;
ThingyRemove.Compile(wxT(" \\(.+\\)$"));
ThingyRemove.Replace(&FontName, wxT(""));
// Set the preview box to use that font
wxFont PreviewFont (18, wxDEFAULT, wxNORMAL, wxNORMAL, false, FontName, wxFONTENCODING_SYSTEM);
wxStaticText* PreviewText = (wxStaticText*)wxWindow::FindWindowById(ID_FontPreview);
PreviewText->SetFont(PreviewFont);
}
void FontSelectorDialog::DefaultFonts(wxString& Name0, wxString& Filename0, wxString& Name1, wxString& Filename1)
{
// Find where the fonts are on the disk
wxRegKey FontPathKey (wxT("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"));
wxString FontPath;
FontPathKey.QueryValue(wxT("Fonts"), FontPath);
Name0 = wxT("Verdana (TrueType)");
Filename0 = FontPath + wxT("\\verdana.ttf");
Name1 = wxT("Arial Unicode MS (TrueType)");
Filename1 = FontPath + wxT("\\arialuni.ttf");
}
+78
View File
@@ -0,0 +1,78 @@
<html>
<head>
<title>Font Builder</title>
</head>
<body bgcolor="#fff4e6" text="black" style="font-family:sans-serif">
<h2>Font Builder</h2>
<h3>Usage</h3>
<ol>
<li>Choose a <i>primary font</i>, which will be used for as much as
it can be used for.
<li>Optionally, choose a different <i>secondary font</i> which is used
when the primary font is missing certain characters - for example,
Trebuchet doesn't include any Greek/Cyrillic/Hebrew characters, so
these will be taken from Arial Unicode MS (by default) instead.
<li>Use the <i>Preview font</i> button to see what the font looks like
by rendering the contents of the textbox. Adjust the font settings
until perfection is attained.
<li>Choose a desired <i>character list</i> - a text file containing
all the characters that must be in the final font. The standard files
are <tt>latin.txt</tt> (containing ASCII plus some accented characters,
mainly useful for non-localised text) and <tt>standard.txt</tt>
(containing Latin, Greek, Cyrillic and Hebrew characters, for text that
could be in any language).
<li>Click <i>Generate texture</i>, and select a name for the <tt>.fnt</tt>
file. A <tt>.tga</tt> texture will also be generated, in the same directory
with the same name. Depending on several random coincidences, the texture
generation might be very fast or might take quite a while. When it finishes, the
excitingly patterned texture will be displayed.
<li>Save your settings through the <i>File</i> menu so that you can
easily recreate the font later.
</ol>
<h3>Unicode fonts</h3>
<p>
The font builder is intended to be used with Unicode characters.
Unfortunately, most fonts aren't. The font builder tries
to use <i>Arial Unicode MS</i> by default: this seems to
be installed by some versions of Microsoft Office, or can
be downloaded from locations such as
<a href="http://wildfiregames.com/~code/libraries/fonts/arialuni.exe">this</a> (12MB
self-extracting 7-Zip). It's probably worth getting, since it
includes almost every Unicode glyph that you could wish for.
</p><p>
Another potentially useful Unicode font is Bitstream Cyberbit
(available from <a href="ftp://ftp.netscape.com/pub/communicator/extras/fonts/windows/Cyberbit.ZIP">Netscape's FTP server</a>,
6MB).
</p><p>
All fonts must be installed into Windows before you can use
them in the font builder.
</p>
<h3>Font settings</h3>
<ul>
<li><b>Size</b> - size of the font in arbitrary units.
<li><b>Boldness</b> - if you don't have a proper bold variation of the
font, the boldness setting fakes it by drawing
the character several times.
<li><b>Italicness</b> - if you don't have a proper italic variaton,
the italicness setting slants it in 5-degree increments. Negative
values slant the other way.
<li><b>Tracking</b> - extra spacing in pixels added between every
non-zero-width glyph.
<li><b>Leading</b> - extra spacing in pixels between lines of text.
</ul>
</body>
</html>
+25
View File
@@ -0,0 +1,25 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by FontBuilder.rc
//
#define IDC_MYICON 2
#define IDD_FONTBUILDER_DIALOG 102
#define IDS_APP_TITLE 103
#define IDM_ABOUT 104
#define IDM_EXIT 105
#define IDI_FONTBUILDER 107
#define IDC_FONTBUILDER 109
#define IDR_MAINFRAME 128
#define IDC_STATIC -1
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NO_MFC 1
#define _APS_NEXT_RESOURCE_VALUE 130
#define _APS_NEXT_COMMAND_VALUE 32771
#define _APS_NEXT_CONTROL_VALUE 1000
#define _APS_NEXT_SYMED_VALUE 110
#endif
#endif
+7
View File
@@ -0,0 +1,7 @@
// $Id: stdafx.cpp,v 1.1 2004/06/17 19:32:04 philip Exp $
// stdafx.cpp : source file that includes just the standard includes
// FontBuilder.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information
#include "stdafx.h"
+54
View File
@@ -0,0 +1,54 @@
// $Id: stdafx.h,v 1.1 2004/06/17 19:32:04 philip Exp $
// Precompiled headers
// Exclude rarely-used stuff from Windows headers
#define WIN32_LEAN_AND_MEAN
// Disable some complaints in wx headers
#pragma warning (push)
#pragma warning (disable: 4267 4311 1125)
#ifdef __INTEL_COMPILER
// Disable some of the excessively pedantic icl /W4 warnings (remarks)
#pragma warning (disable: 193 373 444 981 383 1418)
#endif
// Include relevant wx headers
#include "wx/wxprec.h"
#include "wx/image.h"
#include "wx/spinctrl.h"
#include "wx/regex.h"
#include "wx/ffile.h"
#include "wx/utils.h"
#include "wx/progdlg.h"
#include "wx/wxexpr.h"
#include "wx/docview.h"
#include "wx/config.h"
#include "wx/filename.h"
#include "wx/config.h"
#pragma warning (pop)
#include <set>
#include <list>
//// Things other than precompiled headers which
// are just useful to include everywhere:
// For nicer memory-leak detection
#ifdef _DEBUG
#include <crtdbg.h>
#define new new(_NORMAL_BLOCK ,__FILE__, __LINE__)
#endif
const wxString version = wxT("v0.9");
// Don't care about copy constructors / assignment operators
#pragma warning (disable: 4511 4512)
#ifdef __INTEL_COMPILER
// Disable some of the excessively pedantic warnings again
#pragma warning (disable: 193 373 444 981 383 1418)
#endif
+16
View File
@@ -0,0 +1,16 @@
$Id: todo.txt,v 1.1 2004/06/17 19:32:04 philip Exp $
* Optimise storage of duplicated bitmaps (e.g. e and e-with-some-accent,
comma and semicolon, anything and fullwidth versions, etc)
* Optional antialiasing
* Optional outlining (text with e.g. yellow fill and black outline
is made by drawing the black outline font and then the yellow
normal font)
* Are the one-pixel black borders necessary? I don't trust graphics
cards not to leak a little bit, especially when they force texture
compression and filtering and antialiasing
* Work out when I should say 'character', when 'code point', and when 'glyph'
+34
View File
@@ -0,0 +1,34 @@
// $Id: wxapp.cpp,v 1.1 2004/06/17 19:32:04 philip Exp $
#include "stdafx.h"
#include "wxframe.h"
#include "wxconfig.h"
class FontBuilderApp : public wxApp
{
public:
virtual bool OnInit();
virtual int OnExit();
};
IMPLEMENT_APP(FontBuilderApp)
bool FontBuilderApp::OnInit()
{
ConfigInit();
MainFrame *frame = new MainFrame(wxString::Format(wxT("Font Builder %s"), version), wxDefaultPosition, wxSize(640,480));
frame->SetIcon(wxIcon(wxT("IDI_ICON1")));
frame->Show(true);
SetTopWindow(frame);
return true;
}
int FontBuilderApp::OnExit()
{
ConfigDestroy();
return 0;
}
+55
View File
@@ -0,0 +1,55 @@
// $Id: wxconfig.cpp,v 1.1 2004/06/17 19:32:04 philip Exp $
#include "stdafx.h"
#include "wxconfig.h"
void ConfigInit()
{
wxConfig* cfg = new wxConfig(wxT("WFG Font Builder"));
wxConfig::Set(cfg);
// Default paths, for the first time program is run:
// Get "x:\wherever\etc\binaries\"
wxFileName cwd = wxFileName::GetCwd()+wxT("\\");
cwd.RemoveDir((int)cwd.GetDirCount()-1);
if (!ConfigGet(wxT("FSF path")))
{
wxFileName dir = cwd; dir.AppendDir(wxT("data\\tools\\fontbuilder\\settings"));
ConfigSet(wxT("FSF path"), dir.GetPath(wxPATH_GET_VOLUME));
}
if (!ConfigGet(wxT("FNT path")))
{
wxFileName dir = cwd; dir.AppendDir(wxT("data\\mods\\official\\fonts"));
ConfigSet(wxT("FNT path"), dir.GetPath(wxPATH_GET_VOLUME));
}
if (!ConfigGet(wxT("Charset path")))
{
wxFileName dir = cwd; dir.AppendDir(wxT("data\\tools\\fontbuilder\\charsets"));
ConfigSet(wxT("Charset path"), dir.GetPath(wxPATH_GET_VOLUME));
}
}
wxString ConfigGet(wxString key)
{
wxConfig* cfg = (wxConfig*) wxConfig::Get();
wxString ret;
cfg->Read(key, &ret);
return ret;
}
void ConfigSet(wxString key, wxString value)
{
wxConfig* cfg = (wxConfig*) wxConfig::Get();
cfg->Write(key, value);
}
void ConfigDestroy()
{
delete wxConfig::Get();
}
+6
View File
@@ -0,0 +1,6 @@
// $Id: wxconfig.h,v 1.1 2004/06/17 19:32:04 philip Exp $
void ConfigInit();
wxString ConfigGet(wxString key);
void ConfigSet(wxString key, wxString value);
void ConfigDestroy();
+575
View File
@@ -0,0 +1,575 @@
// $Id: wxframe.cpp,v 1.1 2004/06/17 19:32:04 philip Exp $
#include "stdafx.h"
#include "wxframe.h"
#include "wxconfig.h"
#include "wxspinner.h"
#include "platform/fontselect.h"
#include "imagemanip.h"
#include "font.h"
#include "packer.h"
#include "filemanip.h"
bool Changes = false;
enum
{
ID_Quit = wxID_HIGHEST+1,
ID_About,
ID_New,
ID_Save,
ID_Open,
ID_Recent,
ID_GeneratePreview,
ID_GenerateTexture,
ID_FontSelect0,
ID_FontSelect1,
ID_CharSelect,
// For accessing values:
ID_PreviewText,
ID_Style_Size,
ID_Style_Boldness,
ID_Style_Italicness,
ID_Style_Tracking,
ID_Style_Leading
};
BEGIN_EVENT_TABLE(MainFrame, wxFrame)
EVT_MENU(ID_Quit, MainFrame::OnQuit)
EVT_MENU(ID_About, MainFrame::OnAbout)
EVT_MENU(ID_Save, MainFrame::OnSave)
EVT_MENU(ID_Open, MainFrame::OnOpen)
EVT_MENU_RANGE(wxID_FILE1, wxID_FILE9, MainFrame::OnMRUFile)
EVT_BUTTON(ID_FontSelect0, MainFrame::OnFontSelect0)
EVT_BUTTON(ID_FontSelect1, MainFrame::OnFontSelect1)
EVT_BUTTON(ID_CharSelect, MainFrame::OnCharSelect)
EVT_BUTTON(ID_GeneratePreview, MainFrame::OnGeneratePreview)
EVT_BUTTON(ID_GenerateTexture, MainFrame::OnGenerateTexture)
EVT_CLOSE(MainFrame::OnClose)
END_EVENT_TABLE()
BEGIN_EVENT_TABLE(BitmapPanel, wxPanel)
EVT_PAINT(BitmapPanel::OnPaint)
END_EVENT_TABLE()
MainFrame::MainFrame(const wxString& title, const wxPoint& pos, const wxSize& size)
: wxFrame((wxFrame *)NULL, -1, title, pos, size)
{
RecentFiles = new wxFileHistory(5);
wxMenu* menuFile = new wxMenu;
//menuFile->Append(ID_New, wxT("&New"));
menuFile->Append(ID_Open, wxT("&Open..."));
menuFile->Append(ID_Save, wxT("&Save..."));
menuFile->AppendSeparator();
wxMenu* menuRecent = new wxMenu;
menuFile->Append(ID_Recent, wxT("&Recent files"), menuRecent);
menuFile->AppendSeparator();
menuFile->Append(ID_About, wxT("&About"));
menuFile->AppendSeparator();
menuFile->Append(ID_Quit, wxT("E&xit"));
RecentFiles->UseMenu(menuRecent);
wxConfig* config = (wxConfig*)wxConfig::Get();
RecentFiles->Load(*config);
wxMenuBar* menuBar = new wxMenuBar;
menuBar->Append(menuFile, wxT("&File"));
SetMenuBar(menuBar);
CreateStatusBar();
// For textboxes that need to display Unicode text:
wxFont ArialUnicodeFont (12, wxDEFAULT, wxNORMAL, wxNORMAL, false, wxT("Arial Unicode MS"), wxFONTENCODING_SYSTEM);
// Main panel that fills the whole window
wxPanel* Panel = new wxPanel(this);
// Split the window into three main rows - controls, preview text, graphic
wxBoxSizer* OutlineSizer = new wxBoxSizer(wxVERTICAL);
// Split the controls part into three main columns: font, styles, actions
wxBoxSizer* ControlSizer = new wxBoxSizer(wxHORIZONTAL);
// Get some default values
FontSelectorDialog::DefaultFonts(FontName0, FontFilename0, FontName1, FontFilename1);
CharFilename = wxT("<ascii>");
CharName = wxT("Basic ASCII");
wxFlexGridSizer* FontSizer = new wxFlexGridSizer(2);
FontSizer->AddGrowableCol(0);
FontSizer->Add(new wxStaticText(Panel, -1, wxT("Primary font:")), 0, wxALIGN_RIGHT | wxALL, 2);
FontSizer->Add(new wxButton(Panel, ID_FontSelect0, FontName0), 0, wxGROW | wxALL, 2);
FontSizer->Add(new wxStaticText(Panel, -1, wxT("Secondary font:")), 0, wxALIGN_RIGHT | wxALL, 2);
FontSizer->Add(new wxButton(Panel, ID_FontSelect1, FontName1), 0, wxGROW | wxALL, 2);
FontSizer->Add(new wxStaticText(Panel, -1, wxT("Character list:")), 0, wxALIGN_RIGHT | wxALL, 2);
FontSizer->Add(new wxButton(Panel, ID_CharSelect, CharName), 0, wxGROW | wxALL, 2);
ControlSizer->Add(FontSizer, 0, wxLEFT | wxRIGHT | wxALIGN_CENTER_HORIZONTAL | wxALIGN_TOP, 8);
wxFlexGridSizer* StyleSizer = new wxFlexGridSizer(2);
StyleSizer->AddGrowableCol(0);
StyleSizer->Add(new wxStaticText(Panel, -1, wxT("Size:")), 0, wxALIGN_RIGHT | wxLEFT | wxRIGHT, 2);
StyleSizer->Add(new StyleSpinCtrl(Panel, ID_Style_Size, 1, 1024, 18), 0, wxGROW | wxLEFT | wxRIGHT, 2);
StyleSizer->Add(new wxStaticText(Panel, -1, wxT("Boldness:")), 0, wxALIGN_RIGHT | wxLEFT | wxRIGHT, 2);
StyleSizer->Add(new StyleSpinCtrl(Panel, ID_Style_Boldness, 0, 16, 0), 0, wxGROW | wxLEFT | wxRIGHT, 2);
StyleSizer->Add(new wxStaticText(Panel, -1, wxT("Italicness:")), 0, wxALIGN_RIGHT | wxLEFT | wxRIGHT, 2);
StyleSizer->Add(new StyleSpinCtrl(Panel, ID_Style_Italicness, -16, 16, 0), 0, wxGROW | wxLEFT | wxRIGHT, 2);
StyleSizer->Add(new wxStaticText(Panel, -1, wxT("Tracking:")), 0, wxALIGN_RIGHT | wxLEFT | wxRIGHT, 2);
StyleSizer->Add(new StyleSpinCtrl(Panel, ID_Style_Tracking, -256, 256, 0), 0, wxGROW | wxLEFT | wxRIGHT, 2);
StyleSizer->Add(new wxStaticText(Panel, -1, wxT("Leading:")), 0, wxALIGN_RIGHT | wxLEFT | wxRIGHT, 2);
StyleSizer->Add(new StyleSpinCtrl(Panel, ID_Style_Leading, -256, 256, 0), 0, wxGROW | wxLEFT | wxRIGHT, 2);
ControlSizer->Add(StyleSizer, 0, wxLEFT | wxRIGHT | wxALIGN_CENTER, 8);
wxBoxSizer* GenerateSizer = new wxBoxSizer(wxVERTICAL);
GenerateSizer->Add(new wxButton(Panel, ID_GeneratePreview, wxT("Preview font")), 1, wxGROW | wxALL | wxALIGN_CENTER, 4);
GenerateSizer->Add(new wxButton(Panel, ID_GenerateTexture, wxT("Generate texture")), 1, wxGROW | wxALL | wxALIGN_CENTER, 4);
ControlSizer->Add(GenerateSizer, 0, wxLEFT | wxRIGHT | wxALIGN_CENTER_HORIZONTAL | wxALIGN_TOP, 8);
OutlineSizer->Add(ControlSizer);
OutlineSizer->Add(new wxStaticText(Panel, -1, wxT("Text to display in preview:")), 0, wxALL, 2);
// Create a textbox containing "abcABCfunnysymbols"
wxString Font_string = wxT("abcABC"); Font_string += wchar_t(225); Font_string += wchar_t(223); Font_string += wchar_t(231); Font_string += wchar_t(779);Font_string += wchar_t(9812);
wxTextCtrl* PreviewTextBox = new wxTextCtrl(Panel, ID_PreviewText, Font_string, wxDefaultPosition, wxSize(300, 80), wxTE_MULTILINE);
PreviewTextBox->SetFont(ArialUnicodeFont);
OutlineSizer->Add(PreviewTextBox, 0, wxGROW | wxLEFT | wxRIGHT, 4);
PreviewPanel = new BitmapPanel(Panel);
OutlineSizer->Add(PreviewPanel, 1, wxGROW);
Panel->SetSizer(OutlineSizer);
PreviewImageData = NULL;
PreviewImage = NULL;
PreviewWidth = 512;
PreviewHeight = 256;
}
void MainFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
{
Close(false);
}
void MainFrame::OnClose(wxCloseEvent& event)
{
if (Changes)
{
wxMessageDialog dlg (this, wxT("The font settings have been altered.\n\nDo you want to save the changes?"), wxT("Font Builder"), wxYES_NO|wxCANCEL | wxICON_QUESTION);
int ret = dlg.ShowModal();
if (ret == wxID_CANCEL)
{
event.Veto();
return;
}
else if (ret == wxID_YES)
{
if (! SaveDialog())
{
event.Veto();
return;
}
}
}
wxConfig* config = (wxConfig*)wxConfig::Get();
RecentFiles->Save(*config);
delete RecentFiles;
delete PreviewImage;
delete[] PreviewImageData;
event.Skip();
}
void MainFrame::LoadSettings(wxString& filename)
{
wxExprDatabase db;
db.Read(filename);
wxTextCtrl* PreviewTextCtrl = (wxTextCtrl*)wxWindow::FindWindowById(ID_PreviewText);
StyleSpinCtrl* BoldnessCtrl = (StyleSpinCtrl*)wxWindow::FindWindowById(ID_Style_Boldness);
StyleSpinCtrl* ItalicnessCtrl = (StyleSpinCtrl*)wxWindow::FindWindowById(ID_Style_Italicness);
StyleSpinCtrl* SizeCtrl = (StyleSpinCtrl*)wxWindow::FindWindowById(ID_Style_Size);
StyleSpinCtrl* TrackingCtrl = (StyleSpinCtrl*)wxWindow::FindWindowById(ID_Style_Tracking);
StyleSpinCtrl* LeadingCtrl = (StyleSpinCtrl*)wxWindow::FindWindowById(ID_Style_Leading);
wxButton* FontSelect0 = (wxButton*)wxWindow::FindWindowById(ID_FontSelect0);
wxButton* FontSelect1 = (wxButton*)wxWindow::FindWindowById(ID_FontSelect1);
wxButton* CharSelect = (wxButton*)wxWindow::FindWindowById(ID_CharSelect);
db.BeginFind();
wxExpr *Settings = db.FindClauseByFunctor(wxT("Settings"));
Settings->GetAttributeValue(wxT("FontName0"), FontName0);
Settings->GetAttributeValue(wxT("FontName1"), FontName1);
Settings->GetAttributeValue(wxT("FontFilename0"), FontFilename0);
Settings->GetAttributeValue(wxT("FontFilename1"), FontFilename1);
FontSelect0->SetLabel(FontName0);
FontSelect1->SetLabel(FontName1);
Settings->GetAttributeValue(wxT("CharName"), CharName);
Settings->GetAttributeValue(wxT("CharFilename"), CharFilename);
CharSelect->SetLabel(CharName);
int t;
Settings->GetAttributeValue(wxT("Boldness"), t); BoldnessCtrl->SetValue(t);
Settings->GetAttributeValue(wxT("Italicness"), t); ItalicnessCtrl->SetValue(t);
Settings->GetAttributeValue(wxT("Size"), t); SizeCtrl->SetValue(t);
Settings->GetAttributeValue(wxT("Tracking"), t); TrackingCtrl->SetValue(t);
Settings->GetAttributeValue(wxT("Leading"), t); LeadingCtrl->SetValue(t);
wxString PreviewTextUTF;
Settings->GetAttributeValue(wxT("PreviewText"), PreviewTextUTF);
// Unpleasant conversion from UTF8 (pretending to be UTF16) into UTF16:
char* buffer = new char[PreviewTextUTF.length()+1];
for (size_t i=0; i<PreviewTextUTF.length(); ++i)
buffer[i] = (char)PreviewTextUTF.GetChar(i);
buffer[PreviewTextUTF.length()] = 0;
wxString PreviewText (buffer, wxConvUTF8);
delete[] buffer;
PreviewTextCtrl->SetValue(PreviewText);
Changes = false;
}
void MainFrame::SaveSettings(wxString& filename)
{
wxExprDatabase db;
wxTextCtrl* PreviewTextCtrl = (wxTextCtrl*)wxWindow::FindWindowById(ID_PreviewText);
StyleSpinCtrl* BoldnessCtrl = (StyleSpinCtrl*)wxWindow::FindWindowById(ID_Style_Boldness);
StyleSpinCtrl* ItalicnessCtrl = (StyleSpinCtrl*)wxWindow::FindWindowById(ID_Style_Italicness);
StyleSpinCtrl* SizeCtrl = (StyleSpinCtrl*)wxWindow::FindWindowById(ID_Style_Size);
StyleSpinCtrl* TrackingCtrl = (StyleSpinCtrl*)wxWindow::FindWindowById(ID_Style_Tracking);
StyleSpinCtrl* LeadingCtrl = (StyleSpinCtrl*)wxWindow::FindWindowById(ID_Style_Leading);
wxExpr *Settings = new wxExpr(wxT("Settings"));
Settings->AddAttributeValueString(wxT("FontName0"), FontName0);
Settings->AddAttributeValueString(wxT("FontName1"), FontName1);
Settings->AddAttributeValueString(wxT("FontFilename0"), FontFilename0);
Settings->AddAttributeValueString(wxT("FontFilename1"), FontFilename1);
Settings->AddAttributeValueString(wxT("CharName"), CharName);
Settings->AddAttributeValueString(wxT("CharFilename"), CharFilename);
Settings->AddAttributeValue(wxT("Boldness"), (long)BoldnessCtrl->GetValidValue());
Settings->AddAttributeValue(wxT("Italicness"), (long)ItalicnessCtrl->GetValidValue());
Settings->AddAttributeValue(wxT("Size"), (long)SizeCtrl->GetValidValue());
Settings->AddAttributeValue(wxT("Tracking"), (long)TrackingCtrl->GetValidValue());
Settings->AddAttributeValue(wxT("Leading"), (long)LeadingCtrl->GetValidValue());
// Convert into UTF8 and pretend it's ASCII, because wxExprDatabase doesn't like Unicode
wxCharBuffer PreviewTextUTF = PreviewTextCtrl->GetValue().mb_str(wxConvUTF8);
Settings->AddAttributeValueString(wxT("PreviewText"), wxString::FromAscii(PreviewTextUTF));
db.Append(Settings);
db.Write(filename);
Changes = false;
}
void MainFrame::OnOpen(wxCommandEvent& WXUNUSED(event))
{
wxFileDialog Dlg (this, wxT("Open font settings"), ConfigGet(wxT("FSF path")), wxEmptyString, wxT("Font settings (*.fst)|*.fst|All files (*.*)|*.*"), wxOPEN | wxHIDE_READONLY);
if (Dlg.ShowModal() == wxID_OK)
{
RecentFiles->AddFileToHistory(Dlg.GetPath());
wxString path = Dlg.GetPath();
LoadSettings(path);
ConfigSet(wxT("FSF path"), Dlg.GetDirectory());
}
}
bool MainFrame::SaveDialog()
{
wxFileDialog Dlg (this, wxT("Save current settings"), ConfigGet(wxT("FSF path")), wxEmptyString, wxT("Font settings (*.fst)|*.fst|All files (*.*)|*.*"), wxSAVE | wxOVERWRITE_PROMPT);
if (Dlg.ShowModal() == wxID_OK)
{
RecentFiles->AddFileToHistory(Dlg.GetPath());
wxString path = Dlg.GetPath();
SaveSettings(path);
ConfigSet(wxT("FSF path"), Dlg.GetDirectory());
return true;
}
return false;
}
void MainFrame::OnSave(wxCommandEvent& WXUNUSED(event))
{
SaveDialog();
}
void MainFrame::OnMRUFile(wxCommandEvent& event)
{
wxString filename = RecentFiles->GetHistoryFile(event.GetId() - wxID_FILE1);
LoadSettings(filename);
RecentFiles->AddFileToHistory(filename);
}
void MainFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
{
wxMessageBox(wxString::Format(wxT("Unicode Font Builder %s - created by Philip Taylor for WildFire Games"), version), wxT("About"), wxOK | wxICON_INFORMATION );
}
void MainFrame::OnGeneratePreview(wxCommandEvent& WXUNUSED(event))
{
GeneratePreview();
}
void MainFrame::GeneratePreview()
{
if (FontFilename0.IsEmpty() || FontFilename1.IsEmpty())
return;
PreviewPanel->GetSize(&PreviewWidth, &PreviewHeight);
delete[] PreviewImageData;
PreviewImageData = GenerateImage(PreviewWidth, PreviewHeight);
// Find all the relevant controls (slightly nicer than storing lots of pointers in the class)
wxTextCtrl* PreviewTextCtrl = (wxTextCtrl*)wxWindow::FindWindowById(ID_PreviewText);
StyleSpinCtrl* BoldnessCtrl = (StyleSpinCtrl*)wxWindow::FindWindowById(ID_Style_Boldness);
StyleSpinCtrl* ItalicnessCtrl = (StyleSpinCtrl*)wxWindow::FindWindowById(ID_Style_Italicness);
StyleSpinCtrl* SizeCtrl = (StyleSpinCtrl*)wxWindow::FindWindowById(ID_Style_Size);
StyleSpinCtrl* TrackingCtrl = (StyleSpinCtrl*)wxWindow::FindWindowById(ID_Style_Tracking);
StyleSpinCtrl* LeadingCtrl = (StyleSpinCtrl*)wxWindow::FindWindowById(ID_Style_Leading);
try
{
FontRenderer Font(
FontFilename0.ToAscii(),
FontFilename1.ToAscii(),
SizeCtrl->GetValidValue() );
Font.Boldness = BoldnessCtrl->GetValidValue();
Font.Italicness = 5 * ItalicnessCtrl->GetValidValue();
Font.Tracking = TrackingCtrl->GetValidValue();
Font.Leading = LeadingCtrl->GetValidValue();
Font.Outline = false;
int x = 16, y = Font.GetLineSpacing();
wxString PreviewText = PreviewTextCtrl->GetValue();
for (size_t i = 0; i < PreviewText.Length(); ++i)
{
if (PreviewText[i] == wxT('\n'))
{
x = 16;
y += Font.GetLineSpacing();
}
else
{
Font.LoadGlyph(PreviewText[i]);
Font.RenderGlyph(PreviewImageData, x, y, PreviewWidth, PreviewHeight, PreviewWidth*3, false);
}
}
}
catch (const char* m) {
wxLogError(wxString::Format(wxT("Failed to generate preview: %s"), wxString::FromAscii(m)));
return;
}
delete PreviewImage;
PreviewImage = new wxImage(PreviewWidth, PreviewHeight, PreviewImageData, true);
PreviewPanel->SetBitmap(new wxBitmap(PreviewImage));
PreviewPanel->Refresh();
Changes = true;
}
void MainFrame::OnGenerateTexture(wxCommandEvent& WXUNUSED(event))
{
wxFileDialog Dlg (this, wxT("Save font definition and texture"), ConfigGet(wxT("FNT path")), wxEmptyString, wxT("Font definition files (*.fnt)|*.fnt|All files (*.*)|*.*"), wxSAVE | wxOVERWRITE_PROMPT);
if (Dlg.ShowModal() == wxID_OK)
{
wxFileName FontDefnFilename (Dlg.GetPath());
wxFileName TextureFilename = FontDefnFilename;
TextureFilename.SetExt(wxT("tga"));
GenerateTexture(TextureFilename.GetFullPath(), FontDefnFilename.GetFullPath());
ConfigSet(wxT("FNT path"), TextureFilename.GetPath());
}
}
bool ProgressDialogCallback(float Progress, wxString Msg, void* data) {
return ! ((wxProgressDialog *)data)->Update((int)(Progress*1024.0), Msg);
}
void MainFrame::GenerateTexture(wxString TextureFilename, wxString FontDefnFilename)
{
if (FontFilename0.IsEmpty() || FontFilename1.IsEmpty())
return;
// Find all the relevant controls (slightly nicer than storing lots of pointers in the class)
StyleSpinCtrl* BoldnessCtrl = (StyleSpinCtrl*)wxWindow::FindWindowById(ID_Style_Boldness);
StyleSpinCtrl* ItalicnessCtrl = (StyleSpinCtrl*)wxWindow::FindWindowById(ID_Style_Italicness);
StyleSpinCtrl* SizeCtrl = (StyleSpinCtrl*)wxWindow::FindWindowById(ID_Style_Size);
StyleSpinCtrl* TrackingCtrl = (StyleSpinCtrl*)wxWindow::FindWindowById(ID_Style_Tracking);
StyleSpinCtrl* LeadingCtrl = (StyleSpinCtrl*)wxWindow::FindWindowById(ID_Style_Leading);
// Work out what characters need to be included in the texture
std::set<wchar_t> Chars;
if (CharFilename == wxT("<ascii>"))
{
for (wchar_t c = 0x20; c < 0x7f; ++c)
Chars.insert(c);
}
else
{
try
{
Chars = AnalyseChars(CharFilename);
}
catch (const char* m) {
wxLogError(wxString::Format(wxT("Failed to analyse character file: %s"), wxString::FromAscii(m)));
return;
}
}
// Add the 'missing' symbol (if it's not missing, it'll use a ? instead)
Chars.insert(0xFFFD);
// Generate the texture
try
{
FontRenderer Font(
FontFilename0.ToAscii(),
FontFilename1.ToAscii(),
SizeCtrl->GetValidValue() );
Font.Boldness = BoldnessCtrl->GetValidValue();
Font.Italicness = 5 * ItalicnessCtrl->GetValidValue();
Font.Tracking = TrackingCtrl->GetValidValue();
Font.Leading = LeadingCtrl->GetValidValue();
Font.Outline = false;
PackedFont Packed (&Font, Chars);
wxProgressDialog ProgressDialog (wxT("Progress"), wxT("Thinking..."), 1024, this, wxPD_APP_MODAL | wxPD_CAN_ABORT | wxPD_ELAPSED_TIME);
try
{
Packed.Generate(&ProgressDialogCallback, &ProgressDialog);
}
catch (const char* m) {
wxLogError(wxString::Format(wxT("Failed to generate texture: %s"), wxString::FromAscii(m)));
return;
}
ProgressDialog.Destroy();
PreviewWidth = Packed.TextureWidth;
PreviewHeight = Packed.TextureHeight;
delete[] PreviewImageData;
PreviewImageData = new unsigned char[PreviewWidth*PreviewHeight*3];
memcpy(PreviewImageData, Packed.TextureData, PreviewWidth*PreviewHeight*3);
delete PreviewImage;
PreviewImage = new wxImage(PreviewWidth, PreviewHeight, PreviewImageData, true);
PreviewPanel->SetBitmap(new wxBitmap(PreviewImage));
PreviewPanel->Refresh();
wxFFile TGAFile(TextureFilename, "wb");
if (! TGAFile.IsOpened())
throw "Error opening texture file for output";
RGB_OutputGreyscaleTGA(PreviewImageData, PreviewWidth, PreviewHeight, PreviewWidth*3, TGAFile);
TGAFile.Close();
wxFFile FntFile(FontDefnFilename, "w");
if (! FntFile.IsOpened())
throw "Error opening font definition file for output";
FntFile.Write(Packed.FontDefinition);
FntFile.Close();
}
catch (const char* m) {
wxLogError(wxString::Format(wxT("Failed to generate texture: %s"), wxString::FromAscii(m)));
return;
}
Changes = true;
}
void MainFrame::OnFontSelect0(wxCommandEvent& event)
{
FontSelectorDialog Dlg(this);
if (Dlg.ShowModal() == wxID_OK)
{
FontFilename0 = Dlg.FontFilename;
FontName0 = Dlg.FontName;
((wxButton*)event.GetEventObject()) -> SetLabel(FontName0);
}
}
void MainFrame::OnFontSelect1(wxCommandEvent& event)
{
FontSelectorDialog Dlg(this);
if (Dlg.ShowModal() == wxID_OK)
{
FontFilename1 = Dlg.FontFilename;
FontName1 = Dlg.FontName;
((wxButton*)event.GetEventObject()) -> SetLabel(FontName1);
}
}
void MainFrame::OnCharSelect(wxCommandEvent& event)
{
wxFileDialog Dlg(this, wxT("UTF16 text file containing desired characters"), ConfigGet(wxT("Charset path")), wxEmptyString, wxT("Text files (*.txt)|*.txt|All files (*.*)|*.*"), wxOPEN | wxHIDE_READONLY);
if (Dlg.ShowModal() == wxID_OK)
{
CharFilename = Dlg.GetPath();
CharName = Dlg.GetFilename();
((wxButton*)event.GetEventObject()) -> SetLabel(CharName);
ConfigSet(wxT("Charset path"), Dlg.GetDirectory());
}
}
void BitmapPanel::OnPaint(wxPaintEvent& WXUNUSED(event))
{
wxPaintDC dc(this);
if (Bitmap)
dc.DrawBitmap(*Bitmap, 0, 0, false);
}
+78
View File
@@ -0,0 +1,78 @@
// $Id: wxframe.h,v 1.1 2004/06/17 19:32:04 philip Exp $
class BitmapPanel : public wxPanel
{
public:
BitmapPanel(wxWindow* parent)
: wxPanel(parent)
{
Bitmap = NULL;
}
~BitmapPanel()
{
delete Bitmap;
}
void OnPaint(wxPaintEvent& event);
void SetBitmap(wxBitmap* bmp)
{
delete Bitmap;
Bitmap = bmp;
}
private:
wxBitmap* Bitmap;
DECLARE_EVENT_TABLE()
};
class MainFrame : public wxFrame
{
public:
MainFrame(const wxString& title, const wxPoint& pos, const wxSize& size);
void OnQuit(wxCommandEvent& event);
void OnClose(wxCloseEvent& event);
void OnAbout(wxCommandEvent& event);
bool SaveDialog();
void OnSave(wxCommandEvent& event);
void OnOpen(wxCommandEvent& event);
void OnMRUFile(wxCommandEvent& event);
void OnFontSelect0(wxCommandEvent& event);
void OnFontSelect1(wxCommandEvent& event);
void OnCharSelect(wxCommandEvent& event);
void OnGeneratePreview(wxCommandEvent& event);
void OnGenerateTexture(wxCommandEvent& event);
private:
BitmapPanel* PreviewPanel;
unsigned char* PreviewImageData;
wxImage* PreviewImage;
void GeneratePreview();
int PreviewWidth, PreviewHeight;
void GenerateTexture(wxString TextureFilename, wxString FontDefnFilename);
void SaveSettings(wxString& filename);
void LoadSettings(wxString& filename);
wxString FontName0;
wxString FontName1;
wxString FontFilename0;
wxString FontFilename1;
wxString CharName;
wxString CharFilename;
wxFileHistory* RecentFiles;
DECLARE_EVENT_TABLE()
};
+22
View File
@@ -0,0 +1,22 @@
// $Id: wxspinner.h,v 1.1 2004/06/17 19:32:04 philip Exp $
class StyleSpinCtrl : public wxSpinCtrl
{
public:
StyleSpinCtrl(wxWindow* parent, wxWindowID win_id, int min_val, int max_val, int initial_val)
: wxSpinCtrl(parent, win_id, wxEmptyString, wxDefaultPosition, wxSize(50, 20), wxSP_ARROW_KEYS, min_val, max_val, initial_val)
{
SetValue(initial_val);
}
// Like GetValue, but guaranteed to be inside the range (Min..Max)
// no matter what people type in
int GetValidValue()
{
int Value = GetValue();
int Min = GetMin();
int Max = GetMax();
return Value <= Min ? Min : Value >= Max ? Max : Value;
}
};