📄 main.cpp
字号:
/*
bmfgen: Bitmapfont generator for the BMF_Font library.
Copyright (C) 2003-2005 Trenkwalder Markus
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Trenkwalder Markus
trenki2@gmx.net
*/
#include "SDL.h"
#include "SDL_ttf.h"
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
/******************************************************************************/
#define PTSIZE(size) ((int)(size * (96.0/72.0)))
//#define PTSIZE(size) size
struct CmdLineArgs {
string fontname;
int ptsize;
int texturesize;
bool solid;
bool grid;
bool bmp;
bool italic;
bool underline;
bool bold;
bool useExtendedCharset;
};
/******************************************************************************/
int hostIsLittleEndian() {
static union {
unsigned short sh;
char ch[2];
} endian_test = { 0x0102 };
return endian_test.ch[0] == 0x02;
}
Uint16 swap16(Uint16 D) {
return hostIsLittleEndian() ? D : ((D<<8)|(D>>8));
}
Uint32 swap32(Uint32 D) {
return hostIsLittleEndian() ? D : ((D<<24)|((D<<8)&0x00FF0000)|((D>>8)&0x0000FF00)|(D>>24));
}
/******************************************************************************/
void putpixel(SDL_Surface *surface, int x, int y, Uint32 pixel)
{
int bpp = surface->format->BytesPerPixel;
/* Here p is the address to the pixel we want to set */
Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
switch(bpp) {
case 1:
*p = pixel;
break;
case 2:
*(Uint16 *)p = pixel;
break;
case 3:
if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
p[0] = (pixel >> 16) & 0xff;
p[1] = (pixel >> 8) & 0xff;
p[2] = pixel & 0xff;
} else {
p[0] = pixel & 0xff;
p[1] = (pixel >> 8) & 0xff;
p[2] = (pixel >> 16) & 0xff;
}
break;
case 4:
*(Uint32 *)p = pixel;
break;
}
}
/******************************************************************************/
// Draws a yellow grid into the surface
void DrawGrid(SDL_Surface *surface) {
int advance = surface->w / 16;
Uint32 color = SDL_MapRGB( surface->format, 255, 255, 0 );
for ( int x = 0; x < surface->w; x++ ) {
for ( int y = 0; y < surface->h; y++ ) {
if ( !(x % advance && y % advance) ) {
putpixel( surface, x, y, color );
}
}
}
}
/******************************************************************************/
bool GetArgs(int argc, char* argv[], CmdLineArgs* cmdargs) {
if ( argc < 4 ) {
cout << "Usage: bmfgen <font.ttf> <ptsize> <texture_size> [options]" << endl;
cout << "Example: bmfgen verdana.ttf 12 256" << endl;
cout << "Available options:" << endl;
cout << " -i Render italic text" << endl;
cout << " -u Render underlined text" << endl;
cout << " -b Render bold text" << endl;
cout << " -solid Render text without antialiasing" << endl;
cout << " -grid Draw a grid in the .bmp file" << endl;
cout << " -bmp Create a .bmp file" << endl;
cout << " -ext-charset Also ouput extended ASCII characters" << endl;
return false;
}
cmdargs->fontname = argv[1];
cmdargs->ptsize = atoi( argv[2] );
if ( cmdargs->ptsize <= 0 || cmdargs->ptsize > 150 ) {
cout << "point size must be within 1 and 150" << endl;
return false;
}
cmdargs->texturesize = atoi( argv[3] );
if ( cmdargs->texturesize < 128 || cmdargs->texturesize > 2048 ) {
cout << "wrong parameter: texture size" << endl;
return false;
}
int val = 1;
while ( val < cmdargs->texturesize )
val <<= 1;
if ( val != cmdargs->texturesize ) {
cout << "texture size is not a power of two" << endl;
return false;
}
string option;
cmdargs->solid = false;
cmdargs->grid = false;
cmdargs->bmp = false;
cmdargs->italic = false;
cmdargs->underline = false;
cmdargs->bold = false;
cmdargs->useExtendedCharset = false;
for ( int i = 4; i < argc; i++ ) {
option = argv[i];
if ( option == "-solid" ) {
cmdargs->solid = true;
} else if ( option == "-grid" ) {
cmdargs->grid = true;
} else if ( option == "-bmp" ) {
cmdargs->bmp = true;
} else if ( option == "-i" ) {
cmdargs->italic = true;
} else if ( option == "-u" ) {
cmdargs->underline = true;
} else if ( option == "-b" ) {
cmdargs->bold = true;
} else if ( option == "-ext-charset" ) {
cmdargs->useExtendedCharset = true;
} else {
cout << "wrong option: " << option << endl;
return false;
}
}
return true;
}
/******************************************************************************/
SDL_Rect CalculateBlitPos(TTF_Font *font, int ch, int texturesize) {
string str;
str += (unsigned char)ch;
int w, h;
TTF_SizeText(font, str.c_str(), &w, &h);
int x = (ch - ' ')%16 * texturesize/16;
int y = (ch - ' ')/16 * texturesize/16;
x += texturesize/32 - w/2;
y += texturesize/32 - h/2;
SDL_Rect result = { x, y, w, h };
return result;
}
/******************************************************************************/
SDL_Surface* CreateBMFSurface(TTF_Font* font, int texsize, bool solid, bool extAscii) {
int texheight = extAscii ? texsize : texsize / 2;
// Create the texture surface
SDL_Surface *texture = SDL_CreateRGBSurface(
SDL_SWSURFACE,
texsize,
texheight,
24,
0x000000ff,
0x0000ff00,
0x00ff0000,
0x00000000
);
if ( texture == NULL ) {
cout << "Error creating texture surface" << endl;
return NULL;
}
int numChars = extAscii ? 256 : 128;
// loop through all characters from 32 to 127
for( int ch = 32; ch < numChars; ch++ ) {
SDL_Color fg = { 255, 255, 255, 0 };
char text[2] = { (char)ch, 0 };
SDL_Surface *glyph;
if ( solid ) {
glyph = TTF_RenderText_Solid(font, text, fg);
} else {
glyph = TTF_RenderText_Blended(font, text, fg);
}
// Calculate the blit position
SDL_Rect blitpos = CalculateBlitPos(font, ch, texsize);
// Blit the glyph onto the texture surface
SDL_BlitSurface(glyph, NULL, texture, &blitpos);
SDL_FreeSurface(glyph);
}
return texture;
}
/******************************************************************************/
/*
* Return the pixel value at (x, y)
* NOTE: The surface must be locked before calling this!
*/
Uint32 getpixel(SDL_Surface *surface, int x, int y)
{
int bpp = surface->format->BytesPerPixel;
/* Here p is the address to the pixel we want to retrieve */
Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
switch(bpp) {
case 1:
return *p;
case 2:
return *(Uint16 *)p;
case 3:
//if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
if ( !hostIsLittleEndian() )
return p[0] << 16 | p[1] << 8 | p[2];
else
return p[0] | p[1] << 8 | p[2] << 16;
case 4:
return *(Uint32 *)p;
default:
return 0; /* shouldn't happen, but avoids warnings */
}
}
/******************************************************************************/
int encode_rle(Uint8* dest, Uint8* src, int src_size) {
int src_idx;
int dest_idx = 0;
Uint8 count = 0;
Uint8 value = src[0];
for ( src_idx = 0 ; src_idx < src_size; src_idx++ ) {
if ( src[src_idx] == value && count < 0xFF ) {
count++;
} else {
dest[dest_idx++] = count; count = 1;
dest[dest_idx++] = value; value = src[src_idx];
}
}
return dest_idx;
}
/******************************************************************************/
bool SaveAsBMF(SDL_Surface* texture, TTF_Font* font, int ptsize, const string& filename, bool extAscii) {
#pragma pack(push,1)
struct Header {
Uint32 ident;
Uint16 version;
} header;
struct FontMetrics {
Uint8 ptsize;
Uint8 style;
Uint8 height;
Uint8 ascent;
Sint8 descent;
Uint8 lineskip;
} font_metrics;
int gw_size = extAscii ? 224 : 96;
Uint8 *glyph_width = new Uint8 [gw_size];
#pragma pack(pop)
header.ident = 0x20464D42; // "BMF "
header.version = extAscii ? 0x0101 : 0x0100; // v1.01 for files with extended characters
font_metrics.ptsize = ptsize;
font_metrics.style = TTF_GetFontStyle(font);
font_metrics.height = TTF_FontHeight(font);
font_metrics.ascent = TTF_FontAscent(font);
font_metrics.descent = TTF_FontDescent(font);
font_metrics.lineskip = TTF_FontLineSkip(font);
int numChars = extAscii ? 256 : 128;
for( int i = 32; i < numChars; i++ ) {
int w, h;
char text[2] = { (char)i, 0 };
TTF_SizeText(font, text, &w, &h);
glyph_width[i - 32] = w;
}
ofstream file(filename.c_str(), ios::out | ios::binary);
if ( !file ) {
delete [] glyph_width;
return false;
}
// get the pixel data to be stored to disk
int datacount = texture->w * (extAscii ? texture->w : texture->w/2);
Uint8 *data = new Uint8[datacount];
for ( int i = 0; i < datacount; i++ ) {
Uint32 color = getpixel(texture, i % texture->w, i / texture->w);
// since the texture is a grayscale image it is not important which color
// component is stored
data[i] = color & 0x000000FF;
}
// allocate memory to hold the rle compressed data
// (datacount bytes should always be enough)
Uint8* rle_data = new Uint8[datacount];
// encode the image
datacount = encode_rle(rle_data, data, datacount);
// account for big endian machines: swap the bytes in shorts and ints
header.ident = swap32(header.ident);
header.version = swap16(header.version);
file.write((char*)&header, sizeof(header));
file.write((char*)&font_metrics, sizeof(font_metrics));
file.write((char*)glyph_width, extAscii ? 224 : 96);
int w = swap32(texture->w);
file.write((char*)&w, sizeof(w));
int dc = swap32(datacount);
file.write((char*)&dc, sizeof(dc));
file.write((char*)rle_data, datacount);
delete [] glyph_width;
delete [] data;
delete [] rle_data;
file.close();
return true;
}
/******************************************************************************/
int main(int argc, char *argv[] ) {
CmdLineArgs cmdargs;
// Check the command line arguments
if ( !GetArgs(argc, argv, &cmdargs) ) {
// print usage
return 1;
}
// Initialize SDL and SDL_ttf
TTF_Init();
SDL_Init(SDL_INIT_VIDEO);
// Not even needed to set a video mode
//SDL_Surface *screen = SDL_SetVideoMode(640, 480, 32, SDL_SWSURFACE);
// Load the font
TTF_Font *font = TTF_OpenFont( cmdargs.fontname.c_str(), PTSIZE(cmdargs.ptsize));
if ( !font ) {
cout << "Error loading font" << endl;
return 1;
}
// Set the font style
{
int style = 0;
if ( cmdargs.bold ) style |= TTF_STYLE_BOLD;
if ( cmdargs.italic ) style |= TTF_STYLE_ITALIC;
if ( cmdargs.underline ) style |= TTF_STYLE_UNDERLINE;
TTF_SetFontStyle(font, style);
}
// Create the texture surface
SDL_Surface *texture = CreateBMFSurface(font, cmdargs.texturesize, cmdargs.solid, cmdargs.useExtendedCharset);
// Save the generated texture as a .bmf file
{
string fname = cmdargs.fontname.substr(0, cmdargs.fontname.rfind('.')) + ".bmf";
if ( !SaveAsBMF(texture, font, cmdargs.ptsize, fname, cmdargs.useExtendedCharset) ) {
cout << "Error saving .bmf file" << endl;
}
}
if ( cmdargs.grid ) {
DrawGrid(texture);
}
if ( cmdargs.bmp ) {
string fname = cmdargs.fontname.substr(0, cmdargs.fontname.rfind('.')) + ".bmp";
SDL_SaveBMP(texture, fname.c_str());
}
// clean up
SDL_Quit();
TTF_CloseFont(font);
TTF_Quit();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -