FreeType Zeichen positionieren

Für Fragen zu Grafik APIs wie DirectX und OpenGL sowie Shaderprogrammierung.
Antworten
alexander_ro
Beiträge: 19
Registriert: 14.03.2005, 08:48

FreeType Zeichen positionieren

Beitrag von alexander_ro »

Hallo Mädels ... Jungs ... :-)

ich versuche gerade eine C++ Klasse zu bauen die Texte ausgeben kann und so ähnlich funktioniert wie std::cout nur halt für 3D Programme.

Ich benutze OpenGL aber ohne X11. Womit ich Probleme habe ist die Zeilenabstände richtig zu berechnen. Mir ist irgendwie nicht ganz klar wie man das richtig macht. Die Freetype Dokumentation ist da ein bisschen verwirrend vielleicht liegt es auch an meinen nicht zu guten Übersetzungsfähigkeiten.

Meine Klasse kann zwar Buchstaben neben einander ausgeben aber Buchstaben aus mehreren Zeilen werden wenn es hohe sind übereinander geschrieben.
So sieht die Klasse im Moment aus:

Code: Alles auswählen

class cout3D
{
public:
  FT_Face face;

  cout3D (std::string strFont, float fXPos = -1, float fYPos = 1) : fIntXPos (fXPos), fIntYPos (fYPos)
  {
    FT_Library idFreeType;

    if (FT_Init_FreeType (&idFreeType))
    {
      std::cout << "Initialisierung von FreeType nicht möglich" << std::endl;
      exit (0);
    }

    if (FT_New_Face (idFreeType, strFont.c_str (), 0, &face))
    {
      std::cout << "Font konnte nicht geöffnet werden." << std::endl;
      exit (0);
    }

    FT_Set_Char_Size( face, 50 * 64, 0, 100, 0);

  // Skalierungsfaktoren für die Umrechnung von Pixelkoordinaten in OpenGL Koordinaten
    fIntSx = 2.0 / lcdDisplay.width;  // Bildschirm Auflösung X (liefert DRM)
    fIntSy = 2.0 / lcdDisplay.height; // Bildschirm Auflösung Y (liefert DRM)
  }


  void setCursor (float fXPos, float fYPos)
  {
    fIntXPos = fXPos;
    fIntYPos = fYPos - ((face->glyph->metrics.horiAdvance / 64) * fIntSy);
  }




  cout3D operator<< (std::string strText)
  {
    for (const char &i : strText)
    {
      this->loadChar (i);

      glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
      GLuint tex;
      glGenTextures (1, &tex);
      glBindTexture (GL_TEXTURE_2D, tex);
      glTexImage2D (GL_TEXTURE_2D, 0, GL_ALPHA, face->glyph->bitmap.width, face->glyph->bitmap.rows, 0, GL_ALPHA, GL_UNSIGNED_BYTE, face->glyph->bitmap.buffer);

      glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR);
      glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR);

      GLint texLoc = glGetUniformLocation(gl.program, "myTexture");
      glActiveTexture (GL_TEXTURE0);
      glUniform1i (texLoc, 0);

    // Berechne den Umrechnungsfaktor für Pixelbilder
      fIntSx = 2.0 / lcdDisplay.width;  // Alien Bildschirm Auflösung X (liefert DRM)
      fIntSy = 2.0 / lcdDisplay.height; // Alien Bildschirm Auflösung Y (liefert DRM)

    // glWidth und glHeight soll die für OpenGL umgerechnete Pixel größe des Zeichens sein.
      GLfloat glWidth  = face->glyph->bitmap.width * fIntSx;
      GLfloat glHeight = face->glyph->bitmap.rows  * fIntSy;

    // x, y, z, w (w = 1 vertex, w = 0 transformation)
      GLfloat vertices[] = { 0.0    , 0.0      , 0.0, 1.0,    // links oben
                             glWidth, 0.0      , 0.0, 1.0,    // rechts oben
                             glWidth, -glHeight, 0.0, 1.0,    // recht unten
                             0.0    , -glHeight, 0.0, 1.0 };  // links unten

    // Vertex Daten an den Shader übergeben und die Art der Daten beschreiben.
      glEnableVertexAttribArray (0);     // Die 0 wird im Shader an die layout Variable übergeben.
      glVertexAttribPointer (0, 4, GL_FLOAT, GL_FALSE, 0, vertices);

    // UV-Koordinaten an den Shader übergeben zur Positionierung der Textur
    // X = U, Y = V
      GLfloat uvCoords[] = { 0.0, 0.0,   // links oben
                             1.0, 0.0,   // rechts oben
                             1.0, 1.0,   // rechts unten
                             0.0, 1.0 }; // links unten

      glEnableVertexAttribArray (1); // Die 1 wird im Shader an die ??? Variable übergeben.
      glVertexAttribPointer (1, 2, GL_FLOAT, GL_FALSE, 0, uvCoords);

    // fIntYPos je nach höhe des Zeichens anpassen.
      GLfloat yAnpassung = 0;
      if (face->glyph->bitmap_top != 50)
      {
        yAnpassung = (50 - face->glyph->bitmap_top) * fIntSy;
        std::cout << i << " yAnpassung: " << yAnpassung << std::endl;
      }

    // Erzeuge die Transformationsmatrix um den Buchstaben endgültig zu positionieren.
      GLfloat transMatrix[] = { 1.0, 0.0, 0.0,  fIntXPos,                // X
                                0.0, 1.0, 0.0,  fIntYPos - yAnpassung,   // Y
                                0.0, 0.0, 1.0,  0.00,                    // Z
                                0.0, 0.0, 0.0,  1.00 };                  // Richtung

      fIntXPos = fIntXPos + (face->glyph->metrics.horiAdvance / 64 * fIntSx);

      GLint idTransMatrix = glGetUniformLocation(gl.program, "transMatrix");
      std::cout << idTransMatrix << std::endl;
      glUniformMatrix4fv (idTransMatrix, 1, GL_FALSE, transMatrix);

    // Bitmap des Buchstabens ausgeben.
      glDrawArrays (GL_TRIANGLE_FAN, 0, 4);
    }
  }

private:
// Skalierungsfaktoren für die Umrechnung von Pixelkoordinaten in OpenGL Koordinaten.
  float fIntSx;
  float fIntSy;

// Aktuelle Schreibposition in OpenGL Koordinaten
  float fIntXPos;
  float fIntYPos;

  void loadChar (char cZeichen)
  {
    if (FT_Load_Char (face, cZeichen, FT_LOAD_RENDER))
    {
      std::cout << "Zeichen konnte nicht geladen werden." << std::endl;
      exit (0);
    }
  }
};
In den Zeichnungen und Beschreibungen bei FreeType sieht man das die Zeichen auf die Baseline mit diesem Orgin Punkt ausgerichtet werden und dann um "advance width" der Cursor weiter verschoben werden soll. Leider findet man die genannten Wert in den Metrics des Zeichens nicht so einfach. Ich habe schon diverse verschiedene Arten versucht diese zu berechnen aber irgendwie hat keine Zuverlässig funktioniert. Wie man einen Zeilen Abstand berechnet habe ich in der Dokumentation nicht gefunden. Vielleicht hat ja einer von euch einen Vorschlag wie man das richtig macht ... :-)

Grüße
Alexander
Benutzeravatar
Schrompf
Moderator
Beiträge: 5047
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas
Wohnort: Dresden
Kontaktdaten:

Re: FreeType Zeichen positionieren

Beitrag von Schrompf »

Hab mal in meinem alten Code nachgeschaut - ich nehme als Zeilenhöhe die Sollhöhe in Pixeln, die ich ihm vorher mit FT_Set_Pixel_Sizes() übergeholfen habe, als ich den Font in einen Texturatlas ausgerendert habe.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
alexander_ro
Beiträge: 19
Registriert: 14.03.2005, 08:48

Re: FreeType Zeichen positionieren

Beitrag von alexander_ro »

Gute Idee das sieht dann schon viel besser aus. Man sieht zwar noch das fehlende Kerning weil die Zeichenabstände ein bisschen Merkwürdig sind aber es wird nichts mehr übereinander geschrieben.

Ich habe da diese Funktion benutzt wie in dem Beispiel auf der FreeType Seite. Kann man aus diesen Punkten die man der FT_Set_Char_Size Funktion übergibt auch die Pixel berechnen. Oder ist es besser wenn man gleich die größe in Pixel angibt. Dann muss man ja auch keine DPI mehr angeben weil sich die ja dann aus dem verwendeten Display ergeben.

Code: Alles auswählen

FT_Set_Char_Size(face, 50 * 64, 0, 100, 0);
Das ist auf jeden Fall eine andere Schriftgröße als mit den Werten oben. Ich dachte eigentlich das die 50 die Pixel größe ist und das dann mit 50*64 die Punktgröße gemeint ist scheint aber nicht so zu sein.

Code: Alles auswählen

FT_Set_Pixel_Sizes(face, 0, 50);
Benutzeravatar
Schrompf
Moderator
Beiträge: 5047
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas
Wohnort: Dresden
Kontaktdaten:

Re: FreeType Zeichen positionieren

Beitrag von Schrompf »

Letzteres mache ich wie gesagt. Aber wie der Glyph dann innerhalb des Bereichs positioniert ist und um wieviel Du voranschreiten musst, steht in FT_Face::glyph, nachdem Du FT_Load_Char() mit dem Glyph Deiner Wahl aufgerufen hast. DIe Angaben in der glyph-Struktur sind dann alle in 64steln.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
alexander_ro
Beiträge: 19
Registriert: 14.03.2005, 08:48

Re: FreeType Zeichen positionieren

Beitrag von alexander_ro »

Das die größen bei den zwei verschiedenen Funktionen (FT_Set_Char_Size, FT_Set_Pixel_Sizes) nicht gleich sind liegt an den 100 dpi die ich da angegeben habe und Set_Pixel_Size benutzt den FreeType Standard Wert mit 72 dpi. Vermutlich können Bildschirme auch nicht mehr darstellen.
alexander_ro
Beiträge: 19
Registriert: 14.03.2005, 08:48

Re: FreeType Zeichen positionieren

Beitrag von alexander_ro »

Wie macht man das eigentlich richtig bei OpenGL. Im Moment weil es zum probieren einfacher war lasse ich jedes mal Freetype das Bitmap neu generieren und übergebe die Textur dann an OpenGL. Wenn man die zwischenspeichern will macht man das dann mit dem Bitmap von FreeType oder sollte man OpenGL die Textur puffern lassen.
Antworten