Last active
December 13, 2016 13:48
-
-
Save voidproc/84a2e3d64c4575cae11692a0ff2ef814 to your computer and use it in GitHub Desktop.
Output a sprite sheet of font
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// * config.iniの設定に従いスプライトフォント画像を生成する | |
// * 画像出力後、画像を表示する | |
// * Zキー、Xキーでズームイン・ズームアウト | |
// | |
// * "config.ini"の各項目の説明: | |
// | |
// fontname = 美咲ゴシック フォント名 | |
// fontsize = 4 フォントサイズ | |
// texture_width = 512 出力画像のサイズ | |
// texture_height = 512 〃 | |
// box_width = 8 1文字分の枠のサイズ(box_autosize=1の場合) | |
// box_height = 8 〃 | |
// box_autosize = 0 1文字分の枠のサイズを自動計算する(0 or 1) | |
// shadow_x = 1 影のオフセット | |
// shadow_y = 1 〃 | |
// shadow_color = 96 影の色 | |
// transparent = 1 背景を透明化する(0 or 1) | |
// outname = chars_misakifont 出力ファイル名(.png, .bin) | |
#include <Siv3D.hpp> | |
#include <unordered_map> | |
#if 0 | |
class ImageFont | |
{ | |
public: | |
ImageFont(const FilePath& image, const FilePath& settings) : tex_(image) | |
{ | |
BinaryReader reader(settings); | |
reader.read(w_); | |
reader.read(h_); | |
int l; | |
reader.read(l); | |
for (int i : step(l)) | |
{ | |
wchar c; | |
reader.read(c); | |
Point p; | |
reader.read(p); | |
charPos_[c] = p; | |
} | |
} | |
void draw(const String& text, const Vec2& pos, const Color& color = Palette::White, const double& scale = 1.0) | |
{ | |
int i = 0; | |
for (auto c : text) | |
{ | |
tex_(charPos_[c], w_, h_).scale(scale).draw(pos.x + i * w_ * scale, pos.y, color); | |
++i; | |
} | |
} | |
private: | |
int w_; | |
int h_; | |
const Texture tex_; | |
std::unordered_map<wchar, Point> charPos_; | |
}; | |
#endif | |
String printableChars0_255() | |
{ | |
String s(256, L' '); | |
for (auto i : step(s.length)) | |
{ | |
if (IsPrint(i)) | |
{ | |
s[i] = wchar_t(i); | |
} | |
} | |
return s; | |
} | |
void Main() | |
{ | |
// 設定 | |
struct Config | |
{ | |
String fontname; | |
int fontsize; | |
uint32 texture_width; | |
uint32 texture_height; | |
int box_width; | |
int box_height; | |
int box_autosize; // bool | |
int shadow_x; | |
int shadow_y; | |
int shadow_color; | |
int transparent; // bool | |
String outname; // bool | |
int window_width; | |
int window_height; | |
}; | |
Config config; | |
INIReader ini(L"config.ini"); | |
config.fontname = ini.getOr<String>(L"fontname", L"美咲ゴシック").trim(); | |
config.fontsize = ini.getOr<int>(L"fontsize", 4); | |
config.texture_width = ini.getOr<uint32>(L"texture_width", 512); | |
config.texture_height = ini.getOr<uint32>(L"texture_height", 512); | |
config.box_width = ini.getOr<int>(L"box_width", 0); | |
config.box_height = ini.getOr<int>(L"box_height", 0); | |
config.box_autosize = ini.getOr<int>(L"box_autosize", 0); | |
config.shadow_x = ini.getOr<int>(L"shadow_x", 0); | |
config.shadow_y = ini.getOr<int>(L"shadow_y", 0); | |
config.shadow_color = ini.getOr<int>(L"shadow_color", 128); | |
config.transparent = ini.getOr<int>(L"transparent", 0); | |
config.outname = ini.getOr<String>(L"outname", L"out"); | |
config.window_width = ini.getOr<int>(L"window_width", 1024); | |
config.window_height = ini.getOr<int>(L"window_height", 768); | |
ini.close(); | |
Window::Resize(config.window_width, config.window_height); | |
Graphics::SetBackground(Color(20, 60, 20)); | |
Graphics2D::SetSamplerState(SamplerState::ClampPoint); | |
// テキスト描画先テクスチャ | |
RenderTexture rt { config.texture_width, config.texture_height, Palette::Black }; | |
Graphics2D::SetRenderTarget(rt); | |
// 描画フォント | |
const Font font(config.fontsize, config.fontname, FontStyle::Bitmap); | |
// 描画する文字 | |
const String chars = printableChars0_255() + TextReader(L"chars.txt").readAll(); | |
// 文字の横幅の最大値を知りたい | |
int maxWidth = 0; | |
for (auto c : chars) | |
{ | |
maxWidth = Max(font(c).region().w, maxWidth); | |
} | |
// 文字の縦幅 | |
int maxHeight = font.height; | |
// 1文字あたりの枠 (box) の大きさ | |
const int box_width = config.box_autosize ? maxWidth + config.shadow_x : config.box_width; | |
const int box_height = config.box_autosize ? font.height + config.shadow_y : config.box_height; | |
// テクスチャへ描画できる横方向の文字数 | |
const int nCharsX = rt.width / box_width; | |
// 文字の描画位置保存用 | |
std::unordered_map<wchar, Point> charPos; | |
// テクスチャ rt へテキスト描画 | |
int i = 0; | |
for (auto c : chars) | |
{ | |
// 文字の描画位置 | |
const int x = (i % nCharsX) * box_width; | |
const int y = (i / nCharsX) * box_height; | |
// 文字を描画 | |
// 横位置は枠の中央 | |
const int sx = x + (Max(0, ((box_width - config.shadow_x) - font(c).region().w)) + 0.5) / 2 + config.shadow_x; | |
font(c).draw(sx, y + config.shadow_y, Color(config.shadow_color)); //影 | |
font(c).draw(sx - config.shadow_x, y, Color(254)); | |
charPos[c] = Point(x, y); | |
++i; | |
} | |
Graphics2D::SetRenderTarget(Graphics::GetSwapChainTexture()); | |
// テクスチャをファイル出力 | |
Graphics::Render2D(); | |
rt.saveDDS(config.outname + L".dds"); | |
rt.release(); | |
// 背景色の透明化 | |
Image img(config.outname + L".dds"); | |
if (config.transparent) | |
{ | |
img.forEach([](auto& c) { | |
if (c == Palette::Black) | |
c.a = 0; | |
}); | |
} | |
img.savePNG(config.outname + L".png"); | |
const Texture tex(img); | |
img.release(); | |
// 文字の描画位置などを保存する | |
BinaryWriter writer(config.outname + L".bin"); | |
writer.write(box_width); | |
writer.write(box_height); | |
writer.write(chars.length); | |
for (auto c : chars) | |
{ | |
writer.write(c); | |
writer.write(charPos[c]); | |
} | |
writer.flush(); | |
writer.close(); | |
int scale = 1; | |
while (System::Update()) | |
{ | |
if (Input::KeyZ.clicked) | |
scale = Min(4, scale + 1); | |
if (Input::KeyX.clicked) | |
scale = Max(1, scale - 1); | |
tex.scale(scale).draw().drawFrame(1.0, 0.0, Color(Palette::Lime, 128)); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment