ass_render.c

来自「君正早期ucos系统(只有早期的才不没有打包成库),MPLAYER,文件系统,图」· C语言 代码 · 共 2,195 行 · 第 1/5 页

C
2,195
字号
		int cnt;		long long t1, t2, t, delta_t;		double k;		skip('(');		for (cnt = 0; cnt < 3; ++cnt) {			if (*p == '\\')				break;			v[cnt] = strtod(p, &p);			skip(',');		}		if (cnt == 3) {			v1 = v[0]; v2 = v[1]; v3 = v[2];		} else if (cnt == 2) {			v1 = v[0]; v2 = v[1]; v3 = 1.;		} else if (cnt == 1) {			v1 = 0; v2 = render_context.event->Duration; v3 = v[0];		} else { // cnt == 0			v1 = 0; v2 = render_context.event->Duration; v3 = 1.;		}		render_context.detect_collisions = 0;		t1 = v1;		t2 = v2;		delta_t = v2 - v1;		if (v3 < 0.)			v3 = 0.;		t = frame_context.time - render_context.event->Start; // FIXME: move to render_context		if (t <= t1)			k = 0.;		else if (t >= t2)			k = 1.;		else {			assert(delta_t != 0.);			k = pow(((double)(t - t1)) / delta_t, v3);		}		while (*p == '\\')			p = parse_tag(p, k); // maybe k*pwr ? no, specs forbid nested \t's 		skip_all(')'); // FIXME: better skip(')'), but much more tags support required	} else if (mystrcmp(&p, "clip")) {		int x0, y0, x1, y1;		int res = 1;		skip('(');		res &= mystrtoi(&p, 10, &x0);		skip(',');		res &= mystrtoi(&p, 10, &y0);		skip(',');		res &= mystrtoi(&p, 10, &x1);		skip(',');		res &= mystrtoi(&p, 10, &y1);		skip(')');		if (res) {			render_context.clip_x0 = render_context.clip_x0 * (1-pwr) + x0 * pwr;			render_context.clip_x1 = render_context.clip_x1 * (1-pwr) + x1 * pwr;			render_context.clip_y0 = render_context.clip_y0 * (1-pwr) + y0 * pwr;			render_context.clip_y1 = render_context.clip_y1 * (1-pwr) + y1 * pwr;		} else {			render_context.clip_x0 = 0;			render_context.clip_y0 = 0;			render_context.clip_x1 = frame_context.track->PlayResX;			render_context.clip_y1 = frame_context.track->PlayResY;		}	} else if (mystrcmp(&p, "c")) {		uint32_t val;		if (!strtocolor(&p, &val))			val = render_context.style->PrimaryColour;		mp_msg(MSGT_ASS, MSGL_DBG2, "color: %X\n", val);		change_color(&render_context.c[0], val, pwr);	} else if ((*p >= '1') && (*p <= '4') && (++p) && (mystrcmp(&p, "c") || mystrcmp(&p, "a"))) {		char n = *(p-2);		int cidx = n - '1';		char cmd = *(p-1);		uint32_t val;		assert((n >= '1') && (n <= '4'));		if (!strtocolor(&p, &val))			switch(n) {				case '1': val = render_context.style->PrimaryColour; break;				case '2': val = render_context.style->SecondaryColour; break;				case '3': val = render_context.style->OutlineColour; break;				case '4': val = render_context.style->BackColour; break;				default : val = 0; break; // impossible due to assert; avoid compilation warning			}		switch (cmd) {			case 'c': change_color(render_context.c + cidx, val, pwr); break;			case 'a': change_alpha(render_context.c + cidx, val >> 24, pwr); break;			default: mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_BadCommand, n, cmd); break;		}		mp_msg(MSGT_ASS, MSGL_DBG2, "single c/a at %f: %c%c = %X   \n", pwr, n, cmd, render_context.c[cidx]);	} else if (mystrcmp(&p, "r")) {		reset_render_context();	} else if (mystrcmp(&p, "be")) {		int val;		if (mystrtoi(&p, 10, &val))			render_context.be = val ? 1 : 0;		else			render_context.be = 0;	} else if (mystrcmp(&p, "b")) {		int b;		if (mystrtoi(&p, 10, &b)) {			if (pwr >= .5)				render_context.bold = b;		} else			render_context.bold = render_context.style->Bold;		update_font();	} else if (mystrcmp(&p, "i")) {		int i;		if (mystrtoi(&p, 10, &i)) {			if (pwr >= .5)				render_context.italic = i;		} else			render_context.italic = render_context.style->Italic;		update_font();	} else if (mystrcmp(&p, "kf") || mystrcmp(&p, "K")) {		int val = strtol(p, &p, 10);		render_context.effect_type = EF_KARAOKE_KF;		if (render_context.effect_timing)			render_context.effect_skip_timing += render_context.effect_timing;		render_context.effect_timing = val * 10;	} else if (mystrcmp(&p, "ko")) {		int val = strtol(p, &p, 10);		render_context.effect_type = EF_KARAOKE_KO;		if (render_context.effect_timing)			render_context.effect_skip_timing += render_context.effect_timing;		render_context.effect_timing = val * 10;	} else if (mystrcmp(&p, "k")) {		int val = strtol(p, &p, 10);		render_context.effect_type = EF_KARAOKE;		if (render_context.effect_timing)			render_context.effect_skip_timing += render_context.effect_timing;		render_context.effect_timing = val * 10;	} else if (mystrcmp(&p, "shad")) {		int val;		if (mystrtoi(&p, 10, &val))			render_context.shadow = val;		else			render_context.shadow = render_context.style->Shadow;	}	return p;#undef skip#undef skip_all}/** * \brief Get next ucs4 char from string, parsing and executing style overrides * \param str string pointer * \return ucs4 code of the next char * On return str points to the unparsed part of the string */static unsigned get_next_char(char** str){	char* p = *str;	unsigned chr;	if (*p == '{') { // '\0' goes here		p++;		while (1) {			p = parse_tag(p, 1.);			if (*p == '}') { // end of tag				p++;				if (*p == '{') {					p++;					continue;				} else					break;			} else if (*p != '\\')				mp_msg(MSGT_ASS, MSGL_V, "Unable to parse: \"%s\" \n", p);			if (*p == 0)				break;		}	}	if (*p == '\t') {		++p;		*str = p;		return ' ';	}	if (*p == '\\') {		if ((*(p+1) == 'N') || ((*(p+1) == 'n') && (frame_context.track->WrapStyle == 2))) {			p += 2;			*str = p;			return '\n';		} else if (*(p+1) == 'n') {			p += 2;			*str = p;			return ' ';		}	}	chr = utf8_get_char(&p);	*str = p;	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_ASS, 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_ASS, 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_ASS, 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;		render_context.detect_collisions = 0;	}}/** * \brief partially reset render_context to style values * Works like {\r}: resets some style overrides */static void reset_render_context(void){	render_context.c[0] = render_context.style->PrimaryColour;	render_context.c[1] = render_context.style->SecondaryColour;	render_context.c[2] = render_context.style->OutlineColour;	render_context.c[3] = render_context.style->BackColour;	render_context.font_size = render_context.style->FontSize;	if (render_context.family)		free(render_context.family);	render_context.family = strdup(render_context.style->FontName);	render_context.bold = render_context.style->Bold;	render_context.italic = render_context.style->Italic;	update_font();	change_border(-1.);	render_context.scale_x = render_context.style->ScaleX;	render_context.scale_y = render_context.style->ScaleY;	render_context.hspacing = render_context.style->Spacing;	render_context.be = 0;	render_context.shadow = render_context.style->Shadow;	render_context.frx = render_context.fry = 0.;	render_context.frz = M_PI * render_context.style->Angle / 180.;	// FIXME: does not reset unsupported attributes.}/** * \brief Start new event. Reset render_context. */static void init_render_context(ass_event_t* event){	render_context.event = event;	render_context.style = frame_context.track->styles + event->Style;	reset_render_context();	render_context.evt_type = EVENT_NORMAL;	render_context.alignment = render_context.style->Alignment;	render_context.pos_x = 0;	render_context.pos_y = 0;	render_context.org_x = 0;	render_context.org_y = 0;	render_context.have_origin = 0;	render_context.clip_x0 = 0;	render_context.clip_y0 = 0;	render_context.clip_x1 = frame_context.track->PlayResX;	render_context.clip_y1 = frame_context.track->PlayResY;	render_context.detect_collisions = 1;	render_context.fade = 0;	render_context.effect_type = EF_NONE;	render_context.effect_timing = 0;	render_context.effect_skip_timing = 0;		apply_transition_effects(event);}static void free_render_context(void){}/** * \brief Get normal and outline (border) glyphs * \param symbol ucs4 char * \param info out: struct filled with extracted data * \param advance subpixel shift vector used for cache lookup * Tries to get both glyphs from cache. * If they can't be found, gets a glyph from font face, generates outline with FT_Stroker, * and add them to cache. * The glyphs are returned in info->glyph and info->outline_glyph */static void get_outline_glyph(int symbol, glyph_info_t* info, FT_Vector* advance){	int error;	glyph_hash_val_t* val;	glyph_hash_key_t key;	key.font = render_context.font;	key.size = render_context.font_size;	key.ch = symbol;	key.scale_x = (render_context.scale_x * 0xFFFF);	key.scale_y = (render_context.scale_y * 0xFFFF);	key.advance = *advance;	key.bold = render_context.bold;	key.italic = render_context.italic;	key.outline = render_context.border * 0xFFFF;	info->glyph = info->outline_glyph = 0;	val = cache_find_glyph(&key);	if (val) {		FT_Glyph_Copy(val->glyph, &info->glyph);		if (val->outline_glyph)			FT_Glyph_Copy(val->outline_glyph, &info->outline_glyph);		info->bbox = val->bbox_scaled;		info->advance.x = val->advance.x;		info->advance.y = val->advance.y;	} else {		glyph_hash_val_t v;		info->glyph = ass_font_get_glyph(frame_context.ass_priv->fontconfig_priv, render_context.font, symbol, global_settings->hinting);		if (!info->glyph)			return;		info->advance.x = d16_to_d6(info->glyph->advance.x);		info->advance.y = d16_to_d6(info->glyph->advance.y);		FT_Glyph_Get_CBox( info->glyph, FT_GLYPH_BBOX_PIXELS, &info->bbox);		if (render_context.stroker) {			info->outline_glyph = info->glyph;			error = FT_Glyph_StrokeBorder( &(info->outline_glyph), render_context.stroker, 0 , 0 ); // don't destroy original			if (error) {				mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_FT_Glyph_Stroke_Error, error);			}		}		memset(&v, 0, sizeof(v));		FT_Glyph_Copy(info->glyph, &v.glyph);		if (info->outline_glyph)			FT_Glyph_Copy(info->outline_glyph, &v.outline_glyph);		v.advance = info->advance;		v.bbox_scaled = info->bbox;		cache_add_glyph(&key, &v);	}}static void transform_3d(FT_Vector shift, FT_Glyph* glyph, FT_Glyph* glyph2, double frx, double fry, double frz);/** * \brief Get bitmaps for a glyph * \param info glyph info * Tries to get glyph bitmaps from bitmap cache. * If they can't be found, they are generated by rotating and rendering the glyph. * After that, bitmaps are added to the cache. * They are returned in info->bm (glyph), info->bm_o (outline) and info->bm_s (shadow). */static void get_bitmap_glyph(glyph_info_t* info){	bitmap_hash_val_t* val;	bitmap_hash_key_t* key = &info->hash_key;		val = cache_find_bitmap(key);/* 	val = 0; */		if (val) {		info->bm = val->bm;		info->bm_o = val->bm_o;		info->bm_s = val->bm_s;	} else {		FT_Vector shift;		bitmap_hash_val_t hash_val;		int error;		info->bm = info->bm_o = info->bm_s = 0;		if (info->glyph && info->symbol != '\n' && info->symbol != 0) {			// calculating rotation shift vector (from rotation origin to the glyph basepoint)			shift.x = int_to_d6(info->hash_key.shift_x);			shift.y = int_to_d6(info->hash_key.shift_y);			// apply rotation			transform_3d(shift, &info->glyph, &info->outline_glyph, info->frx, info->fry, info->frz);			// render glyph			error = glyph_to_bitmap(ass_renderer->synth_priv,					info->glyph, info->outline_glyph,					&info->bm, &info->bm_o,					&info->bm_s, info->be);			if (error)				info->symbol = 0;			// add bitmaps to cache			hash_val.bm_o = info->bm_o;			hash_val.bm = info->bm;			hash_val.bm_s = info->bm_s;			cache_add_bitmap(&(info->hash_key), &hash_val);		}	}	// deallocate glyphs	if (info->glyph)		FT_Done_Glyph(info->glyph);	if (info->outline_glyph)		FT_Done_Glyph(info->outline_glyph);}/**

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?