rougier / freetype-gl

OpenGL text using one vertex buffer, one texture and FreeType
Other
1.65k stars 266 forks source link

texture_atlas_upload at each frame #119

Open shadd3 opened 8 years ago

shadd3 commented 8 years ago

Hello,

I am building the font on the fly. During the drawing, I call ftgl::texture_atlas_upload(m_text_buffer->manager->atlas); This call is necessary when some new glyph have been added. otherwise this call causes useless GPU upload transferts. Currently, I am using this hack to avoid some useless transferts

size_t const s = ftgl::vector_size(m_text_buffer->manager->atlas->nodes);
if (s != m_Atlas_Cached_Nodes_Hack)
{
logMsg(LVL_LOG, "Uploading font texture !!!\n");
ftgl::texture_atlas_upload(m_text_buffer->manager->atlas);
m_Atlas_Cached_Nodes_Hack = s;
}

we could not have an "official AP"I that would be responsible for transferring or not the texture ? Best regards

rougier commented 8 years ago

@shadd3 For displaying code, you can use triple quote (I took the freedom to edit your comment)

The texture_atlas_upload should do nothing if there is not something new to upload. Isn't it the case ?

shadd3 commented 8 years ago

right, but from my understanding, it is not the case see my comments in your code + my proposal best regards - shadd

void
texture_atlas_upload( texture_atlas_t * self )
{
    assert( self );
    assert( self->data );

// shadd : the id texture is created once
    if( !self->id ) 
    {
        glGenTextures( 1, &self->id );
    }

    glBindTexture( GL_TEXTURE_2D, self->id );
// shadd : the tex parameters are bound to texture object id; so it is not necessary to apply at each time (see immutable vs mutable texture Gl khronos spec)
    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_MAG_FILTER, GL_LINEAR );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
    if( self->depth == 4 )
    {
.....
    }
    else if( self->depth == 3 )
    {
// shadd: the texture is allocated and uploaded at each time; use glTexSubImage2D for updating
        glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, self->width, self->height,
                      0, GL_RGB, GL_UNSIGNED_BYTE, self->data );
    }
    else
    {
.....
    }
}

from https://www.opengl.org/wiki/Common_Mistakes

Updating a texture To change texels in an already existing 2d texture, use glTexSubImage2D​:

glBindTexture(GL_TEXTURE_2D, textureID); //A texture you have already created storage for glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_BGRA, GL_UNSIGNED_BYTE, pixels); glTexImage2D​ creates the storage for the texture, defining the size/format and removing all previous pixel data. glTexSubImage2D​ only modifies pixel data within the texture. It can be used to update all the texels, or simply a portion of them.

To copy texels from the framebuffer, use glCopyTexSubImage2D​.

glBindTexture(GL_TEXTURE_2D, textureID); //A texture you have already created storage for glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, width, height); //Copy current read buffer to texture

Note that there is a glCopyTexImage2D​ function, which does the copy to fill the image, but also defines the image size, format and so forth, just like glTexImage2D​.

void
texture_atlas_upload( texture_atlas_t * self )
{
    assert( self );
    assert( self->data );

    size_t const s = vector_size(self->nodes);
    if (!self->id)
    {
        glGenTextures(1, &self->id);
        glBindTexture(GL_TEXTURE_2D, self->id);
        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_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        if (self->depth == 4)
        {
#ifdef GL_UNSIGNED_INT_8_8_8_8_REV
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, self->width, self->height,
                0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, self->data);
#else
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, self->width, self->height,
                0, GL_RGBA, GL_UNSIGNED_BYTE, self->data);
#endif
        }
        else if (self->depth == 3)
        {
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, self->width, self->height,
                0, GL_RGB, GL_UNSIGNED_BYTE, self->data);
        }
        else
        {
#if defined(GL_ES_VERSION_2_0) || defined(GL_ES_VERSION_3_0)
            glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, self->width, self->height,
                0, GL_LUMINANCE, GL_UNSIGNED_BYTE, self->data);
#else
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, self->width, self->height,
                0, GL_RED, GL_UNSIGNED_BYTE, self->data);
#endif
        }
    }
    else
    {
        if (s != self->nodesCurSize)
        {
            glBindTexture(GL_TEXTURE_2D, self->id);
            if (self->depth == 4)
            {
                // TODO: glTexSubImage2D
            }
            else if (self->depth == 3)
            {
                glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, self->width, self->height, GL_RGB, GL_UNSIGNED_BYTE, self->data);
            }
            else
            {
                // TODO: glTexSubImage2D
            }
        }
    }
    self->nodesCurSize = s;
}
adrianbroher commented 8 years ago

The texture_atlas_upload API call was dropped just recently. Library clients should handle the texture generation, uploading and cleaning up by themselves.