FreeType & SDL/OpenGl - verschiebung der buchstaben



  • hi,
    ich habe folgendes problem:
    ich lade mit der freetype library ein font und speichere die einzelnen buchstaben in einzelnen opengl texturen ab (256 stück - ascii satz).
    das funktioniert auch alles wunderbar.
    nur leider wird jeder buchstabe an die linke obere ecke der bitmap geschrieben, wodurch alle gleich hoch sind und z.b. die großbustaben nach unten weiter hinausstehen als die kleinbuchstaben. kann mir jemand sagen, wie ich nun die anzahl der pixel die ich den entsprechenden buchstaben verschieben muss (y achse) damit der text richtig angezeigt wird herausfinden kann?

    ich hoffe das war einigermaßen verständlich

    mein code zum laden:

    bool SFont::Load(string font, SVector size)
    {
      if(loaded)
        return true;
    
      FT_Library ftLib;
      int error = FT_Init_FreeType(&ftLib);
    
      if(error != 0)
      {
        return false;
      }
    
      FT_Face face;
    
      if((error = FT_New_Face(ftLib, font.c_str(), 0, &face)) != 0)
      {
        return false;
      }
    
      if((error = FT_Set_Char_Size(face, (long int)size.x*64, (long int)size.y*64, 0, 0)) != 0)
      {
        return false;
      }
    
      for(int i = 0; i < 256; i++)
      {
        FT_Glyph       glyph;
        FT_BitmapGlyph bitmapGlyph;
        FT_Bitmap      bitmap;
    
        if((error = FT_Load_Glyph(face, FT_Get_Char_Index(face, i), FT_LOAD_DEFAULT)) != 0)
        {
          continue;
        }
    
        if((error = FT_Get_Glyph(face->glyph, &glyph)) != 0)
        {
          continue;
        }
    
        if((error = FT_Glyph_To_Bitmap(&glyph, ft_render_mode_normal, 0, 1)) != 0)
        {
          continue;
        }
    
        bitmapGlyph = (FT_BitmapGlyph)glyph;
        bitmap = bitmapGlyph->bitmap;
    
        int width = FindNextValidTexSize(bitmap.width);
        int height = FindNextValidTexSize(bitmap.rows);
    
        GLubyte *data = new GLubyte[2*width*height];
    
        if(data == NULL)
        {
          continue;
        }
    
        for(int w = 0; w < width; w++)
        {
          for(int h = 0; h < height; h++)
          {
    
            data[2*(w+h*width)] = data[2*(w+h*width)+1] = (w >= bitmap.width ||
            h >= bitmap.rows) ? 0 : bitmap.buffer[w+bitmap.width*h];
          }
        }
    
        textures[i] = new STexture();
    
        if(textures[i] != NULL)
        {
          textures[i]->Load(data, width, height, GL_RGBA, GL_LUMINANCE_ALPHA); /*generiert eine textur aus einem GLubyte pointer*/
        }
    
        delete[] data;
    
        sizes[i].x = bitmap.width; //speichert die höhe/breite der einzelnen buchstaben
        sizes[i].y = bitmap.rows;
      }
    
      FT_Done_Face(face);
      FT_Done_FreeType(ftLib);
    
      log.Log(LL_NONE, "Loaded font %s", font.c_str());
    
      loaded = true;
    
      return true;
    }
    

    danke im voraus

    mfg

    ps: ist es normal, dass das leerzeichen "nicht vorhanden ist", d.h. höhe und breite des glyphen = 0 ist? und wie finde ich dann die gewünschte breite heraus? -.- danke sehr



  • vorschlagsweise bastel dir einfach ne eigene Fontlib.

    Ich hab mir eine gebaut, die einfach eine Textur (512 * 512) lädt auf der die einzelnen Buchstaben eines Fonts sind. Dies kann man mit dem LMNopc Bitmap Font Builder relativ simpel machen. Beim Darstellen des Fonts wird dann einfach der entsprechende Teil der Textur dargestellt...

    Ich werd meinen Code nachher mal posten. Allerdings ist der wohl noch verbesserungswürdig..
    Benötigt wird die SDL_Image..



  • wäre auch ne möglichkeit, wollt mit verschiedenen gedanken halt erstma was auf freetype basierendes machen - mal schaun ^^
    thx
    mfg



  • muss nachher dran denken - hab das Ganze irgendwie verschwitzt..



  • Jo, würd' mich auch interesieren, da ich Fonts bei SDL mehr als umständlich finde
    ( irgendwie geil, natürlich, aber dennoch umständlich )



  • DocJunioR schrieb:

    muss nachher dran denken - hab das Ganze irgendwie verschwitzt..

    ja wär nett wenn du da was machen könntest 😃
    danke schonmal



  • soodele, ich geb einfach mal keine garantie, aber b ei mir läufts erstmal.

    Verbesserungswürdig ist die Sache mit dem Blending - looft net so richtig..

    Die Klasse nennt sich Cfont:

    #ifndef CFONT_H
    #define CFONT_H
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #include <SDL/SDL.h>
    #include <SDL/SDL_opengl.h>
    #include <SDL/SDL_image.h>
    #include <gl/glu.h>
    
    class cFont 
    {
        private:
            unsigned int texture,
                         screenw,
                         screenh;
            float        color[4];             
    
        public:
    
            cFont (char *filename, int sX, int sY);
            ~cFont ();
            int setColor (float *c);
            int print(float x, float y, float scale, const char *string);
    };
    #endif
    

    Die Methoden sehen so aus :

    #include "cfont.h"
    
    int cFont::setColor (float *c)
    {
       int i;
       for (i=0; i < 4; i++)   
       {
            color[i] = c[i];
       }
    }
    
    cFont::cFont (char *filename, int sX, int sY)
    {
        SDL_Surface     *image,
                        *bitmap
                        ;
        int             i;
    
        screenw = sX;
        screenh = sY; 
    
        for (i = 0; i < 4; i++)
        {
            color[i] = 1.0;        
        }
    
        /* Wer die SDL_image nicht nutzen möchte, kann 
         *        SDL_LoadBMP(filename); 
         * nutzen. Dann sind nur BMPs als Font möglich
         */
        bitmap = IMG_Load(filename);
        if (!bitmap) 
        {
             fprintf(stderr, "%s: konnte nicht geladen werden\n", filename);
             exit(1);
        }
        image = SDL_CreateRGBSurface(SDL_SWSURFACE, bitmap->w, bitmap->h, 32,
             #if SDL_BYTEORDER == SDL_BIG_ENDIAN
                       0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff);
             #else
                       0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
             #endif
    
        SDL_BlitSurface(bitmap, 0, image, 0);
    
        glGenTextures   (1, &texture);
        glBindTexture   (GL_TEXTURE_2D, texture);
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glPixelStorei   (GL_UNPACK_ROW_LENGTH, image->pitch / image->format->BytesPerPixel);
        glTexImage2D    (GL_TEXTURE_2D, 0, 3, image->w, image->h, 0, GL_RGBA,
                        GL_UNSIGNED_BYTE, image->pixels);
        glPixelStorei   (GL_UNPACK_ROW_LENGTH, 0);
    
        SDL_FreeSurface(image);
        SDL_FreeSurface(bitmap);
    
    }
    
    cFont::~cFont ()
    {
        glDeleteTextures(1, &texture);    
    }
    
    int cFont::print(float x, float y, float scale, const char *string)
    {
        int i, lo, hi;
        float sH, sL, rf = 1.0 / 16.0;
    
        glDisable (GL_DEPTH_TEST);
        glMatrixMode(GL_PROJECTION);						// Select The Projection Matrix
    	glPushMatrix();				
        glLoadIdentity();							        //  Reset The Projection Matrix
    	glOrtho(0,screenw,screenh,0,-1,1);	
    
    	glMatrixMode(GL_MODELVIEW);					     	// Select The Modelview Matrix
    	glPushMatrix();							         	// Store The Modelview Matrix
    	glLoadIdentity();
    
    	glBlendFunc(GL_ONE,GL_ONE);					// Select The Type Of Blending
        glEnable(GL_BLEND);
    
        glAlphaFunc  (GL_GREATER, 0.0f);
        glEnable     (GL_ALPHA_TEST);
    
    	glShadeModel(GL_SMOOTH);
    
        glEnable (GL_TEXTURE_2D);
        glBindTexture(GL_TEXTURE_2D, texture);
    
        glColor4fv(color);
    
        glBegin(GL_QUADS);
    
        for (i = 0; i < strlen(string); i++)
        {   
            lo = string[i] & 0x0f;
            hi = (string[i] & 0xf0) /16;
            sH = rf  *  (float)hi;
            sL = rf  *  (float)lo;
    
            glTexCoord2f(sL             , sH );      
                      glVertex2f(x + (i * scale)         , y );
            glTexCoord2f(sL             , sH + rf ); 
                      glVertex2f(x + (i * scale)         , y  + scale);
            glTexCoord2f(sL + rf , sH + rf ); 
                      glVertex2f(x + (i * scale ) + scale, y  + scale);
            glTexCoord2f(sL + rf , sH );      
                      glVertex2f(x + (i * scale ) + scale, y );
    
        }
        glEnd();
    
        glDisable (GL_TEXTURE_2D);
    
        glMatrixMode(GL_PROJECTION);						// Select The Projection Matrix
    	glPopMatrix();				
    
        glMatrixMode(GL_MODELVIEW);						// Select The Projection Matrix
    	glPopMatrix();				
    
        glEnable  (GL_DEPTH_TEST);
    
        GLenum code;
        code = glGetError();
    
    }
    

    Der Aufruf ist eigentlich schon ersichtlich, ich schreibs trotzdem mal kurz auf :

    /* Es sind sämtliche Bildtypen möglich, die SDL_image unterstützt 
     * Fensterhöhe und -breite sind für die pixelgenaue Darstellung nötig
     */
        cFont *F=new cFont("font.bmp", Screen->width, Screen->height);
        ...
    /* die hoehe ist in Pixeln */
        F->print (x, y, hoehe, "Text");
    /* prints können beliebig viele abgesetzt werden, ergo : als Button ist der Text
     * so erstmal nicht brauchbar.
     */
    
        delete F;
    


  • ah, sehr schön, vielen dank 😃
    werds mir mal anschauen

    edit:
    hm, was mir so spontan aufzufallen glaubt, ein problem:
    wenn ich jetzt ne 512x512 große texture hab und da die zeichen drin sind und ich will die zeichnen, hat jeder buchstabe ja nen gewissen rand (ist ja nicht wirklich 32x32 pixel groß) - der wird auch mit angezeigt -> riesen abstände, oder?

    mfg


Anmelden zum Antworten