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)