Mercurial > mplayer.hg
comparison libass/ass_render.c @ 28789:a0ce88ba2557
Combine adjacent overlapping, translucent glyph borders and shadows to
avoid luminance build-up, which looks ugly.
The resulting, modified bitmaps are stored in separate bitmap cache.
author | greg |
---|---|
date | Thu, 05 Mar 2009 20:47:33 +0000 |
parents | 09348bd171e9 |
children | 65b83aee82fb |
comparison
equal
deleted
inserted
replaced
28788:09348bd171e9 | 28789:a0ce88ba2557 |
---|---|
277 priv->ftlibrary = ft; | 277 priv->ftlibrary = ft; |
278 // images_root and related stuff is zero-filled in calloc | 278 // images_root and related stuff is zero-filled in calloc |
279 | 279 |
280 ass_font_cache_init(); | 280 ass_font_cache_init(); |
281 ass_bitmap_cache_init(); | 281 ass_bitmap_cache_init(); |
282 ass_composite_cache_init(); | |
282 ass_glyph_cache_init(); | 283 ass_glyph_cache_init(); |
283 | 284 |
284 text_info.glyphs = calloc(MAX_GLYPHS, sizeof(glyph_info_t)); | 285 text_info.glyphs = calloc(MAX_GLYPHS, sizeof(glyph_info_t)); |
285 | 286 |
286 ass_init_exit: | 287 ass_init_exit: |
292 | 293 |
293 void ass_renderer_done(ass_renderer_t* priv) | 294 void ass_renderer_done(ass_renderer_t* priv) |
294 { | 295 { |
295 ass_font_cache_done(); | 296 ass_font_cache_done(); |
296 ass_bitmap_cache_done(); | 297 ass_bitmap_cache_done(); |
298 ass_composite_cache_done(); | |
297 ass_glyph_cache_done(); | 299 ass_glyph_cache_done(); |
298 if (render_context.stroker) { | 300 if (render_context.stroker) { |
299 FT_Stroker_Done(render_context.stroker); | 301 FT_Stroker_Done(render_context.stroker); |
300 render_context.stroker = 0; | 302 render_context.stroker = 0; |
301 } | 303 } |
404 } | 406 } |
405 return tail; | 407 return tail; |
406 } | 408 } |
407 | 409 |
408 /** | 410 /** |
411 * \brief Calculate overlapping area of two consecutive bitmaps and in case they | |
412 * overlap, composite them together | |
413 * Mainly useful for translucent glyphs and especially borders, to avoid the | |
414 * luminance adding up where they overlap (which looks ugly) | |
415 */ | |
416 static void render_overlap(ass_image_t** last_tail, ass_image_t** tail, bitmap_hash_key_t *last_hash, bitmap_hash_key_t* hash) { | |
417 int left, top, bottom, right; | |
418 int old_left, old_top, w, h, cur_left, cur_top; | |
419 int x, y, opos, cpos; | |
420 char m; | |
421 composite_hash_key_t hk; | |
422 composite_hash_val_t *hv; | |
423 composite_hash_key_t *nhk; | |
424 int ax = (*last_tail)->dst_x; | |
425 int ay = (*last_tail)->dst_y; | |
426 int aw = (*last_tail)->w; | |
427 int ah = (*last_tail)->h; | |
428 int bx = (*tail)->dst_x; | |
429 int by = (*tail)->dst_y; | |
430 int bw = (*tail)->w; | |
431 int bh = (*tail)->h; | |
432 unsigned char* a; | |
433 unsigned char* b; | |
434 | |
435 if ((*last_tail)->bitmap == (*tail)->bitmap) | |
436 return; | |
437 | |
438 // Calculate overlap coordinates | |
439 left = (ax > bx) ? ax : bx; | |
440 top = (ay > by) ? ay : by; | |
441 right = ((ax+aw) < (bx+bw)) ? (ax+aw) : (bx+bw); | |
442 bottom = ((ay+ah) < (by+bh)) ? (ay+ah) : (by+bh); | |
443 if ((right <= left) || (bottom <= top)) | |
444 return; | |
445 old_left = left-(ax); | |
446 old_top = top-(ay); | |
447 w = right-left; | |
448 h = bottom-top; | |
449 cur_left = left-(bx); | |
450 cur_top = top-(by); | |
451 | |
452 // Query cache | |
453 memcpy(&hk.a, last_hash, sizeof(*last_hash)); | |
454 memcpy(&hk.b, hash, sizeof(*hash)); | |
455 hk.aw = aw; | |
456 hk.ah = ah; | |
457 hk.bw = bw; | |
458 hk.bh = bh; | |
459 hk.ax = ax; | |
460 hk.ay = ay; | |
461 hk.bx = bx; | |
462 hk.by = by; | |
463 hv = cache_find_composite(&hk); | |
464 if (hv) { | |
465 (*last_tail)->bitmap = hv->a; | |
466 (*tail)->bitmap = hv->b; | |
467 return; | |
468 } | |
469 | |
470 // Allocate new bitmaps and copy over data | |
471 a = (*last_tail)->bitmap; | |
472 b = (*tail)->bitmap; | |
473 (*last_tail)->bitmap = malloc(aw*ah); | |
474 (*tail)->bitmap = malloc(bw*bh); | |
475 memcpy((*last_tail)->bitmap, a, aw*ah); | |
476 memcpy((*tail)->bitmap, b, bw*bh); | |
477 | |
478 // Composite overlapping area | |
479 for (y=0; y<h; y++) | |
480 for (x=0; x<w; x++) { | |
481 opos = (old_top+y)*(aw) + (old_left+x); | |
482 cpos = (cur_top+y)*(bw) + (cur_left+x); | |
483 m = (a[opos] > b[cpos]) ? a[opos] : b[cpos]; | |
484 (*last_tail)->bitmap[opos] = 0; | |
485 (*tail)->bitmap[cpos] = m; | |
486 } | |
487 | |
488 // Insert bitmaps into the cache | |
489 nhk = calloc(1, sizeof(*nhk)); | |
490 memcpy(nhk, &hk, sizeof(*nhk)); | |
491 hv = calloc(1, sizeof(*hv)); | |
492 hv->a = (*last_tail)->bitmap; | |
493 hv->b = (*tail)->bitmap; | |
494 cache_add_composite(nhk, hv); | |
495 } | |
496 | |
497 /** | |
409 * \brief Convert text_info_t struct to ass_image_t list | 498 * \brief Convert text_info_t struct to ass_image_t list |
410 * Splits glyphs in halves when needed (for \kf karaoke). | 499 * Splits glyphs in halves when needed (for \kf karaoke). |
411 */ | 500 */ |
412 static ass_image_t* render_text(text_info_t* text_info, int dst_x, int dst_y) | 501 static ass_image_t* render_text(text_info_t* text_info, int dst_x, int dst_y) |
413 { | 502 { |
414 int pen_x, pen_y; | 503 int pen_x, pen_y; |
415 int i; | 504 int i; |
416 bitmap_t* bm; | 505 bitmap_t* bm; |
417 ass_image_t* head; | 506 ass_image_t* head; |
418 ass_image_t** tail = &head; | 507 ass_image_t** tail = &head; |
508 ass_image_t** last_tail = 0; | |
509 ass_image_t** here_tail = 0; | |
510 bitmap_hash_key_t* last_hash = 0; | |
419 | 511 |
420 for (i = 0; i < text_info->length; ++i) { | 512 for (i = 0; i < text_info->length; ++i) { |
421 glyph_info_t* info = text_info->glyphs + i; | 513 glyph_info_t* info = text_info->glyphs + i; |
422 if ((info->symbol == 0) || (info->symbol == '\n') || !info->bm_s || (info->shadow == 0)) | 514 if ((info->symbol == 0) || (info->symbol == '\n') || !info->bm_s || (info->shadow == 0)) |
423 continue; | 515 continue; |
424 | 516 |
425 pen_x = dst_x + info->pos.x + ROUND(info->shadow * frame_context.border_scale); | 517 pen_x = dst_x + info->pos.x + ROUND(info->shadow * frame_context.border_scale); |
426 pen_y = dst_y + info->pos.y + ROUND(info->shadow * frame_context.border_scale); | 518 pen_y = dst_y + info->pos.y + ROUND(info->shadow * frame_context.border_scale); |
427 bm = info->bm_s; | 519 bm = info->bm_s; |
428 | 520 |
521 here_tail = tail; | |
429 tail = render_glyph(bm, pen_x, pen_y, info->c[3], 0, 1000000, tail); | 522 tail = render_glyph(bm, pen_x, pen_y, info->c[3], 0, 1000000, tail); |
430 } | 523 if (last_tail && tail != here_tail && ((info->c[3] & 0xff) > 0)) |
431 | 524 render_overlap(last_tail, here_tail, last_hash, &info->hash_key); |
525 last_tail = here_tail; | |
526 last_hash = &info->hash_key; | |
527 } | |
528 | |
529 last_tail = 0; | |
432 for (i = 0; i < text_info->length; ++i) { | 530 for (i = 0; i < text_info->length; ++i) { |
433 glyph_info_t* info = text_info->glyphs + i; | 531 glyph_info_t* info = text_info->glyphs + i; |
434 if ((info->symbol == 0) || (info->symbol == '\n') || !info->bm_o) | 532 if ((info->symbol == 0) || (info->symbol == '\n') || !info->bm_o) |
435 continue; | 533 continue; |
436 | 534 |
438 pen_y = dst_y + info->pos.y; | 536 pen_y = dst_y + info->pos.y; |
439 bm = info->bm_o; | 537 bm = info->bm_o; |
440 | 538 |
441 if ((info->effect_type == EF_KARAOKE_KO) && (info->effect_timing <= info->bbox.xMax)) { | 539 if ((info->effect_type == EF_KARAOKE_KO) && (info->effect_timing <= info->bbox.xMax)) { |
442 // do nothing | 540 // do nothing |
443 } else | 541 } else { |
542 here_tail = tail; | |
444 tail = render_glyph(bm, pen_x, pen_y, info->c[2], 0, 1000000, tail); | 543 tail = render_glyph(bm, pen_x, pen_y, info->c[2], 0, 1000000, tail); |
544 if (last_tail && tail != here_tail && ((info->c[2] & 0xff) > 0)) | |
545 render_overlap(last_tail, here_tail, last_hash, &info->hash_key); | |
546 last_tail = here_tail; | |
547 last_hash = &info->hash_key; | |
548 } | |
445 } | 549 } |
446 for (i = 0; i < text_info->length; ++i) { | 550 for (i = 0; i < text_info->length; ++i) { |
447 glyph_info_t* info = text_info->glyphs + i; | 551 glyph_info_t* info = text_info->glyphs + i; |
448 if ((info->symbol == 0) || (info->symbol == '\n') || !info->bm) | 552 if ((info->symbol == 0) || (info->symbol == '\n') || !info->bm) |
449 continue; | 553 continue; |
2119 static void ass_reconfigure(ass_renderer_t* priv) | 2223 static void ass_reconfigure(ass_renderer_t* priv) |
2120 { | 2224 { |
2121 priv->render_id = ++last_render_id; | 2225 priv->render_id = ++last_render_id; |
2122 ass_glyph_cache_reset(); | 2226 ass_glyph_cache_reset(); |
2123 ass_bitmap_cache_reset(); | 2227 ass_bitmap_cache_reset(); |
2228 ass_composite_cache_reset(); | |
2124 ass_free_images(priv->prev_images_root); | 2229 ass_free_images(priv->prev_images_root); |
2125 priv->prev_images_root = 0; | 2230 priv->prev_images_root = 0; |
2126 } | 2231 } |
2127 | 2232 |
2128 void ass_set_frame_size(ass_renderer_t* priv, int w, int h) | 2233 void ass_set_frame_size(ass_renderer_t* priv, int w, int h) |