changeset 19965:70352570e9ae

Shadow support in libass.
author eugeni
date Sun, 24 Sep 2006 16:04:37 +0000
parents edee81101156
children 27187c1ac20b
files libass/ass_bitmap.c libass/ass_bitmap.h libass/ass_cache.c libass/ass_cache.h libass/ass_render.c
diffstat 5 files changed, 63 insertions(+), 14 deletions(-) [+]
line wrap: on
line diff
--- a/libass/ass_bitmap.c	Sun Sep 24 15:55:10 2006 +0000
+++ b/libass/ass_bitmap.c	Sun Sep 24 16:04:37 2006 +0000
@@ -122,6 +122,15 @@
 	}
 }
 
+static bitmap_t* copy_bitmap(const bitmap_t* src)
+{
+	bitmap_t* dst = alloc_bitmap(src->w, src->h);
+	dst->left = src->left;
+	dst->top = src->top;
+	memcpy(dst->buffer, src->buffer, src->w * src->h);
+	return dst;
+}
+
 static bitmap_t* glyph_to_bitmap_internal(FT_Glyph glyph, int bord)
 {
 	FT_BitmapGlyph bg;
@@ -165,15 +174,19 @@
 	return bm;
 }
 
-static void fix_outline(bitmap_t* bm_g, bitmap_t* bm_o)
+static bitmap_t* fix_outline_and_shadow(bitmap_t* bm_g, bitmap_t* bm_o)
 {
 	int x, y;
 	const int l = bm_o->left > bm_g->left ? bm_o->left : bm_g->left;
 	const int t = bm_o->top > bm_g->top ? bm_o->top : bm_g->top;
 	const int r = bm_o->left + bm_o->w < bm_g->left + bm_g->w ? bm_o->left + bm_o->w : bm_g->left + bm_g->w;
 	const int b = bm_o->top + bm_o->h < bm_g->top + bm_g->h ? bm_o->top + bm_o->h : bm_g->top + bm_g->h;
+
+	bitmap_t* bm_s = copy_bitmap(bm_o);
+
 	unsigned char* g = bm_g->buffer + (t - bm_g->top) * bm_g->w + (l - bm_g->left);
 	unsigned char* o = bm_o->buffer + (t - bm_o->top) * bm_o->w + (l - bm_o->left);
+	unsigned char* s = bm_s->buffer + (t - bm_s->top) * bm_s->w + (l - bm_s->left);
 	
 	for (y = 0; y < b - t; ++y) {
 		for (x = 0; x < r - l; ++x) {
@@ -181,33 +194,38 @@
 			c_g = g[x];
 			c_o = o[x];
 			o[x] = (c_o > c_g) ? c_o - c_g : 0;
+			s[x] = (c_o < 0xFF - c_g) ? c_o + c_g : 0xFF;
 		}
 		g += bm_g->w;
 		o += bm_o->w;
+		s += bm_s->w;
 	}
+
+	assert(bm_s);
+	return bm_s;
 }
 
-int glyph_to_bitmap(ass_synth_priv_t* priv, FT_Glyph glyph, FT_Glyph outline_glyph, bitmap_t** bm_g, bitmap_t** bm_o, int be)
+int glyph_to_bitmap(ass_synth_priv_t* priv, FT_Glyph glyph, FT_Glyph outline_glyph,
+		bitmap_t** bm_g, bitmap_t** bm_o, bitmap_t** bm_s, int be)
 {
 	const int bord = be ? ceil(blur_radius) : 0;
 
-	assert(bm_g && bm_o);
+	assert(bm_g && bm_o && bm_s);
+
+	*bm_g = *bm_o = *bm_s = 0;
 
 	if (glyph)
 		*bm_g = glyph_to_bitmap_internal(glyph, bord);
-	else
-		*bm_g = 0;
 	if (!*bm_g)
 		return 1;
+
 	if (outline_glyph) {
 		*bm_o = glyph_to_bitmap_internal(outline_glyph, bord);
 		if (!*bm_o) {
 			ass_free_bitmap(*bm_g);
 			return 1;
 		}
-	} else
-		*bm_o = 0;
-
+	}
 	if (*bm_o)
 		resize_tmp(priv, (*bm_o)->w, (*bm_o)->h);
 	resize_tmp(priv, (*bm_g)->w, (*bm_g)->h);
@@ -219,8 +237,11 @@
 	}
 
 	if (*bm_o)
-		fix_outline(*bm_g, *bm_o);
+		*bm_s = fix_outline_and_shadow(*bm_g, *bm_o);
+	else
+		*bm_s = copy_bitmap(*bm_g);
 
+	assert(bm_s);
 	return 0;
 }
 
--- a/libass/ass_bitmap.h	Sun Sep 24 15:55:10 2006 +0000
+++ b/libass/ass_bitmap.h	Sun Sep 24 16:04:37 2006 +0000
@@ -12,7 +12,7 @@
 	unsigned char* buffer; // w x h buffer
 } bitmap_t;
 
-int glyph_to_bitmap(ass_synth_priv_t* priv, FT_Glyph glyph, FT_Glyph outline_glyph, bitmap_t** bm_g, bitmap_t** bm_o, int be);
+int glyph_to_bitmap(ass_synth_priv_t* priv, FT_Glyph glyph, FT_Glyph outline_glyph, bitmap_t** bm_g, bitmap_t** bm_o, bitmap_t** bm_s, int be);
 void ass_free_bitmap(bitmap_t* bm);
 
 #endif
--- a/libass/ass_cache.c	Sun Sep 24 15:55:10 2006 +0000
+++ b/libass/ass_cache.c	Sun Sep 24 16:04:37 2006 +0000
@@ -202,6 +202,7 @@
 			glyph_hash_item_t* next = item->next;
 			if (item->val.bm) ass_free_bitmap(item->val.bm);
 			if (item->val.bm_o) ass_free_bitmap(item->val.bm_o);
+			if (item->val.bm_s) ass_free_bitmap(item->val.bm_s);
 			free(item);
 			item = next;
 		}
--- a/libass/ass_cache.h	Sun Sep 24 15:55:10 2006 +0000
+++ b/libass/ass_cache.h	Sun Sep 24 16:04:37 2006 +0000
@@ -38,6 +38,7 @@
 typedef struct glyph_hash_val_s {
 	bitmap_t* bm; // the actual glyph bitmaps
 	bitmap_t* bm_o;
+	bitmap_t* bm_s;
 	FT_BBox bbox_scaled; // bbox after scaling, but before rotation
 	FT_Vector advance; // 26.6, advance distance to the next glyph in line
 } glyph_hash_val_t;
--- a/libass/ass_render.c	Sun Sep 24 15:55:10 2006 +0000
+++ b/libass/ass_render.c	Sun Sep 24 16:04:37 2006 +0000
@@ -53,8 +53,9 @@
 	unsigned symbol;
 	FT_Glyph glyph;
 	FT_Glyph outline_glyph;
-	bitmap_t* bm;
-	bitmap_t* bm_o;
+	bitmap_t* bm; // glyph bitmap
+	bitmap_t* bm_o; // outline bitmap
+	bitmap_t* bm_s; // shadow bitmap
 	FT_BBox bbox;
 	FT_Vector pos;
 	char linebreak; // the first (leading) glyph of some line ?
@@ -68,6 +69,7 @@
 	int asc, desc; // font max ascender and descender
 //	int height;
 	int be; // blur edges
+	int shadow;
 	
 	glyph_hash_key_t hash_key;
 } glyph_info_t;
@@ -113,6 +115,7 @@
 	char detect_collisions;
 	uint32_t fade; // alpha from \fad
 	char be; // blur edges
+	int shadow;
 
 	effect_t effect_type;
 	int effect_timing;
@@ -376,7 +379,8 @@
 				continue;
 			error = glyph_to_bitmap(ass_instance->synth_priv,
 					text_info->glyphs[i].glyph, text_info->glyphs[i].outline_glyph,
-					&text_info->glyphs[i].bm, &text_info->glyphs[i].bm_o, text_info->glyphs[i].be);
+					&text_info->glyphs[i].bm, &text_info->glyphs[i].bm_o,
+					&text_info->glyphs[i].bm_s, text_info->glyphs[i].be);
 			if (error)
 				text_info->glyphs[i].symbol = 0;
 			FT_Done_Glyph(text_info->glyphs[i].glyph);
@@ -387,6 +391,7 @@
 			hash_val.bbox_scaled = text_info->glyphs[i].bbox;
 			hash_val.bm_o = text_info->glyphs[i].bm_o;
 			hash_val.bm = text_info->glyphs[i].bm;
+			hash_val.bm_s = text_info->glyphs[i].bm_s;
 			hash_val.advance.x = text_info->glyphs[i].advance.x;
 			hash_val.advance.y = text_info->glyphs[i].advance.y;
 			cache_add_glyph(&(text_info->glyphs[i].hash_key), &hash_val);
@@ -396,6 +401,18 @@
 
 	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))
+			continue;
+
+		pen_x = dst_x + info->pos.x + info->shadow;
+		pen_y = dst_y + info->pos.y + info->shadow;
+		bm = info->bm_s;
+
+		tail = render_glyph(bm, pen_x, pen_y, info->c[3], 0, 1000000, tail);
+	}
+
+	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_o)
 			continue;
 
@@ -992,6 +1009,12 @@
 		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;
@@ -1137,6 +1160,7 @@
 	render_context.scale_y = render_context.style->ScaleY;
 	render_context.hspacing = 0; // FIXME
 	render_context.be = 0;
+	render_context.shadow = render_context.style->Shadow;
 
 	// FIXME: does not reset unsupported attributes.
 }
@@ -1208,6 +1232,7 @@
 		info->glyph = info->outline_glyph = 0;
 		info->bm = val->bm;
 		info->bm_o = val->bm_o;
+		info->bm_s = val->bm_s;
 		info->bbox = val->bbox_scaled;
 		info->advance.x = val->advance.x;
 		info->advance.y = val->advance.y;
@@ -1252,7 +1277,7 @@
 		info->outline_glyph = 0;
 	}
 
-	info->bm = info->bm_o = 0;
+	info->bm = info->bm_o = info->bm_s = 0;
 
 	return 0;
 }
@@ -1625,6 +1650,7 @@
 		text_info.glyphs[text_info.length].asc = get_face_ascender(render_context.face);
 		text_info.glyphs[text_info.length].desc = get_face_descender(render_context.face);
 		text_info.glyphs[text_info.length].be = render_context.be;
+		text_info.glyphs[text_info.length].shadow = render_context.shadow;
 
 		text_info.length++;