freetype
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[ft] deferred rendering issue


From: Stuart Heinrich
Subject: [ft] deferred rendering issue
Date: Fri, 2 Dec 2011 10:16:54 -0800

Following the first tutorial example with FT_Render_Glyph to render into slot and then bitwise-or into the image buffer, I get proper kerning.  However, when I follow the deferred rendering example in the tutorial page that uses FT_Glyph_To_Bitmap, I don't get proper kerning anymore.

I have verified that the precomputed 'pen' positions are still correct, but they don't seem to be respected by the FT_Glyph_To_Bitmap function.  In my first pass over the glyphs, if I make a call FT_Render_Glyph, then a later call to FT_Glyph_To_Bitmap will work properly...but this means I've rendered every glyph redundantly.  Anyone know what's going on?
Here's my code:

template<class T>
        void render_text(cimgl::CImg<T> &image, unsigned px, unsigned py, const std::string &text, const T *color, static_matrix<2,2,float> *skew = NULL)
        {
            FT_GlyphSlot slot = face->glyph;
            FT_UInt glyph_index;
            FT_Bool use_kerning = FT_HAS_KERNING( face );
            FT_UInt previous =0;

            std::vector< FT_Glyph > glyphs( text.size() );
            std::vector< FT_Vector > pos( text.size() );

            FT_Vector pen;
            pen.x = 0;
            pen.y = 0;

            FT_Matrix *xform = NULL;
            FT_Matrix matrix;

            if (skew)
            {
                //convert from float into 16.16 fixed format
                matrix.xx = round((*skew)(0, 0)*(1 << 16));
                matrix.xy = round((*skew)(0, 1)*(1 << 16));
                matrix.yx = round((*skew)(1, 0)*(1 << 16));
                matrix.yy = round((*skew)(1, 1)*(1 << 16));
                xform = &matrix;
            }

            //compute bounding box...
            FT_BBox bbox;
            bbox.xMin = 0;
            bbox.yMin = 0;
            bbox.xMax = 0;
            bbox.yMax = 0;

            //load all the glyphs without rendering...
            unsigned count = 0;
            for ( int n = 0; n < text.size(); n++ )
            {
                // convert character code to glyph index
                glyph_index = FT_Get_Char_Index( face, text[n] );

                // retrieve kerning distance and move pen position
                if ( use_kerning && previous && glyph_index )
                {
                    FT_Vector delta;
                    FT_Get_Kerning( face, previous, glyph_index, FT_KERNING_DEFAULT, &delta );
                    pen.x += delta.x;
                    pen.y += delta.y;
                }

                //store current pen position
                pos[count] = pen;

                //set glyph transform...
                FT_Set_Transform( face, xform, &pen );

                // load glyph image into the slot without rendering
                int error = FT_Load_Glyph( face, glyph_index, FT_LOAD_DEFAULT );
                if ( error ) continue; // ignore errors, jump to next glyph

                //if we dont do this here, then when we render later, there is way too much white space
                // not sure WHY this fixes it...but should be able to remove the double-render.
                // seems we can't save this render because it goes directly into a temporary slot?
                error = FT_Render_Glyph( face->glyph, FT_RENDER_MODE_NORMAL );
                if ( error ) continue; // ignore errors, jump to next glyph

                // extract glyph image and store it in our table
                error = FT_Get_Glyph( face->glyph, &glyphs[count] );
                if ( error ) continue; // ignore errors, jump to next glyph

                //increment bounding box...
                FT_BBox glyph_bbox;
                FT_Glyph_Get_CBox( glyphs[count], ft_glyph_bbox_pixels, &glyph_bbox );

                //std::cout << "glyph bbox: " << glyph_bbox.xMin <<"," << glyph_bbox.yMin << " to " << glyph_bbox.xMax <<","<<glyph_bbox.yMax << "\n";

                if( glyph_bbox.xMin < bbox.xMin )
                    bbox.xMin = glyph_bbox.xMin;
                if( glyph_bbox.xMax > bbox.xMax )
                    bbox.xMax = glyph_bbox.xMax;
                if( glyph_bbox.yMin < bbox.yMin )
                    bbox.yMin = glyph_bbox.yMin;
                if( glyph_bbox.yMax > bbox.yMax )
                    bbox.yMax = glyph_bbox.yMax;       

                // increment pen position
                pen.x += slot->advance.x;
                pen.y += slot->advance.y;

                // record current glyph index
                previous = glyph_index;
                ++count;
            }

            //render each glyph and bitwise-or the intensity values into a buffer...
            int buffer_width = bbox.xMax - bbox.xMin, buffer_height = bbox.yMax - bbox.yMin;
            //std::cout << "buffer size: " << buffer_width << " x " << buffer_height << "\n";
            unsigned char *buffer = new unsigned char[ buffer_width * buffer_height ];
            memset( buffer, 0, sizeof( buffer_width * buffer_height ) );

            for ( int n = 0; n < count; n++ )
            {
                FT_Glyph glyph = glyphs[n];
                FT_Vector pen = pos[n];

                int error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_NORMAL, &pen, 0 );
                if (error) continue;

                FT_BitmapGlyph bit = (FT_BitmapGlyph) glyph;
                FT_Bitmap *bitmap = &(bit->bitmap);

                int ix_to_bx = bit->left - bbox.xMin,
                    iy_to_by = (buffer_height - bit->top) - bbox.yMin;

                int ix_end = std::min(buffer_width, bitmap->width + ix_to_bx) - ix_to_bx,
                    iy_end = std::min(buffer_height, bitmap->rows + iy_to_by) - iy_to_by;

                for (int ix = 0; ix < ix_end; ++ix)
                {
                    for (int iy = 0; iy < iy_end; ++iy)
                    {
                        int bx = ix + ix_to_bx, by = iy + iy_to_by;
                        buffer[by * buffer_width + bx] |= bitmap->buffer[iy * bitmap->width + ix];
                    }
                }

                FT_Done_Glyph( glyph );
            }

            //now draw the buffer onto the image, centered over target point, as a colored overlay
            int bx_to_x = (int)px - (int)(buffer_width>>1),
                by_to_y = (int)py - (int)(buffer_height>>1);
            int bx_end = std::min((int)image.width, buffer_width+bx_to_x) - bx_to_x,
                by_end = std::min((int)image.height, buffer_height+by_to_y) - by_to_y;
            for(unsigned bx=0; bx<bx_end; ++bx)
                for(unsigned by=0; by<by_end; ++by)
                    image.draw_point(bx+bx_to_x, by+by_to_y, color, buffer[by*buffer_width + bx]/255.0f );

            //free the buffer...
            delete [] buffer;                                                       

        }

reply via email to

[Prev in Thread] Current Thread [Next in Thread]