Exemplo n.º 1
0
void SubtitleRenderer::
prepare_glyphs(const std::vector<InternalChar>& text) {
  for (auto c = text.begin(); c != text.end(); ++c) {
    if (glyphs_.find(*c) == glyphs_.end())
      load_glyph(*c);
  }
}
// ------------------------------------------------------------------- init ---
void init( void )
{
    atlas = texture_atlas_new( 512, 512, 1 );
    font = texture_font_new_from_file( atlas, 32, "../media/fonts/Vera.ttf" );

    texture_glyph_t *glyph;

    // Generate the glyp at 512 points, compute distance field and scale it
    // back to 32 points
    // Just load another glyph if you want to see difference (draw render a '@')
    glyph = load_glyph( "../media/fonts/Vera.ttf", "@", 512, 64, 0.1);
    vector_push_back( font->glyphs, &glyph );

    texture_atlas_upload( atlas );

    glyph = texture_font_get_glyph( font, "@");

    GLuint indices[6] = {0,1,2, 0,2,3};
    vertex_t vertices[4] = { { -.5,-.5,0,  glyph->s0,glyph->t1,  0,0,0,1 },
                             { -.5, .5,0,  glyph->s0,glyph->t0,  0,0,0,1 },
                             {  .5, .5,0,  glyph->s1,glyph->t0,  0,0,0,1 },
                             {  .5,-.5,0,  glyph->s1,glyph->t1,  0,0,0,1 } };
    buffer = vertex_buffer_new( "vertex:3f,tex_coord:2f,color:4f" );
    vertex_buffer_push_back( buffer, vertices, 4, indices, 6 );

    program = shader_load( "../media/shaders/distance-field.vert",
                           "../media/shaders/distance-field-2.frag" );
    mat4_set_identity( &projection );
    mat4_set_identity( &model );
    mat4_set_identity( &view );
}
Exemplo n.º 3
0
static int dtext_prepare_text(AVFilterContext *ctx)
{
    DrawTextContext *s = ctx->priv;
    uint32_t code = 0, prev_code = 0;
    int x = 0, y = 0, i = 0, ret;
    int text_height, baseline;
    char *text;
    uint8_t *p;
    int str_w = 0, len;
    int y_min = 32000, y_max = -32000;
    FT_Vector delta;
    Glyph *glyph = NULL, *prev_glyph = NULL;
    Glyph dummy = { 0 };
    int width  = ctx->inputs[0]->w;
    int height = ctx->inputs[0]->h;

    ret = expand_strftime(s);
    if (ret < 0)
        return ret;

    text = s->expanded_text ? s->expanded_text : s->text;

    if ((len = strlen(text)) > s->nb_positions) {
        FT_Vector *p = av_realloc(s->positions,
                                  len * sizeof(*s->positions));
        if (!p) {
            av_freep(s->positions);
            s->nb_positions = 0;
            return AVERROR(ENOMEM);
        } else {
            s->positions = p;
            s->nb_positions = len;
        }
    }

    /* load and cache glyphs */
    for (i = 0, p = text; *p; i++) {
        GET_UTF8(code, *p++, continue;);

        /* get glyph */
        dummy.code = code;
        glyph = av_tree_find(s->glyphs, &dummy, glyph_cmp, NULL);
        if (!glyph) {
            ret = load_glyph(ctx, &glyph, code);
            if (ret)
                return ret;
        }

        y_min = FFMIN(glyph->bbox.yMin, y_min);
        y_max = FFMAX(glyph->bbox.yMax, y_max);
    }
Exemplo n.º 4
0
// ------------------------------------------------------------------- main ---
int
main( int argc, char **argv )
{
    glutInit( &argc, argv );
    glutInitWindowSize( 512, 512 );
    glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH );
    glutCreateWindow( "Distance fields demo" );
    glutReshapeFunc( reshape );
    glutDisplayFunc( display );
    glutKeyboardFunc( keyboard );
    glutTimerFunc( 1000.0/60, timer, 60 );

    glewExperimental = GL_TRUE;
    GLenum err = glewInit();
    if (GLEW_OK != err)
    {
        /* Problem: glewInit failed, something is seriously wrong. */
        fprintf( stderr, "Error: %s\n", glewGetErrorString(err) );
        exit( EXIT_FAILURE );
    }
    fprintf( stderr, "Using GLEW %s\n", glewGetString(GLEW_VERSION) );

    program = shader_load( "shaders/distance-field.vert",
                           "shaders/distance-field-3.frag" );
    glUseProgram( program );
    atlas = texture_atlas_new( 512, 512, 1 );
    font = texture_font_new_from_file( atlas, 32, "fonts/Vera.ttf" );

    texture_glyph_t *glyph;

    // Generate the glyp at 512 points, compute distance field and scale it
    // back to 32 points
    // Just load another glyph if you want to see difference (draw render a '@')
    glyph = load_glyph( "fonts/Vera.ttf", L'@', 512, 64, 0.1);
    vector_push_back( font->glyphs, &glyph );

    texture_atlas_upload( atlas );

    glutMainLoop( );
    return 0;
}
Exemplo n.º 5
0
static av_cold int init(AVFilterContext *ctx)
{
    int err;
    DrawTextContext *s = ctx->priv;
    Glyph *glyph;

    if (!s->fontfile && !CONFIG_LIBFONTCONFIG) {
        av_log(ctx, AV_LOG_ERROR, "No font filename provided\n");
        return AVERROR(EINVAL);
    }

    if (s->textfile) {
        if (s->text) {
            av_log(ctx, AV_LOG_ERROR,
                   "Both text and text file provided. Please provide only one\n");
            return AVERROR(EINVAL);
        }
        if ((err = load_textfile(ctx)) < 0)
            return err;
    }

    if (s->reload && !s->textfile)
        av_log(ctx, AV_LOG_WARNING, "No file to reload\n");

    if (s->tc_opt_string) {
        int ret = av_timecode_init_from_string(&s->tc, s->tc_rate,
                                               s->tc_opt_string, ctx);
        if (ret < 0)
            return ret;
        if (s->tc24hmax)
            s->tc.flags |= AV_TIMECODE_FLAG_24HOURSMAX;
        if (!s->text)
            s->text = av_strdup("");
    }

    if (!s->text) {
        av_log(ctx, AV_LOG_ERROR,
               "Either text, a valid file or a timecode must be provided\n");
        return AVERROR(EINVAL);
    }

#if CONFIG_LIBFRIBIDI
    if (s->text_shaping)
        if ((err = shape_text(ctx)) < 0)
            return err;
#endif

    if ((err = FT_Init_FreeType(&(s->library)))) {
        av_log(ctx, AV_LOG_ERROR,
               "Could not load FreeType: %s\n", FT_ERRMSG(err));
        return AVERROR(EINVAL);
    }

    err = load_font(ctx);
    if (err)
        return err;
    if (!s->fontsize)
        s->fontsize = 16;
    if ((err = FT_Set_Pixel_Sizes(s->face, 0, s->fontsize))) {
        av_log(ctx, AV_LOG_ERROR, "Could not set font size to %d pixels: %s\n",
               s->fontsize, FT_ERRMSG(err));
        return AVERROR(EINVAL);
    }

    if (s->borderw) {
        if (FT_Stroker_New(s->library, &s->stroker)) {
            av_log(ctx, AV_LOG_ERROR, "Coult not init FT stroker\n");
            return AVERROR_EXTERNAL;
        }
        FT_Stroker_Set(s->stroker, s->borderw << 6, FT_STROKER_LINECAP_ROUND,
                       FT_STROKER_LINEJOIN_ROUND, 0);
    }

    s->use_kerning = FT_HAS_KERNING(s->face);

    /* load the fallback glyph with code 0 */
    load_glyph(ctx, NULL, 0);

    /* set the tabsize in pixels */
    if ((err = load_glyph(ctx, &glyph, ' ')) < 0) {
        av_log(ctx, AV_LOG_ERROR, "Could not set tabsize.\n");
        return err;
    }
    s->tabsize *= glyph->advance;

    if (s->exp_mode == EXP_STRFTIME &&
        (strchr(s->text, '%') || strchr(s->text, '\\')))
        av_log(ctx, AV_LOG_WARNING, "expansion=strftime is deprecated.\n");

    av_bprint_init(&s->expanded_text, 0, AV_BPRINT_SIZE_UNLIMITED);
    av_bprint_init(&s->expanded_fontcolor, 0, AV_BPRINT_SIZE_UNLIMITED);

    return 0;
}
Exemplo n.º 6
0
static int dtext_prepare_text(AVFilterContext *ctx)
{
    DrawTextContext *s = ctx->priv;
    uint32_t code = 0, prev_code = 0;
    int x = 0, y = 0, i = 0, ret;
    int text_height, baseline;
    char *text = s->text;
    uint8_t *p;
    int str_w = 0, len;
    int y_min = 32000, y_max = -32000;
    FT_Vector delta;
    Glyph *glyph = NULL, *prev_glyph = NULL;
    Glyph dummy = { 0 };
    int width  = ctx->inputs[0]->w;
    int height = ctx->inputs[0]->h;
    time_t now = time(0);
    struct tm ltime;
    uint8_t *buf = s->expanded_text;
    int buf_size = s->expanded_text_size;

    if (!buf)
        buf_size = 2*strlen(s->text)+1;

    localtime_r(&now, &ltime);

    while ((buf = av_realloc(buf, buf_size))) {
        *buf = 1;
        if (strftime(buf, buf_size, s->text, &ltime) != 0 || *buf == 0)
            break;
        buf_size *= 2;
    }

    if (!buf)
        return AVERROR(ENOMEM);
    text = s->expanded_text = buf;
    s->expanded_text_size = buf_size;

    if ((len = strlen(text)) > s->nb_positions) {
        FT_Vector *p = av_realloc(s->positions,
                                  len * sizeof(*s->positions));
        if (!p) {
            av_freep(s->positions);
            s->nb_positions = 0;
            return AVERROR(ENOMEM);
        } else {
            s->positions = p;
            s->nb_positions = len;
        }
    }

    /* load and cache glyphs */
    for (i = 0, p = text; *p; i++) {
        GET_UTF8(code, *p++, continue;);

        /* get glyph */
        dummy.code = code;
        glyph = av_tree_find(s->glyphs, &dummy, glyph_cmp, NULL);
        if (!glyph) {
            ret = load_glyph(ctx, &glyph, code);
            if (ret)
                return ret;
        }

        y_min = FFMIN(glyph->bbox.yMin, y_min);
        y_max = FFMAX(glyph->bbox.yMax, y_max);
    }
Exemplo n.º 7
0
static av_cold int init(AVFilterContext *ctx)
{
    int err;
    DrawTextContext *s = ctx->priv;
    Glyph *glyph;

    if ((err = parse_font(ctx)) < 0)
        return err;

    if (s->textfile) {
        uint8_t *textbuf;
        size_t textbuf_size;

        if (s->text) {
            av_log(ctx, AV_LOG_ERROR,
                   "Both text and text file provided. Please provide only one\n");
            return AVERROR(EINVAL);
        }
        if ((err = av_file_map(s->textfile, &textbuf, &textbuf_size, 0, ctx)) < 0) {
            av_log(ctx, AV_LOG_ERROR,
                   "The text file '%s' could not be read or is empty\n",
                   s->textfile);
            return err;
        }

        if (textbuf_size > SIZE_MAX - 1 ||
            !(s->text = av_malloc(textbuf_size + 1))) {
            av_file_unmap(textbuf, textbuf_size);
            return AVERROR(ENOMEM);
        }
        memcpy(s->text, textbuf, textbuf_size);
        s->text[textbuf_size] = 0;
        av_file_unmap(textbuf, textbuf_size);
    }

    if (!s->text) {
        av_log(ctx, AV_LOG_ERROR,
               "Either text or a valid file must be provided\n");
        return AVERROR(EINVAL);
    }

    if ((err = av_parse_color(s->fontcolor_rgba, s->fontcolor_string, -1, ctx))) {
        av_log(ctx, AV_LOG_ERROR,
               "Invalid font color '%s'\n", s->fontcolor_string);
        return err;
    }

    if ((err = av_parse_color(s->boxcolor_rgba, s->boxcolor_string, -1, ctx))) {
        av_log(ctx, AV_LOG_ERROR,
               "Invalid box color '%s'\n", s->boxcolor_string);
        return err;
    }

    if ((err = av_parse_color(s->shadowcolor_rgba, s->shadowcolor_string, -1, ctx))) {
        av_log(ctx, AV_LOG_ERROR,
               "Invalid shadow color '%s'\n", s->shadowcolor_string);
        return err;
    }

    if ((err = FT_Init_FreeType(&(s->library)))) {
        av_log(ctx, AV_LOG_ERROR,
               "Could not load FreeType: %s\n", FT_ERRMSG(err));
        return AVERROR(EINVAL);
    }

    /* load the face, and set up the encoding, which is by default UTF-8 */
    if ((err = FT_New_Face(s->library, s->fontfile, 0, &s->face))) {
        av_log(ctx, AV_LOG_ERROR, "Could not load fontface from file '%s': %s\n",
               s->fontfile, FT_ERRMSG(err));
        return AVERROR(EINVAL);
    }
    if ((err = FT_Set_Pixel_Sizes(s->face, 0, s->fontsize))) {
        av_log(ctx, AV_LOG_ERROR, "Could not set font size to %d pixels: %s\n",
               s->fontsize, FT_ERRMSG(err));
        return AVERROR(EINVAL);
    }

    s->use_kerning = FT_HAS_KERNING(s->face);

    /* load the fallback glyph with code 0 */
    load_glyph(ctx, NULL, 0);

    /* set the tabsize in pixels */
    if ((err = load_glyph(ctx, &glyph, ' ') < 0)) {
        av_log(ctx, AV_LOG_ERROR, "Could not set tabsize.\n");
        return err;
    }
    s->tabsize *= glyph->advance;

#if !HAVE_LOCALTIME_R
    av_log(ctx, AV_LOG_WARNING, "strftime() expansion unavailable!\n");
#endif

    return 0;
}
Exemplo n.º 8
0
Arquivo: font.cpp Projeto: Greyze/xd
void xd::font::render(const std::string& text, const font_style& style,
	xd::shader_program::handle shader, const glm::mat4& mvp, glm::vec2 *pos)
{
	// check if we're rendering using this font or a linked font
	if (style.m_type && style.m_type->length() != 0) {
		font_map_t::iterator i = m_linked_fonts.find(*style.m_type);
		if (i == m_linked_fonts.end())
			throw invalid_font_type(*style.m_type);
		font_style linked_style = style;
		linked_style.m_type = boost::none;
		i->second->render(text, linked_style, shader, mvp, pos);
		return;
	}

	// check if the font size is already loaded
	auto it = m_face->sizes.find(style.m_size);
	if (it == m_face->sizes.end()) {
		// create a new size
		FT_Size size;
		if (FT_New_Size(m_face->handle, &size) != 0)
			throw font_load_failed(m_filename);
		// free the size in catch block if something goes wrong
		try {
			if (FT_Activate_Size(size) != 0)
				throw font_load_failed(m_filename);
			// set the pixel size
			if (FT_Set_Pixel_Sizes(m_face->handle, 0, style.m_size) != 0)
				throw font_load_failed(m_filename);
			// pre-load 7-bit ASCII glyphs
			for (int i = 0; i < 128; i++) {
				load_glyph(i, style.m_size);
			}
		} catch (...) {
			// free the size and re-throw
			FT_Done_Size(size);
			throw;
		}
		// insert the newly loaded size in the map
		m_face->sizes.insert(std::make_pair(style.m_size, size));
	} else {
		// activate the size
		FT_Activate_Size(it->second);
	}

	// bind to first texture unit
	glActiveTexture(GL_TEXTURE0);

	// setup the shader
	shader->use();
	shader->bind_uniform(m_mvp_uniform, mvp);
	shader->bind_uniform(m_color_uniform, style.m_color);
	shader->bind_uniform(m_texture_uniform, 0);

	// is kerning supported
	FT_Bool kerning = FT_HAS_KERNING(m_face->handle);

	// render each glyph in the string
	glm::vec2 text_pos;
	if (pos)
		text_pos = *pos;

	FT_UInt prev_glyph_index = 0;
	auto i = text.begin();
	while (i != text.end()) {
		// get the unicode code point
		utf8::uint32_t char_index = utf8::next(i, text.end());

		// get the cached glyph, or cache if it is not yet cached
		const detail::font::glyph& glyph = load_glyph(char_index, style.m_size);

		// bind the texture
		glBindTexture(GL_TEXTURE_2D, glyph.texture_id);

		// check for kerning
		if (kerning && glyph.glyph_index && prev_glyph_index) {
			FT_Vector kerning_delta;
			FT_Get_Kerning(m_face->handle, prev_glyph_index, glyph.glyph_index, FT_KERNING_DEFAULT, &kerning_delta);
			text_pos.x += kerning_delta.x >> 6;
		}

		// calculate exact offset
		glm::vec2 glyph_pos = text_pos;
		glyph_pos.x += glyph.offset.x;
		glyph_pos.y += glyph.offset.y;

		// add optional letter spacing
		glyph_pos.x += style.m_letter_spacing/2;

		// if shadow is enabled, draw the shadow first
		if (style.m_shadow) {
			// calculate shadow position
			glm::vec2 shadow_pos = glyph_pos;
			shadow_pos.x += style.m_shadow->x;
			shadow_pos.y += style.m_shadow->y;

			// calculate shadow color
			glm::vec4 shadow_color = style.m_shadow->color;
			shadow_color.a *= style.m_color.a;

			// bind uniforms
			shader->bind_uniform(m_color_uniform, shadow_color);
			shader->bind_uniform(m_position_uniform, shadow_pos);

			// draw shadow
			glyph.quad_ptr->render();

			// restore the text color
			shader->bind_uniform(m_color_uniform, style.m_color);
		}
		
		// if outline is enabled, draw outline
		if (style.m_outline) {
			// calculate outline color
			glm::vec4 outline_color = style.m_outline->color;
			outline_color.a *= style.m_color.a;

			// bind color
			shader->bind_uniform(m_color_uniform, outline_color);

			// draw font multiple times times to draw outline (EXPENSIVE!)
			for (int x = -style.m_outline->width; x <= style.m_outline->width; x++) {
				for (int y = -style.m_outline->width; y <= style.m_outline->width; y++) {
					if (x == 0 && y == 0)
						continue;
					shader->bind_uniform(m_position_uniform, glyph_pos + glm::vec2(x, y));
					glyph.quad_ptr->render();
				}
			}

			// restore the text color
			shader->bind_uniform(m_color_uniform, style.m_color);
		}

		// bind uniforms
		shader->bind_uniform(m_position_uniform, glyph_pos);

		// draw the glyph
		glyph.quad_ptr->render();
		
		// advance the position
		text_pos += glyph.advance;
		text_pos.x += style.m_letter_spacing;

		// keep track of previous glyph to do kerning
		prev_glyph_index = glyph.glyph_index;
	}