画像ファイルを読み込んでテクスチャーを表示するように修正します。
プログラムはこちらで公開しています。
https://github.com/matsushima-terunao/opengl_sample
参考サイト
https://learnopengl.com/In-Practice/Text-Rendering
FreeType の環境設定
こちらで FreeType の環境設定を行ってください。
https://mappuri.com/program/freetype-settings/
テキスト描画準備
文字イメージセット用のテクスチャーを用意し、各文字のイメージを書き込みます。また、各文字の座標を取得します。
また、テキスト描画用のバッファ作成します。
/**
* テキスト描画初期化。
*/
int init_render_text() {
// 文字イメージセット描画用テクスチャー準備
glEnable(GL_CULL_FACE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// シェーダー作成。
program = glCreateProgram();
create_shader("text vertex shader", program, GL_VERTEX_SHADER, &text_vertex_shader);
create_shader("text fragment shader", program, GL_FRAGMENT_SHADER, &text_fragment_shader);
glLinkProgram(program);
glUseProgram(program);
// 透視設定
mat4x4 projection;
mat4x4_ortho(projection, 0.0f, static_cast<float>(SCR_WIDTH), 0.0f, static_cast<float>(SCR_HEIGHT), 1.f, -100.f);
glUniformMatrix4fv(glGetUniformLocation(program, "projection"), 1, GL_FALSE, (const GLfloat*)projection);
// テクスチャー作成
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // disable byte-alignment restriction
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, ch_width * ch_count, ch_width, 0, GL_RED, GL_UNSIGNED_BYTE, NULL);
// FreeType 初期化
FT_Error ft_error;
ft_error = FT_Init_FreeType(&ft);
assert(!ft_error && "init_resources: FT_Init_FreeType();");
std::string font_name = "assets/font/FreeSans.ttf";
ft_error = FT_New_Face(ft, font_name.c_str(), 0, &face);
assert(!ft_error && "init_resources: FT_New_Face();");
FT_Set_Pixel_Sizes(face, 0, ch_width);
// 文字ごとのイメージ書き込み
for (unsigned char c = 0; c < ch_count; ++c) {
ft_error = FT_Load_Char(face, c, FT_LOAD_RENDER);
if (ft_error) {
assert(!ft_error && "init_resources: FT_LOAD_RENDER();");
continue;
}
// 文字イメージをテクスチャーに書き込み
if (face->glyph->bitmap.width > 0) {
glTexSubImage2D(GL_TEXTURE_2D, 0, c * ch_width, 0, face->glyph->bitmap.width, face->glyph->bitmap.rows,
GL_RED, GL_UNSIGNED_BYTE, face->glyph->bitmap.buffer);
}
// 文字座標取得
character_textures[c] = {
face->glyph->bitmap_left, face->glyph->bitmap_top,
(int)face->glyph->bitmap.width, (int)face->glyph->bitmap.rows,
(int)face->glyph->advance.x,
};
}
// 文字イメージセット描画終了
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
FT_Done_Face(face);
FT_Done_FreeType(ft);
// テキスト描画用バッファ作成
glGenVertexArrays(1, &vertex_array);
glGenBuffers(1, &vertex_object);
glBindVertexArray(vertex_array);
glBindBuffer(GL_ARRAY_BUFFER, vertex_object);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6 * 4 * str_length, NULL, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
return 0;
}
テキスト描画
文字イメージセットが描画されたテクスチャーから、各文字のイメージを切り出したポリゴンを作成します。
/**
* テキスト描画。
*/
float render_text(const char* text, float x, float y, float scale, float color[3], bool proportional) {
// テキスト描画用バッファ準備
glUseProgram(program);
glUniform3f(glGetUniformLocation(program, "texture_color"), color[0], color[1], color[2]);
glActiveTexture(GL_TEXTURE0);
glBindVertexArray(vertex_array);
// テキストポリゴン配列準備
char* vertices_buf = new char[strlen(text) * 4 * 24];
int i;
for (i = 0; i < str_length && '\0' != text[i]; ++i) {
// テクスチャー切り出し
character_rectangle_info& ch = character_textures[text[i]];
float xpos = x + ch.x * scale;
float ypos = y - (ch.h - ch.y) * scale;
float w = ch.w * scale;
float h = ch.h * scale * 1.5f;
float u = 1.0f / ch_count * text[i];
float uw = (float)ch.w / ch_width / ch_count;
float uh = (float)ch.h / ch_width;
if (!proportional) {
xpos += (ch_width * scale - w) / 2;
}
float vertices[6][4] = {
{ xpos, ypos + h, u, 0.0f }, // 0
{ xpos, ypos, u, uh },
{ xpos + w, ypos, u + uw, uh },
{ xpos, ypos + h, u, 0.0f }, // 1
{ xpos + w, ypos, u + uw, uh },
{ xpos + w, ypos + h, u + uw, 0.0f },
};
// ポリゴン追加
memcpy(vertices_buf + i * sizeof(vertices), vertices, sizeof(vertices));
x += proportional ? (ch.advance_x >> 6) * scale : ch_width * scale / 1.5f;
}
// ポリゴン描画
glBindTexture(GL_TEXTURE_2D, texture);
glBindBuffer(GL_ARRAY_BUFFER, vertex_object);
glBufferSubData(GL_ARRAY_BUFFER, 0, i * 6ull * 4 * sizeof(float), vertices_buf); // be sure to use glBufferSubData and not glBufferData
glBindBuffer(GL_ARRAY_BUFFER, 0);
glDrawArrays(GL_TRIANGLES, 0, 6 * i);
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
delete[] vertices_buf;
return x;
}
パネル表示
現在の状態と設定変更ができるパネルを表示します。
1,2行目は FPS と1フレーム当たりの秒数で、それぞれ平均、平均(CPU 使用率換算)、経過、直近1フレーム、直近1フレーム(CPU 使用率換算)です。
3行目以降は設定表示で、選択パラメーターは上下左右でカーソル移動し、Enter キーで決定です。数値パラメーターは Enter で赤色にしてから上下左右で数値変更し、再度 Enter キーで決定です。
コメント