>From 560e6f26b7df38c1d55e2e7c7a12f08d6b4aa3dc Mon Sep 17 00:00:00 2001 From: greg Date: Wed, 18 Feb 2009 03:59:48 +0100 Subject: [PATCH 10/12] Add support for compositing of overlapping glyph borders. This makes translucent borders which overlap look right. On the downside this is quite CPU intensive... This is useful to --- libass/ass_render.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 107 insertions(+), 2 deletions(-) diff --git a/libass/ass_render.c b/libass/ass_render.c index 7700fdf..75b3c46 100644 --- a/libass/ass_render.c +++ b/libass/ass_render.c @@ -201,11 +201,19 @@ typedef struct frame_context_s { double border_scale; } frame_context_t; +// List of objects to free after each frame +typedef struct free_list_s { + int count; + int size; + void** obj; +} free_list_t; + static ass_renderer_t* ass_renderer; static ass_settings_t* global_settings; static text_info_t text_info; static render_context_t render_context; static frame_context_t frame_context; +static free_list_t free_list; struct render_priv_s { int top, height; @@ -289,6 +297,30 @@ ass_init_exit: return priv; } +static void ass_free_objects(void) { + int i = 0; + while (free_list.count--) + free(free_list.obj[i++]); + free_list.count = 0; +} + +static void ass_free_add(void * obj) { + if (free_list.size == 0) { + free_list.size = 2; + free_list.obj = malloc(free_list.size * sizeof(void *)); + } else if (free_list.size <= free_list.count+1) { + free_list.size *= 2; + free_list.obj = realloc(free_list.obj, free_list.size * sizeof(void *)); + } + free_list.obj[free_list.count++] = obj; +} + +static void ass_free_done(void) { + if (free_list.obj) + free(free_list.obj); + free_list.obj = 0; +} + void ass_renderer_done(ass_renderer_t* priv) { ass_font_cache_done(); @@ -305,6 +337,8 @@ void ass_renderer_done(ass_renderer_t* priv) if (priv && priv->eimg) free(priv->eimg); if (priv) free(priv); if (text_info.glyphs) free(text_info.glyphs); + ass_free_objects(); + ass_free_done(); } /** @@ -406,6 +440,68 @@ static ass_image_t** render_glyph(bitmap_t* bm, int dst_x, int dst_y, uint32_t c } /** + * \brief Calculate overlapping area of two consecutive bitmaps and in case they + * overlap, composite them together + * Mainly useful for translucent glyphs and especially borders, to avoid the + * luminance adding up where they overlap (which looks ugly) + */ +static void render_overlap(ass_image_t** last_tail, ass_image_t** tail) { + int left, top, bottom, right; + int old_left, old_top, w, h, cur_left, cur_top; + int x, y, opos, cpos; + char m; + + int ax = (*last_tail)->dst_x; + int ay = (*last_tail)->dst_y; + int aw = (*last_tail)->w; + int ah = (*last_tail)->h; + int bx = (*tail)->dst_x; + int by = (*tail)->dst_y; + int bw = (*tail)->w; + int bh = (*tail)->h; + unsigned char* a; + unsigned char* b; + + // Calculate overlap as coordinates + left = (ax > bx) ? ax : bx; + top = (ay > by) ? ay : by; + right = ((ax+aw) < (bx+bw)) ? + (ax+aw) : (bx+bw); + bottom = ((ay+ah) < (by+bh)) ? + (ay+ah) : (by+bh); + // Check whether overlap rect is valid + if ((right <= left) || (bottom <= top)) + return; + // Translate into coordinates+width/height for each bitmap + old_left = left-(ax); + old_top = top-(ay); + w = right-left; + h = bottom-top; + cur_left = left-(bx); + cur_top = top-(by); + + // Allocate new bitmaps and copy over data + a = (*last_tail)->bitmap; + b = (*tail)->bitmap; + (*last_tail)->bitmap = malloc(aw*ah); + ass_free_add((*last_tail)->bitmap); + (*tail)->bitmap = malloc(bw*bh); + ass_free_add((*tail)->bitmap); + memcpy((*last_tail)->bitmap, a, aw*ah); + memcpy((*tail)->bitmap, b, bw*bh); + + // Composite overlapping area + for (y=0; y b[cpos]) ? a[opos] : b[cpos]; + (*last_tail)->bitmap[opos] = 0; + (*tail)->bitmap[cpos] = m; + } +} + +/** * \brief Convert text_info_t struct to ass_image_t list * Splits glyphs in halves when needed (for \kf karaoke). */ @@ -416,7 +512,9 @@ static ass_image_t* render_text(text_info_t* text_info, int dst_x, int dst_y) bitmap_t* bm; ass_image_t* head; ass_image_t** tail = &head; - + ass_image_t** last_tail = 0; + ass_image_t** here_tail = 0; + for (i = 0; i < text_info->length; ++i) { glyph_info_t* info = text_info->glyphs + i; if ((info->symbol == 0) || (info->symbol == '\n') || !info->bm_s || (info->shadow == 0)) @@ -440,8 +538,13 @@ static ass_image_t* render_text(text_info_t* text_info, int dst_x, int dst_y) if ((info->effect_type == EF_KARAOKE_KO) && (info->effect_timing <= info->bbox.xMax)) { // do nothing - } else + } else { + here_tail = tail; tail = render_glyph(bm, pen_x, pen_y, info->c[2], 0, 1000000, tail); + if (last_tail && tail != here_tail && ((info->c[2] & 0xff) > 0)) + render_overlap(last_tail, here_tail); + last_tail = here_tail; + } } for (i = 0; i < text_info->length; ++i) { glyph_info_t* info = text_info->glyphs + i; @@ -2211,6 +2314,8 @@ static int ass_start_frame(ass_renderer_t *priv, ass_track_t* track, long long n if (track->n_events == 0) return 1; // nothing to do + ass_free_objects(); + frame_context.ass_priv = priv; frame_context.width = global_settings->frame_width; frame_context.height = global_settings->frame_height; -- 1.5.4.3