# HG changeset patch # User eugeni # Date 1156716751 0 # Node ID c7057724ba8cc1c4069c704c28cc9156e1651391 # Parent 32e4e68651d02b72ad8e1a98c4dcdc1186733271 Transition effects support. diff -r 32e4e68651d0 -r c7057724ba8c libass/ass_render.c --- a/libass/ass_render.c Sun Aug 27 22:03:24 2006 +0000 +++ b/libass/ass_render.c Sun Aug 27 22:12:31 2006 +0000 @@ -91,7 +91,9 @@ int alignment; // alignment overrides go here; if zero, style value will be used double rotation; enum { EVENT_NORMAL, // "normal" top-, sub- or mid- title - EVENT_POSITIONED // happens after pos(,), margins are ignored + EVENT_POSITIONED, // happens after pos(,), margins are ignored + EVENT_HSCROLL, // "Banner" transition effect, text_width is unlimited + EVENT_VSCROLL // "Scroll up", "Scroll down" transition effects } evt_type; int pos_x, pos_y; // position int org_x, org_y; // origin @@ -105,6 +107,13 @@ effect_t effect_type; int effect_timing; + enum { SCROLL_LR, // left-to-right + SCROLL_RL, + SCROLL_TB, // top-to-bottom + SCROLL_BT + } scroll_direction; // for EVENT_HSCROLL, EVENT_VSCROLL + int scroll_shift; + // face properties char* family; unsigned bold; @@ -1023,6 +1032,70 @@ return chr; } +static void apply_transition_effects(ass_event_t* event) +{ + int v[4]; + int cnt; + char* p = event->Effect; + + if (!p || !*p) return; + + cnt = 0; + while (cnt < 4 && (p = strchr(p, ';'))) { + v[cnt++] = atoi(++p); + } + + if (strncmp(event->Effect, "Banner;", 7) == 0) { + int delay; + if (cnt < 1) { + mp_msg(MSGT_GLOBAL, MSGL_V, "Error parsing effect: %s \n", event->Effect); + return; + } + if (cnt >= 2 && v[1] == 0) // right-to-left + render_context.scroll_direction = SCROLL_RL; + else // left-to-right + render_context.scroll_direction = SCROLL_LR; + + delay = v[0]; + if (delay == 0) delay = 1; // ? + render_context.scroll_shift = (frame_context.time - render_context.event->Start) / delay; + render_context.evt_type = EVENT_HSCROLL; + return; + } + + if (strncmp(event->Effect, "Scroll up;", 10) == 0) { + render_context.scroll_direction = SCROLL_BT; + } else if (strncmp(event->Effect, "Scroll down;", 12) == 0) { + render_context.scroll_direction = SCROLL_TB; + } else { + mp_msg(MSGT_GLOBAL, MSGL_V, "Unknown transition effect: %s \n", event->Effect); + return; + } + // parse scroll up/down parameters + { + int delay; + int y0, y1; + if (cnt < 3) { + mp_msg(MSGT_GLOBAL, MSGL_V, "Error parsing effect: %s \n", event->Effect); + return; + } + delay = v[2]; + if (delay == 0) delay = 1; // ? + render_context.scroll_shift = (frame_context.time - render_context.event->Start) / delay; + if (v[0] < v[1]) { + y0 = v[0]; y1 = v[1]; + } else { + y0 = v[1]; y1 = v[0]; + } + if (y1 == 0) + y1 = frame_context.track->PlayResY; // y0=y1=0 means fullscreen scrolling + render_context.clip_y0 = y0; + render_context.clip_y1 = y1; + render_context.evt_type = EVENT_VSCROLL; + } + +} + /** * \brief Start new event. Reset render_context. */ @@ -1078,6 +1151,8 @@ change_border(border); } } + + apply_transition_effects(event); return 0; } @@ -1430,7 +1505,7 @@ ass_style_t* style = frame_context.track->styles + event->Style; int last_break; int alignment, halign, valign; - int device_x, device_y; + int device_x = 0, device_y = 0; init_render_context(event); @@ -1541,17 +1616,6 @@ // depends on glyph x coordinates being monotonous, so it should be done before line wrap process_karaoke_effects(); - // calculate max length of a line - MarginL = (event->MarginL) ? event->MarginL : style->MarginL; - MarginR = (event->MarginR) ? event->MarginR : style->MarginR; - MarginV = (event->MarginV) ? event->MarginV : style->MarginV; - - max_text_width = x2scr(frame_context.track->PlayResX - MarginR) - x2scr(MarginL); - mp_msg(MSGT_GLOBAL, MSGL_DBG2, "normal text width: %d\n", max_text_width); - - // rearrange text in several lines - wrap_lines_smart(max_text_width); - // alignments alignment = render_context.alignment; if (!alignment) @@ -1559,6 +1623,17 @@ halign = alignment & 3; valign = alignment & 12; + MarginL = (event->MarginL) ? event->MarginL : style->MarginL; + MarginR = (event->MarginR) ? event->MarginR : style->MarginR; + MarginV = (event->MarginV) ? event->MarginV : style->MarginV; + + if (render_context.evt_type != EVENT_HSCROLL) { + // calculate max length of a line + max_text_width = x2scr(frame_context.track->PlayResX - MarginR) - x2scr(MarginL); + + // rearrange text in several lines + wrap_lines_smart(max_text_width); + // align text last_break = -1; for (i = 1; i < text_info.length + 1; ++i) { // (text_info.length + 1) is the end of the last line @@ -1584,17 +1659,27 @@ last_break = i - 1; } } + } // determing text bounding box compute_string_bbox(&text_info, &bbox); // determine device coordinates for text + + // x coordinate for everything except positioned events + if (render_context.evt_type == EVENT_NORMAL || + render_context.evt_type == EVENT_VSCROLL) { + device_x = x2scr(MarginL); + } else if (render_context.evt_type == EVENT_HSCROLL) { + if (render_context.scroll_direction == SCROLL_RL) + device_x = x2scr(frame_context.track->PlayResX - render_context.scroll_shift); + else if (render_context.scroll_direction == SCROLL_LR) + device_x = x2scr(render_context.scroll_shift) - (bbox.xMax - bbox.xMin); + } - // FIXME: using current font descender, ascender and height here is wrong. - // correct way is using max(descender) over all the fonts used in a line - // the same for height and ascender - if (render_context.evt_type == EVENT_NORMAL) { - device_x = x2scr(MarginL); + // y coordinate for everything except positioned events + if (render_context.evt_type == EVENT_NORMAL || + render_context.evt_type == EVENT_HSCROLL) { if (valign == VALIGN_TOP) { // toptitle device_y = y2scr_top(MarginV) + (text_info.lines[0].asc >> 6); if (render_context.detect_collisions) { @@ -1617,7 +1702,15 @@ frame_context.add_bottom_margin += (text_info.height >> 6); } } - } else if (render_context.evt_type == EVENT_POSITIONED) { + } else if (render_context.evt_type == EVENT_VSCROLL) { + if (render_context.scroll_direction == SCROLL_TB) + device_y = y2scr(render_context.clip_y0 + render_context.scroll_shift) - (bbox.yMax - bbox.yMin); + else if (render_context.scroll_direction == SCROLL_BT) + device_y = y2scr(render_context.clip_y1 - render_context.scroll_shift); + } + + // positioned events are totally different + if (render_context.evt_type == EVENT_POSITIONED) { int align_shift_x = 0; int align_shift_y = 0; mp_msg(MSGT_GLOBAL, MSGL_DBG2, "positioned event at %d, %d\n", render_context.pos_x, render_context.pos_y); @@ -1645,16 +1738,14 @@ } device_x = x2scr(render_context.pos_x) + align_shift_x; device_y = y2scr(render_context.pos_y) + align_shift_y; - } else { - mp_msg(MSGT_GLOBAL, MSGL_V, "unknown evt_type\n"); - device_x = 10; - device_y = 10; } // fix clip coordinates (they depend on alignment) render_context.clip_x0 = x2scr(render_context.clip_x0); render_context.clip_x1 = x2scr(render_context.clip_x1); - if (render_context.evt_type == EVENT_NORMAL) { + if (render_context.evt_type == EVENT_NORMAL || + render_context.evt_type == EVENT_HSCROLL || + render_context.evt_type == EVENT_VSCROLL) { if (valign == VALIGN_TOP) { render_context.clip_y0 = y2scr_top(render_context.clip_y0); render_context.clip_y1 = y2scr_top(render_context.clip_y1);