Commits

Anonymous committed 044ca37

add basic support for utf-8 stirng print.

Comments (0)

Files changed (5)

src/modules/font/FontData.cpp

 	{
 		data = new GlyphData *[MAX_CHARS];
 		for (unsigned int i = 0; i < MAX_CHARS; i++) {
-			data[i] = raster->getGlyphData(i);
+			data[i] = 0;
 		}
 	}
 
 	FontData::~FontData()
 	{
 		for (unsigned int i = 0; i < MAX_CHARS; i++) {
-			data[i]->release();
+			if (data[i]) {
+				data[i]->release();
+			}
 		}
 		delete[] data;
 	}
 
 	GlyphData * FontData::getGlyphData(unsigned short glyph) const
 	{
+		if (!data[glyph]) {
+			data[glyph] = raster->getGlyphData(glyph);
+		}
 		return data[glyph];
 	}
 

src/modules/font/FontData.h

 		virtual ~FontData();
 		
 		// Implements Data.
-		void * getData() const;
 		int getSize() const;
 		
 		GlyphData * getGlyphData(unsigned short glyph) const;
 		int getHeight() const;
 		
-		static const unsigned int MAX_CHARS = 256;
+		static const unsigned int MAX_CHARS = 65536;
 		
 	private:
+
+		void * getData() const;
+
 		GlyphData ** data;
 		Rasterizer * raster;
 	};

src/modules/font/ImageRasterizer.h

 		virtual GlyphData * getGlyphData(unsigned short glyph) const;
 		virtual int getNumGlyphs() const;
 		
-		static const unsigned int MAX_CHARS = 256;
+		static const unsigned int MAX_CHARS = 65536;
 		
 	}; // ImageRasterizer
 

src/modules/graphics/opengl/Font.cpp

 	{
 		glyphs = new Glyph*[MAX_CHARS];
 		type = FONT_UNKNOWN;
-		love::font::GlyphData * gd;
+		this->data = data;
 
 		for(unsigned int i = 0; i < MAX_CHARS; i++)
 		{
-			gd = data->getGlyphData(i);
-			glyphs[i] = new Glyph(gd);
-			glyphs[i]->load();
-			widths[i] = gd->getWidth();
-			spacing[i] = gd->getAdvance();
-			bearingX[i] = gd->getBearingX();
-			bearingY[i] = gd->getBearingY();
-			if (type == FONT_UNKNOWN) type = (gd->getFormat() == love::font::GlyphData::FORMAT_LUMINANCE_ALPHA ? FONT_TRUETYPE : FONT_IMAGE);
+			glyphs[i] = 0;
+			widths[i] = -1;
+			spacing[i] = -1;
+			bearingX[i] = -1;
+			bearingY[i] = -1;
 		}
 	}
 
 	{
 		for(unsigned int i = 0; i < MAX_CHARS; i++)
 		{
-			glyphs[i]->release();
+			if (glyphs[i]) {
+				glyphs[i]->release();
+			}
 		}
 		delete[] glyphs;
 	}
 
+	Glyph * Font::getGlyph(unsigned int glyph)
+	{
+		if (!glyphs[glyph]) {
+			love::font::GlyphData * gd = data->getGlyphData(glyph);
+			glyphs[glyph] = new Glyph(gd);
+			glyphs[glyph]->load();
+			widths[glyph] = gd->getWidth();
+			spacing[glyph] = gd->getAdvance();
+			bearingX[glyph] = gd->getBearingX();
+			bearingY[glyph] = gd->getBearingY();
+			if (type == FONT_UNKNOWN) type = (gd->getFormat() == love::font::GlyphData::FORMAT_LUMINANCE_ALPHA ? FONT_TRUETYPE : FONT_IMAGE);
+		}
+		return glyphs[glyph];
+	}
+
+	int Font::getWidths(unsigned int glyph)
+	{
+		if (widths[glyph] == -1) {
+			getGlyph(glyph);
+		}
+		return widths[glyph];
+	}
+
+	int Font::getSpacing(unsigned int glyph)
+	{
+		if (spacing[glyph] == -1) {
+			getGlyph(glyph);
+		}
+		return spacing[glyph];
+	}
+
+	int Font::getBearingX(unsigned int glyph)
+	{
+		if (bearingX[glyph] == -1) {
+			getGlyph(glyph);
+		}
+		return bearingX[glyph];
+	}
+
+	int Font::getBearingY(unsigned int glyph)
+	{
+		if (bearingY[glyph] == -1) {
+			getGlyph(glyph);
+		}
+		return bearingY[glyph];
+	}
+
 	float Font::getHeight() const
 	{
 		return height / lineHeight;
 	}
 
-	void Font::print(std::string text, float x, float y) const
+	void Font::print(std::string text, float x, float y)
 	{
 		print(text, x, y, 0.0f, 1.0f, 1.0f);
 	}
 
-	void Font::print(std::string text, float x, float y, float angle, float sx, float sy) const
+	void Font::print(std::string text, float x, float y, float angle, float sx, float sy)
 	{
 		float dx = 0.0f; // spacing counter for newline handling
 		glPushMatrix();
 		glTranslatef(ceil(x), ceil(y), 0.0f);
 		glRotatef(LOVE_TODEG(angle), 0, 0, 1.0f);
 		glScalef(sx, sy, 1.0f);
+
+		unsigned short ucs2;
+		int state = 0;
+		int left = 0;
+
 		for (unsigned int i = 0; i < text.size(); i++) {
+
 			unsigned char g = (unsigned char)text[i];
-			if (g == '\n') { // wrap newline, but do not print it
-				glTranslatef(-dx, round(getHeight()), 0);
+
+			unsigned char head = g;
+			unsigned int bcount = 0;
+			while (head & 0x80) {
+				head <<= 1;
+				bcount++;
+			};
+			switch (state) {
+			case 1:
+				if (bcount == 1) {
+					ucs2 = (ucs2 << 6) | (g & 0x3F);
+					left--;
+					if (left == 0) {
+						state = 0;
+						break;
+					}
+					continue;
+				} else {
+					state = 0;
+					// fall through state 0
+				}
+			case 0:
+				if (bcount == 1 || bcount > 4) {
+					continue;
+				} else if (bcount == 0) {
+					ucs2 = g;
+					break;
+				} else {
+					left = bcount-1;
+					state = 1;
+					unsigned char mask = (1 << (7 - left)) - 1;
+					ucs2 = g & mask;
+					continue;
+				}
+			}
+
+			if (ucs2 == '\n') { // wrap newline, but do not print it
+				glTranslatef(-dx, floor(getHeight()+0.5), 0);
 				dx = 0.0f;
 				continue;
 			}
-			if (!glyphs[g]) g = 32; // space
+			if (!getGlyph(ucs2)) ucs2 = 32; // space
 			glPushMatrix();
-			if (type == FONT_TRUETYPE) glTranslatef(0, round(getHeight()), 0);
-			glyphs[g]->draw(0, 0, 0, 1, 1, 0, 0);
+			if (type == FONT_TRUETYPE) glTranslatef(0, floor(getHeight()+0.5), 0);
+			getGlyph(ucs2)->draw(0, 0, 0, 1, 1, 0, 0);
 			glPopMatrix();
-			glTranslatef(spacing[g], 0, 0);
-			dx += spacing[g];
+			glTranslatef(getSpacing(ucs2), 0, 0);
+			dx += getSpacing(ucs2);
 		}
 		glPopMatrix();
 	}
 
-	void Font::print(char character, float x, float y) const
+	void Font::print(char character, float x, float y)
 	{
-		if (!glyphs[character]) character = ' ';
+		if (!getGlyph(character)) character = ' ';
 		glPushMatrix();
-		glTranslatef(x, round(y+getHeight()), 0.0f);
+		glTranslatef(x, floor(y+getHeight()+0.5), 0.0f);
 		glCallList(list+character);
 		glPopMatrix();
 	}
 
-	int Font::getWidth(const std::string & line) const
+	int Font::getWidth(const std::string & line)
 	{
 		if(line.size() == 0) return 0;
 		int temp = 0;
 
 		for(unsigned int i = 0; i < line.size(); i++)
 		{
-			temp += (spacing[(int)line[i]] * mSpacing);
+			temp += (getSpacing((int)line[i]) * mSpacing);
 		}
 
 		return temp;
 	}
 
-	int Font::getWidth(const char * line) const
+	int Font::getWidth(const char * line)
 	{
 		return this->getWidth(std::string(line));
 	}
 
-	int Font::getWidth(const char character) const
+	int Font::getWidth(const char character)
 	{
-		return spacing[(int)character];
+		return getSpacing((int)character);
 	}
 
-	int Font::getWrap(const std::string & line, float wrap, int * lines) const
+	int Font::getWrap(const std::string & line, float wrap, int * lines)
 	{
 		if(line.size() == 0) return 0;
 		int maxw = 0;
 				temp = getWidth(text);
 				linen++;
 			}
-			temp += (spacing[(int)line[i]] * mSpacing);
+			temp += (getSpacing((int)line[i]) * mSpacing);
 			text += line[i];
 		}
 
 		return maxw;
 	}
 
-	int Font::getWrap(const char * line, float wrap, int * lines) const
+	int Font::getWrap(const char * line, float wrap, int * lines)
 	{
 		return getWrap(std::string(line), wrap, lines);
 	}
 		// reload all glyphs
 		for(unsigned int i = 0; i < MAX_CHARS; i++)
 		{
-			glyphs[i]->load();
-			glNewList(list + i, GL_COMPILE);
-			glyphs[i]->draw(0, 0, 0, 1, 1, 0, 0);
-			glEndList();
+			if (glyphs[i]) {
+				glyphs[i]->load();
+				glNewList(list + i, GL_COMPILE);
+				glyphs[i]->draw(0, 0, 0, 1, 1, 0, 0);
+				glEndList();
+			}
 		}
 		return true;
 	}

src/modules/graphics/opengl/Font.h

 		Glyph ** glyphs;
 		GLuint list; // the list of glyphs, for quicker drawing
 		FontType type;
+		love::font::FontData * data;
 
 	public:
-		static const unsigned int MAX_CHARS = 256;
+		static const unsigned int MAX_CHARS = 65536;
+	private:
 		// The widths of each character.
 		int widths[MAX_CHARS];
 		// The spacing of each character.
 		// The Y-bearing of each character.
 		int bearingY[MAX_CHARS];
 
+		Glyph * getGlyph(unsigned int glyph);
+
+		int getWidths(unsigned int glyph);
+
+		int getSpacing(unsigned int glyph);
+
+		int getBearingX(unsigned int glyph);
+
+		int getBearingY(unsigned int glyph);
+
+		FontType getType();
+
+	public:
 		/**
 		* Default constructor.
 		*
 		* @param x The x-coordinate.
 		* @param y The y-coordinate.
 		**/
-		void print(std::string text, float x, float y) const;
+		void print(std::string text, float x, float y);
 
 		/**
 		* Prints the text at the designated position with rotation and scaling.
 		* @param y The y-coordinate.
 		* @param angle The amount of rotation.
 		**/
-		void print(std::string text, float x, float y, float angle, float sx, float sy) const;
+		void print(std::string text, float x, float y, float angle, float sx, float sy);
 
 		/**
 		* Prints the character at the designated position.
 		* @param x The x-coordinate.
 		* @param y The y-coordinate.
 		**/
-		void print(char character, float x, float y) const;
+		void print(char character, float x, float y);
 
 		/**
 		* Returns the height of the font.
 		*
 		* @param line A line of text.
 		**/
-		int getWidth(const std::string & line) const;
-		int getWidth(const char * line) const;
+		int getWidth(const std::string & line);
+		int getWidth(const char * line);
 
 		/**
 		* Returns the width of the passed character.
 		*
 		* @param character A character.
 		**/
-		int getWidth(const char character) const;
+		int getWidth(const char character);
 
 		/**
 		 * Returns the maximal width of a wrapped string
 		 * @param wrap The number of pixels to wrap at
 		 * @param lines Optional output of the number of lines needed
 		 **/
-		int getWrap(const std::string & line, float wrap, int *lines = 0) const;
-		int getWrap(const char * line, float wrap, int *lines = 0) const;
+		int getWrap(const std::string & line, float wrap, int *lines = 0);
+		int getWrap(const char * line, float wrap, int *lines = 0);
 
 		/**
 		* Sets the line height (which should be a number to multiply the font size by,