質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.49%

openglでtextureatlasをつかったフォント表示

受付中

回答 0

投稿

  • 評価
  • クリップ 0
  • VIEW 1,162

score 72

いつもありがとうございます!!お世話になります!

参考サイト

リンク1 / リンク2 / リンク3

したいこと

テクスチャアトラスをつくってフォント表示をしたい。
(リンク1のやりかたではフォント表示できました。)

わからないこと

・リンク3でglTexImage2D()をもう一度呼べばテクスチャのサイズ変更可能とありますが、
const GLvoid * dataは何を指定すればいいですか?

void glTexImage2D(Lenum target,GLint level,GLint internalformat,GLsizei width,GLsizei height,GLint border,GLenum format,GLenum type,const GLvoid * data);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, w, h, 0, GL_RED, GL_UNSIGNED_BYTE, 0);

・char16_t* の文字数の取得はどうやってしますか?

コード
#pragma once
#include <ft2build.h>
#include FT_FREETYPE_H
#include <cstdlib>
#include <iostream>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <vector>
#include <windows.h>
#include <map>
#include <string.h>

class Font
{
      struct character_info {
            float ax; // advance.x
            float ay; // advance.y

            float bw; // bitmap.width;
            float bh; // bitmap.rows;

            float bl; // bitmap_left;
            float bt; // bitmap_top;

            float tx; // x offset of glyph in texture coordinates
      } ;

public:
      FT_Library library;
      FT_Face face;
      FT_GlyphSlot g;
      FT_GlyphSlot slot;

      GLuint tex;
      GLuint vao;
      GLuint vbo;

      BYTE *font_buff = NULL;
      //文字の最長の高さ
      int h = 0;
      //文字列の長さ
      int w = 0;
      std::map<char16_t, character_info> font_data;

      Font(const GLuint program)
      {
            Init(program);
      }

      int Init(const GLuint program)
      {
            if (FT_Init_FreeType(&library))
            {
                  std::cout << "Could not init freetype library\n";
                  return 1;
            }

            LOGFONT lf;
            ZeroMemory(&lf, sizeof(lf));
            CHOOSEFONT cf;
            ZeroMemory(&cf, sizeof(cf));
            cf.lStructSize = sizeof(cf);
            cf.Flags = 0;
            cf.lpLogFont = &lf;
            // とりあえず、適当なフォントを選ぶ。
            if (!ChooseFont(&cf)) {
                  return 1;
            }
            HFONT font_h = CreateFontIndirect(&lf);
            if (font_h == NULL) {
                  std::fprintf(stderr, "%s(%d): failed to load font.\n", __FILE__, __LINE__);
                  return 1;
            }
            HDC dc_h = GetDC(NULL);
            HGDIOBJ old_font_h = SelectObject(dc_h, font_h);
            DWORD cb = GetFontData(dc_h, 0x66637474, 0, NULL, 0);
            if (cb != 0 && cb != GDI_ERROR) {
                  // これなら、TTC
                  font_buff = new BYTE[cb];
                  GetFontData(dc_h, 0x66637474, 0, font_buff, cb);
            }
            else {
                  // TTFとして読んでみる。
                  cb = GetFontData(dc_h, 0, 0, NULL, 0);
                  if (cb == 0 || cb == GDI_ERROR) {
                        std::fprintf(stderr, "%s(%d): failed to load font.\n", __FILE__, __LINE__);
                        return 1;
                  }
                  font_buff = new BYTE[cb];
                  GetFontData(dc_h, 0, 0, font_buff, cb);
            }
            if (FT_New_Memory_Face(library, font_buff, cb, 0, &face) != 0) {
                  std::fprintf(stderr, "%s(%d): failed to load font.\n", __FILE__, __LINE__);
                  return 1;
            }

            DeleteObject(SelectObject(dc_h, old_font_h));
            ReleaseDC(NULL, dc_h);

            g = face->glyph;

            FT_Set_Pixel_Sizes(face, 0, 48);

            glGenVertexArrays(1, &vao);
            glBindVertexArray(vao);

            glEnable(GL_BLEND);
            glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

            glActiveTexture(GL_TEXTURE0);
            glGenTextures(1, &tex);
            glBindTexture(GL_TEXTURE_2D, tex);
            int uniform_tex = glGetUniformLocation(program, "tex");
            glUniform1i(uniform_tex, 0);

            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);

            glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

            glGenBuffers(1, &vbo);
            int attribute_coord = glGetAttribLocation(program, "coord");
            glEnableVertexAttribArray(attribute_coord);
            glBindBuffer(GL_ARRAY_BUFFER, vbo);
            glVertexAttribPointer(attribute_coord, 4, GL_FLOAT, GL_FALSE, 0, 0);
      }

      void render_text(const char16_t *text, float x, float y, float sx, float sy) {
            struct point {
                  GLfloat x;
                  GLfloat y;
                  GLfloat s;
                  GLfloat t;
            } coords[6 * 5];

            //頂点数
            int n = 0;

            for (const char16_t *p = text; *p != '\0'; ++p) {

                  //初めての文字だったら
                  if (font_data.end() == font_data.find(*p))
                  {
                        if (FT_Load_Glyph(face, FT_Get_Char_Index(face, *p), FT_LOAD_RENDER))
                              continue;
                        //文字の書き始め
                        font_data[*p].tx = (float)w;

                        w += g->bitmap.width;
                        h = Int_max(h, g->bitmap.rows);

                        font_data[*p].ax = g->advance.x >> 6;
                        font_data[*p].ay = g->advance.y >> 6;

                        font_data[*p].bw = g->bitmap.width;
                        font_data[*p].bh = g->bitmap.rows;

                        font_data[*p].bl = g->bitmap_left;
                        font_data[*p].bt = g->bitmap_top;

                        glBindTexture(GL_TEXTURE_2D, tex);


                        glTexImage2D(
                              GL_TEXTURE_2D,
                              0,
                              GL_RED,
                              w,
                              h,
                              0,
                              GL_RED,
                              GL_UNSIGNED_BYTE,
                              0
                        );

                        glTexSubImage2D(
                              GL_TEXTURE_2D,
                              0,
                              font_data[*p].tx,
                              0,
                              g->bitmap.width,
                              g->bitmap.rows,
                              GL_ALPHA,
                              GL_UNSIGNED_BYTE,
                              g->bitmap.buffer
                        );
                  }

                  //描画座標
                  float x2 = x + font_data[*p].bl * sx;
                  float y2 = y + font_data[*p].bt * sy;
                  float w = font_data[*p].bw * sx;
                  float h = font_data[*p].bh * sy;

                  x += font_data[*p].ax * sx;
                  y += font_data[*p].ay * sy;

                  if (!w || !h)
                        continue;

                  /* coords[n++] =  { x2       ,     y2      , font_data[*p].tx / w                                   , 0 };
                   coords[n++] =  { x2 + w,     y2      , font_data[*p].tx / w + font_data[*p].bw / w, 0 };
                   coords[n++] =  { x2       ,     y2 - h , font_data[*p].tx / w                                   , font_data[*p].bh / h };
                   coords[n++] =  { x2 + w,     y2      , font_data[*p].tx / w + font_data[*p].bw / w, 0 };
                   coords[n++] =  { x2       ,     y2 - h , font_data[*p].tx / w                                   , font_data[*p].bh / h };
                   coords[n++] =  { x2 + w,     y2 - h , font_data[*p].tx / w + font_data[*p].bw / w, font_data[*p].bh / h };*/

                  coords[n++] = { x2       ,     y2      , font_data[*p].tx / w                                   , 0 };
                  coords[n++] = { x2       ,     y2 - h , font_data[*p].tx / w                                   , font_data[*p].bh / h };
                  coords[n++] = { x2 + w,     y2      , font_data[*p].tx / w + font_data[*p].bw / w, 0 };
                  coords[n++] = { x2 + w,     y2      , font_data[*p].tx / w + font_data[*p].bw / w, 0 };
                  coords[n++] = { x2       ,     y2 - h , font_data[*p].tx / w                                   , font_data[*p].bh / h };
                  coords[n++] = { x2 + w,     y2 - h , font_data[*p].tx / w + font_data[*p].bw / w, font_data[*p].bh / h };
            }
            glBindBuffer(GL_ARRAY_BUFFER, vbo);
            glBufferData(GL_ARRAY_BUFFER, sizeof coords, coords, GL_DYNAMIC_DRAW);
            glBindVertexArray(vao);
            glDrawArrays(GL_TRIANGLES, 0, n);
      }

      void display(const GLuint program, GLFWwindow *const window)
      {
            glClearColor(1, 1, 1, 1);
            glClear(GL_COLOR_BUFFER_BIT);
            GLfloat black[4] = { 0, 0, 0, 1 };
            int uniform_color = glGetUniformLocation(program, "color");
            glUniform4fv(uniform_color, 1, black);

            float sx = (2.0 / 640) * 0.5;
            float sy = (2.0 / 480) * 0.5;

            render_text(u"フォントの",
                  -1 + 8 * sx, 1 - 50 * sy, sx, sy);
            render_text(u"openg",
                  -1 + 8.5 * sx, 1 - 100.5 * sy, sx, sy);

            glfwSwapBuffers(window);
            glfwPollEvents();
      }

      virtual ~Font()
      {
            glDeleteBuffers(1, &vao);
            glDeleteBuffers(1, &vbo);
            glDeleteBuffers(1, &tex);
            FT_Done_Face(face);
            delete[] font_buff;
      }

      static int Int_max(int x, int y)
      {
            if (x < y)
            {
                  return y;
            }
            else {
                  return x;
            }
      }

      static int Char16_Length(const char16_t *text)
      {
            size_t size = sizeof(text) / sizeof(text);

            size_t length = size;
            char16_t c = 0;

            for (int i = 0; i < size; ++i) {
                  c = text[i];

                  if ((c > 0xD800) && (0xDC00 > c)) {
                        --length;
                  }
            }
            return length;
      }
};
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

まだ回答がついていません

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.49%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る