Browse Source

wip distance field font import

font import may not work if using distance field, this is WIP
Juan Linietsky 10 years ago
parent
commit
90a84b4ddb
1 changed files with 297 additions and 50 deletions
  1. 297 50
      tools/editor/io_plugins/editor_font_import_plugin.cpp

+ 297 - 50
tools/editor/io_plugins/editor_font_import_plugin.cpp

@@ -47,6 +47,12 @@ class _EditorFontImportOptions : public Object {
 	OBJ_TYPE(_EditorFontImportOptions,Object);
 	OBJ_TYPE(_EditorFontImportOptions,Object);
 public:
 public:
 
 
+	enum FontMode {
+
+		FONT_BITMAP,
+		FONT_DISTANCE_FIELD
+	};
+
 	enum ColorType {
 	enum ColorType {
 		COLOR_WHITE,
 		COLOR_WHITE,
 		COLOR_CUSTOM,
 		COLOR_CUSTOM,
@@ -69,6 +75,9 @@ public:
 		CHARSET_CUSTOM_LATIN
 		CHARSET_CUSTOM_LATIN
 	};
 	};
 
 
+
+	FontMode font_mode;
+
 	CharacterSet character_set;
 	CharacterSet character_set;
 	String custom_file;
 	String custom_file;
 
 
@@ -91,7 +100,6 @@ public:
 	bool color_use_monochrome;
 	bool color_use_monochrome;
 	String gradient_image;
 	String gradient_image;
 
 
-
 	bool disable_filter;
 	bool disable_filter;
 	bool round_advance;
 	bool round_advance;
 
 
@@ -100,7 +108,10 @@ public:
 	bool _set(const StringName& p_name, const Variant& p_value) {
 	bool _set(const StringName& p_name, const Variant& p_value) {
 
 
 		String n = p_name;
 		String n = p_name;
-		if (n=="extra_space/char")
+		if (n=="mode/mode") {
+			font_mode=FontMode(int(p_value));
+			_change_notify();
+		} else if (n=="extra_space/char")
 			char_extra_spacing=p_value;
 			char_extra_spacing=p_value;
 		else if (n=="extra_space/space")
 		else if (n=="extra_space/space")
 			space_extra_spacing=p_value;
 			space_extra_spacing=p_value;
@@ -169,7 +180,9 @@ public:
 	bool _get(const StringName& p_name,Variant &r_ret) const{
 	bool _get(const StringName& p_name,Variant &r_ret) const{
 
 
 		String n = p_name;
 		String n = p_name;
-		if (n=="extra_space/char")
+		if (n=="mode/mode")
+			r_ret=font_mode;
+		else if (n=="extra_space/char")
 			r_ret=char_extra_spacing;
 			r_ret=char_extra_spacing;
 		else if (n=="extra_space/space")
 		else if (n=="extra_space/space")
 			r_ret=space_extra_spacing;
 			r_ret=space_extra_spacing;
@@ -231,6 +244,9 @@ public:
 
 
 	void _get_property_list( List<PropertyInfo> *p_list) const{
 	void _get_property_list( List<PropertyInfo> *p_list) const{
 
 
+
+		p_list->push_back(PropertyInfo(Variant::INT,"mode/mode",PROPERTY_HINT_ENUM,"Bitmap,Distance Field"));
+
 		p_list->push_back(PropertyInfo(Variant::INT,"extra_space/char",PROPERTY_HINT_RANGE,"-64,64,1"));
 		p_list->push_back(PropertyInfo(Variant::INT,"extra_space/char",PROPERTY_HINT_RANGE,"-64,64,1"));
 		p_list->push_back(PropertyInfo(Variant::INT,"extra_space/space",PROPERTY_HINT_RANGE,"-64,64,1"));
 		p_list->push_back(PropertyInfo(Variant::INT,"extra_space/space",PROPERTY_HINT_RANGE,"-64,64,1"));
 		p_list->push_back(PropertyInfo(Variant::INT,"extra_space/top",PROPERTY_HINT_RANGE,"-64,64,1"));
 		p_list->push_back(PropertyInfo(Variant::INT,"extra_space/top",PROPERTY_HINT_RANGE,"-64,64,1"));
@@ -240,35 +256,45 @@ public:
 		if (character_set>=CHARSET_CUSTOM)
 		if (character_set>=CHARSET_CUSTOM)
 			p_list->push_back(PropertyInfo(Variant::STRING,"character_set/custom",PROPERTY_HINT_FILE));
 			p_list->push_back(PropertyInfo(Variant::STRING,"character_set/custom",PROPERTY_HINT_FILE));
 
 
-		p_list->push_back(PropertyInfo(Variant::BOOL,"shadow/enabled"));
-		if (shadow) {
-			p_list->push_back(PropertyInfo(Variant::INT,"shadow/radius",PROPERTY_HINT_RANGE,"-64,64,1"));
-			p_list->push_back(PropertyInfo(Variant::VECTOR2,"shadow/offset"));
-			p_list->push_back(PropertyInfo(Variant::COLOR,"shadow/color"));
-			p_list->push_back(PropertyInfo(Variant::REAL,"shadow/transition",PROPERTY_HINT_EXP_EASING));
-		}
+		int usage = PROPERTY_USAGE_DEFAULT;
 
 
-		p_list->push_back(PropertyInfo(Variant::BOOL,"shadow2/enabled"));
-		if (shadow2) {
-			p_list->push_back(PropertyInfo(Variant::INT,"shadow2/radius",PROPERTY_HINT_RANGE,"-64,64,1"));
-			p_list->push_back(PropertyInfo(Variant::VECTOR2,"shadow2/offset"));
-			p_list->push_back(PropertyInfo(Variant::COLOR,"shadow2/color"));
-			p_list->push_back(PropertyInfo(Variant::REAL,"shadow2/transition",PROPERTY_HINT_EXP_EASING));
+		if (font_mode==FONT_DISTANCE_FIELD) {
+			usage = PROPERTY_USAGE_NOEDITOR;
 		}
 		}
 
 
-		p_list->push_back(PropertyInfo(Variant::INT,"color/mode",PROPERTY_HINT_ENUM,"White,Color,Gradient,Gradient Image"));
-		if (color_type==COLOR_CUSTOM) {
-			p_list->push_back(PropertyInfo(Variant::COLOR,"color/color"));
+		{
 
 
+			p_list->push_back(PropertyInfo(Variant::BOOL,"shadow/enabled",PROPERTY_HINT_NONE,"",usage));
+			if (shadow) {
+				p_list->push_back(PropertyInfo(Variant::INT,"shadow/radius",PROPERTY_HINT_RANGE,"-64,64,1",usage));
+				p_list->push_back(PropertyInfo(Variant::VECTOR2,"shadow/offset",PROPERTY_HINT_NONE,"",usage));
+				p_list->push_back(PropertyInfo(Variant::COLOR,"shadow/color",PROPERTY_HINT_NONE,"",usage));
+				p_list->push_back(PropertyInfo(Variant::REAL,"shadow/transition",PROPERTY_HINT_EXP_EASING,"",usage));
+			}
+
+			p_list->push_back(PropertyInfo(Variant::BOOL,"shadow2/enabled",PROPERTY_HINT_NONE,"",usage));
+			if (shadow2) {
+				p_list->push_back(PropertyInfo(Variant::INT,"shadow2/radius",PROPERTY_HINT_RANGE,"-64,64,1",usage));
+				p_list->push_back(PropertyInfo(Variant::VECTOR2,"shadow2/offset",PROPERTY_HINT_NONE,"",usage));
+				p_list->push_back(PropertyInfo(Variant::COLOR,"shadow2/color",PROPERTY_HINT_NONE,"",usage));
+				p_list->push_back(PropertyInfo(Variant::REAL,"shadow2/transition",PROPERTY_HINT_EXP_EASING,"",usage));
+			}
+
+			p_list->push_back(PropertyInfo(Variant::INT,"color/mode",PROPERTY_HINT_ENUM,"White,Color,Gradient,Gradient Image",usage));
+			if (color_type==COLOR_CUSTOM) {
+				p_list->push_back(PropertyInfo(Variant::COLOR,"color/color",PROPERTY_HINT_NONE,"",usage));
+
+			}
+			if (color_type==COLOR_GRADIENT_RANGE) {
+				p_list->push_back(PropertyInfo(Variant::COLOR,"color/begin",PROPERTY_HINT_NONE,"",usage));
+				p_list->push_back(PropertyInfo(Variant::COLOR,"color/end",PROPERTY_HINT_NONE,"",usage));
+			}
+			if (color_type==COLOR_GRADIENT_IMAGE) {
+				p_list->push_back(PropertyInfo(Variant::STRING,"color/image",PROPERTY_HINT_FILE,"",usage));
+			}
+			p_list->push_back(PropertyInfo(Variant::BOOL,"color/monochrome",PROPERTY_HINT_NONE,"",usage));
 		}
 		}
-		if (color_type==COLOR_GRADIENT_RANGE) {
-			p_list->push_back(PropertyInfo(Variant::COLOR,"color/begin"));
-			p_list->push_back(PropertyInfo(Variant::COLOR,"color/end"));
-		}
-		if (color_type==COLOR_GRADIENT_IMAGE) {
-			p_list->push_back(PropertyInfo(Variant::STRING,"color/image",PROPERTY_HINT_FILE));
-		}
-		p_list->push_back(PropertyInfo(Variant::BOOL,"color/monochrome"));
+
 		p_list->push_back(PropertyInfo(Variant::BOOL,"advanced/round_advance"));
 		p_list->push_back(PropertyInfo(Variant::BOOL,"advanced/round_advance"));
 		p_list->push_back(PropertyInfo(Variant::BOOL,"advanced/disable_filter"));
 		p_list->push_back(PropertyInfo(Variant::BOOL,"advanced/disable_filter"));
 
 
@@ -307,6 +333,7 @@ public:
 		gradient_end=Color(0.5,0.5,0.5,1);
 		gradient_end=Color(0.5,0.5,0.5,1);
 		color_use_monochrome=false;
 		color_use_monochrome=false;
 
 
+		font_mode=FONT_BITMAP;
 		round_advance=true;
 		round_advance=true;
 		disable_filter=false;
 		disable_filter=false;
 
 
@@ -314,6 +341,8 @@ public:
 
 
 	_EditorFontImportOptions() {
 	_EditorFontImportOptions() {
 
 
+		font_mode=FONT_BITMAP;
+
 		char_extra_spacing=0;
 		char_extra_spacing=0;
 		top_extra_spacing=0;
 		top_extra_spacing=0;
 		bottom_extra_spacing=0;
 		bottom_extra_spacing=0;
@@ -706,6 +735,137 @@ struct _EditorKerningKey {
 
 
 };
 };
 
 
+
+static unsigned char get_SDF_radial(
+		unsigned char *fontmap,
+		int w, int h,
+		int x, int y,
+		int max_radius )
+{
+	//	hideous brute force method
+	float d2 = max_radius*max_radius+1.0;
+	unsigned char v = fontmap[x+y*w];
+	for( int radius = 1; (radius <= max_radius) && (radius*radius < d2); ++radius )
+	{
+		int line, lo, hi;
+		//	north
+		line = y - radius;
+		if( (line >= 0) && (line < h) )
+		{
+			lo = x - radius;
+			hi = x + radius;
+			if( lo < 0 ) { lo = 0; }
+			if( hi >= w ) { hi = w-1; }
+			int idx = line * w + lo;
+			for( int i = lo; i <= hi; ++i )
+			{
+				//	check this pixel
+				if( fontmap[idx] != v )
+				{
+					float nx = i - x;
+					float ny = line - y;
+					float nd2 = nx*nx+ny*ny;
+					if( nd2 < d2 )
+					{
+						d2 = nd2;
+					}
+				}
+				//	move on
+				++idx;
+			}
+		}
+		//	south
+		line = y + radius;
+		if( (line >= 0) && (line < h) )
+		{
+			lo = x - radius;
+			hi = x + radius;
+			if( lo < 0 ) { lo = 0; }
+			if( hi >= w ) { hi = w-1; }
+			int idx = line * w + lo;
+			for( int i = lo; i <= hi; ++i )
+			{
+				//	check this pixel
+				if( fontmap[idx] != v )
+				{
+					float nx = i - x;
+					float ny = line - y;
+					float nd2 = nx*nx+ny*ny;
+					if( nd2 < d2 )
+					{
+						d2 = nd2;
+					}
+				}
+				//	move on
+				++idx;
+			}
+		}
+		//	west
+		line = x - radius;
+		if( (line >= 0) && (line < w) )
+		{
+			lo = y - radius + 1;
+			hi = y + radius - 1;
+			if( lo < 0 ) { lo = 0; }
+			if( hi >= h ) { hi = h-1; }
+			int idx = lo * w + line;
+			for( int i = lo; i <= hi; ++i )
+			{
+				//	check this pixel
+				if( fontmap[idx] != v )
+				{
+					float nx = line - x;
+					float ny = i - y;
+					float nd2 = nx*nx+ny*ny;
+					if( nd2 < d2 )
+					{
+						d2 = nd2;
+					}
+				}
+				//	move on
+				idx += w;
+			}
+		}
+		//	east
+		line = x + radius;
+		if( (line >= 0) && (line < w) )
+		{
+			lo = y - radius + 1;
+			hi = y + radius - 1;
+			if( lo < 0 ) { lo = 0; }
+			if( hi >= h ) { hi = h-1; }
+			int idx = lo * w + line;
+			for( int i = lo; i <= hi; ++i )
+			{
+				//	check this pixel
+				if( fontmap[idx] != v )
+				{
+					float nx = line - x;
+					float ny = i - y;
+					float nd2 = nx*nx+ny*ny;
+					if( nd2 < d2 )
+					{
+						d2 = nd2;
+					}
+				}
+				//	move on
+				idx += w;
+			}
+		}
+	}
+	d2 = sqrtf( d2 );
+	if( v==0 )
+	{
+		d2 = -d2;
+	}
+	d2 *= 127.5 / max_radius;
+	d2 += 127.5;
+	if( d2 < 0.0 ) d2 = 0.0;
+	if( d2 > 255.0 ) d2 = 255.0;
+	return (unsigned char)(d2 + 0.5);
+}
+
+
 Ref<Font> EditorFontImportPlugin::generate_font(const Ref<ResourceImportMetadata>& p_from, const String &p_existing) {
 Ref<Font> EditorFontImportPlugin::generate_font(const Ref<ResourceImportMetadata>& p_from, const String &p_existing) {
 
 
 	Ref<ResourceImportMetadata> from = p_from;
 	Ref<ResourceImportMetadata> from = p_from;
@@ -754,7 +914,11 @@ Ref<Font> EditorFontImportPlugin::generate_font(const Ref<ResourceImportMetadata
 
 
 	}
 	}
 
 
-	error = FT_Set_Pixel_Sizes(face,0,size);
+	int font_mode = from->get_option("mode/mode");
+
+	int scaler=(font_mode==_EditorFontImportOptions::FONT_DISTANCE_FIELD)?16:1;
+
+	error = FT_Set_Pixel_Sizes(face,0,size*scaler);
 
 
 	FT_GlyphSlot slot = face->glyph;
 	FT_GlyphSlot slot = face->glyph;
 
 
@@ -822,7 +986,7 @@ Ref<Font> EditorFontImportPlugin::generate_font(const Ref<ResourceImportMetadata
 		bool skip=false;
 		bool skip=false;
 		error = FT_Load_Char( face, charcode, FT_LOAD_RENDER );
 		error = FT_Load_Char( face, charcode, FT_LOAD_RENDER );
 		if (error) skip=true;
 		if (error) skip=true;
-		else error = FT_Render_Glyph( face->glyph, ft_render_mode_normal );
+		else error = FT_Render_Glyph( face->glyph, font_mode==_EditorFontImportOptions::FONT_BITMAP?ft_render_mode_normal:ft_render_mode_mono );
 		if (error) {
 		if (error) {
 			skip=true;
 			skip=true;
 		} else if (!skip) {
 		} else if (!skip) {
@@ -847,28 +1011,35 @@ Ref<Font> EditorFontImportPlugin::generate_font(const Ref<ResourceImportMetadata
 		}
 		}
 
 
 		_EditorFontData * fdata = memnew( _EditorFontData );
 		_EditorFontData * fdata = memnew( _EditorFontData );
-		fdata->bitmap.resize( slot->bitmap.width*slot->bitmap.rows );
-		fdata->width=slot->bitmap.width;
-		fdata->height=slot->bitmap.rows;
-		fdata->character=charcode;
-		fdata->glyph=FT_Get_Char_Index(face,charcode);
-		if  (charcode=='x')
-			xsize=slot->bitmap.width;
 
 
 
 
-		if (charcode<127) {
-			if (slot->bitmap_top>max_up) {
-
-				max_up=slot->bitmap_top;
-			}
+		int w = slot->bitmap.width;
+		int h = slot->bitmap.rows;
+		int p = slot->bitmap.pitch;
+		print_line("pitch "+itos(slot->bitmap.pitch));
 
 
+		if (font_mode==_EditorFontImportOptions::FONT_DISTANCE_FIELD) {
 
 
-			if ( (slot->bitmap_top - fdata->height)<max_down ) {
+			//	oversize the holding buffer so I can smooth it!
+			int sw = w + scaler * 4;
+			int sh = h + scaler * 4;
+			//	do the SDF
+			int sdfw = sw / scaler;
+			int sdfh = sh / scaler;
 
 
-				max_down=slot->bitmap_top - fdata->height;
-			}
+			fdata->width=sdfw;
+			fdata->height=sdfh;
+		} else {
+			fdata->width=w;
+			fdata->height=h;
 		}
 		}
 
 
+		fdata->character=charcode;
+		fdata->glyph=FT_Get_Char_Index(face,charcode);
+		if  (charcode=='x')
+			xsize=w/scaler;
+
+
 
 
 		fdata->valign=slot->bitmap_top;
 		fdata->valign=slot->bitmap_top;
 		fdata->halign=slot->bitmap_left;
 		fdata->halign=slot->bitmap_left;
@@ -878,12 +1049,87 @@ Ref<Font> EditorFontImportPlugin::generate_font(const Ref<ResourceImportMetadata
 		else
 		else
 			fdata->advance=slot->advance.x/float(1<<6);
 			fdata->advance=slot->advance.x/float(1<<6);
 
 
+		fdata->advance/=scaler;
+
+		if (font_mode==_EditorFontImportOptions::FONT_DISTANCE_FIELD) {
+
+			fdata->halign = fdata->halign / scaler - 1.5;
+			fdata->valign = fdata->valign / scaler + 1.5;
+			fdata->advance/=scaler;
+
+		}
+
 		fdata->advance+=font_spacing;
 		fdata->advance+=font_spacing;
 
 
-		for (int i=0;i<slot->bitmap.width;i++) {
-			for (int j=0;j<slot->bitmap.rows;j++) {
 
 
-				fdata->bitmap[j*slot->bitmap.width+i]=slot->bitmap.buffer[j*slot->bitmap.width+i];
+		if (charcode<127) {
+			int top = fdata->valign;
+			int hmax = h/scaler;
+
+			if (top>max_up) {
+
+				max_up=top;
+			}
+
+
+			if ( (top - hmax)<max_down ) {
+
+				max_down=top - hmax;
+			}
+		}
+
+		if (font_mode==_EditorFontImportOptions::FONT_DISTANCE_FIELD) {
+
+
+			//	oversize the holding buffer so I can smooth it!
+			int sw = w + scaler * 4;
+			int sh = h + scaler * 4;
+
+			unsigned char *smooth_buf = new unsigned char[sw*sh];
+
+			for( int i = 0; i < sw*sh; ++i ) {
+				smooth_buf[i] = 0;
+			}
+
+			// copy the glyph into the buffer to be smoothed
+			unsigned char *buf = slot->bitmap.buffer;
+			for( int j = 0; j < h; ++j ) {
+				for( int i = 0; i < w; ++i ) {
+					smooth_buf[scaler*2+i+(j+scaler*2)*sw] = 255 * ((buf[j*p+(i>>3)] >> (7 - (i & 7))) & 1);
+				}
+			}
+
+			// do the SDF
+			int sdfw = fdata->width;
+			int sdfh = fdata->height;
+
+			fdata->bitmap.resize( sdfw*sdfh );
+
+			for( int j = 0; j < sdfh; ++j )	{
+				for( int i = 0; i < sdfw; ++i )	{
+					int pd_idx = j*sdfw+i;
+
+					//fdata->bitmap[j*slot->bitmap.width+i]=slot->bitmap.buffer[j*slot->bitmap.width+i];
+
+					fdata->bitmap[pd_idx] =
+							//get_SDF
+							get_SDF_radial
+							( smooth_buf, sw, sh,
+							  i*scaler + (scaler >>1), j*scaler + (scaler >>1),
+							  2*scaler );
+
+				}
+			}
+
+			delete [] smooth_buf;
+
+		} else {
+			fdata->bitmap.resize( slot->bitmap.width*slot->bitmap.rows );
+			for (int i=0;i<slot->bitmap.width;i++) {
+				for (int j=0;j<slot->bitmap.rows;j++) {
+
+					fdata->bitmap[j*slot->bitmap.width+i]=slot->bitmap.buffer[j*slot->bitmap.width+i];
+				}
 			}
 			}
 		}
 		}
 
 
@@ -907,6 +1153,7 @@ Ref<Font> EditorFontImportPlugin::generate_font(const Ref<ResourceImportMetadata
 	if (!FT_Load_Char( face, ' ', FT_LOAD_RENDER ) && !FT_Render_Glyph( face->glyph, ft_render_mode_normal )) {
 	if (!FT_Load_Char( face, ' ', FT_LOAD_RENDER ) && !FT_Render_Glyph( face->glyph, ft_render_mode_normal )) {
 
 
 		spd->advance = slot->advance.x>>6; //round to nearest or store as float
 		spd->advance = slot->advance.x>>6; //round to nearest or store as float
+		spd->advance/=scaler;
 		spd->advance+=font_spacing;
 		spd->advance+=font_spacing;
 	} else {
 	} else {
 
 
@@ -955,7 +1202,7 @@ Ref<Font> EditorFontImportPlugin::generate_font(const Ref<ResourceImportMetadata
 
 
 				if (kern==0)
 				if (kern==0)
 					continue;
 					continue;
-				kerning_map[kpk]=kern;
+				kerning_map[kpk]=kern/scaler;
 			}
 			}
 		}
 		}
 	}
 	}
@@ -1079,7 +1326,7 @@ Ref<Font> EditorFontImportPlugin::generate_font(const Ref<ResourceImportMetadata
 		pixels.resize(s.x*s.y*4);
 		pixels.resize(s.x*s.y*4);
 
 
 		DVector<uint8_t>::Write w = pixels.write();
 		DVector<uint8_t>::Write w = pixels.write();
-		print_line("val: "+itos(font_data_list[i]->valign));
+		//print_line("val: "+itos(font_data_list[i]->valign));
 		for(int y=0;y<s.height;y++) {
 		for(int y=0;y<s.height;y++) {
 
 
 			int yc=CLAMP(y-o.y+font_data_list[i]->valign,0,height-1);
 			int yc=CLAMP(y-o.y+font_data_list[i]->valign,0,height-1);
@@ -1251,7 +1498,7 @@ Ref<Font> EditorFontImportPlugin::generate_font(const Ref<ResourceImportMetadata
 		atlas.convert(Image::FORMAT_GRAYSCALE_ALPHA);
 		atlas.convert(Image::FORMAT_GRAYSCALE_ALPHA);
 	}
 	}
 
 
-	if (0) {
+	if (1) {
 		//debug the texture
 		//debug the texture
 		Ref<ImageTexture> atlast = memnew( ImageTexture );
 		Ref<ImageTexture> atlast = memnew( ImageTexture );
 		atlast->create_from_image(atlas);
 		atlast->create_from_image(atlas);