Source

love / src / modules / graphics / opengl / Font.cpp

Full commit
Bill Meltsner f852ad8 
Bill Meltsner 150b94a 
ba...@bartbes.at… 69ff4a9 
Bill Meltsner f852ad8 


ba...@bartbes.at… 69ff4a9 
Bill Meltsner f852ad8 


ba...@bartbes.at… 69ff4a9 
Bill Meltsner f852ad8 






rude d362ae6 
rude 4afba41 
rude d362ae6 
Bill Meltsner 0bba2aa 
Bill Meltsner 1819ef6 
rude d362ae6 
Bill Meltsner 4ca613c 

Bill Meltsner f852ad8 


Bill Meltsner 1819ef6 

rude d362ae6 





ba...@bartbes.at… 69ff4a9 
Bill Meltsner 61c010f 
Bill Meltsner 1819ef6 
rude d362ae6 
Bill Meltsner 38c39d7 
Bill Meltsner 1819ef6 
Bill Meltsner 63ebf3c 

Bill Meltsner 1819ef6 
rude d362ae6 



Bill Meltsner 38c39d7 
Bill Meltsner 1819ef6 




















































































rude d362ae6 



rude 348b7de 
Bill Meltsner f852ad8 
ba...@bartbes.at… 69ff4a9 
Bill Meltsner 1819ef6 
Bill Meltsner f852ad8 
Bill Meltsner 1819ef6 
Bill Meltsner f852ad8 
ba...@bartbes.at… 69ff4a9 
Bill Meltsner 22c3c8c 
Bill Meltsner f852ad8 

Bill Meltsner 4ca613c 



Bill Meltsner 24a04be 
vrld a17b9a7 
Bill Meltsner 24a04be 


Bill Meltsner 1819ef6 

Bill Meltsner 37c7273 
vrld a17b9a7 

Bill Meltsner 1819ef6 
Bill Meltsner 37c7273 
Bill Meltsner 1819ef6 

Bill Meltsner f852ad8 
Bill Meltsner 1819ef6 
Bill Meltsner f852ad8 
ba...@bartbes.at… 69ff4a9 
Bill Meltsner 1819ef6 
Bill Meltsner f852ad8 
Bill Meltsner 1819ef6 

Bill Meltsner 37c7273 
rude 2968d34 
Bill Meltsner 1819ef6 

rude d362ae6 
ba...@bartbes.at… 69ff4a9 
Bill Meltsner 1819ef6 
rude d362ae6 

Bill Meltsner 22c3c8c 
Bill Meltsner 1819ef6 

rude d362ae6 
Bill Meltsner 4ca613c 





Bill Meltsner 1819ef6 
rude d362ae6 
ba...@bartbes.at… 69ff4a9 
rude d362ae6 


Bill Meltsner 1819ef6 
rude d362ae6 


ba...@bartbes.at… 69ff4a9 
Bill Meltsner 1819ef6 
rude d362ae6 
Bill Meltsner 1819ef6 


rude d362ae6 

Bill Meltsner 1819ef6 
ba...@bartbes.at… 69ff4a9 





Bill Meltsner 1819ef6 
ba...@bartbes.at… 69ff4a9 
Bill Meltsner 4ca613c 



ba...@bartbes.at… 69ff4a9 









Bill Meltsner 4ca613c 


Bill Meltsner 1819ef6 
Bill Meltsner 4ca613c 
ba...@bartbes.at… 69ff4a9 







Bill Meltsner 1819ef6 
ba...@bartbes.at… 69ff4a9 



rude d362ae6 


















Bart van Strien beddd13 
Bill Meltsner 7f3ac70 

Bill Meltsner 1819ef6 
Bart van Strien 25e582e 
Bill Meltsner 7f3ac70 
Bart van Strien beddd13 
Bill Meltsner 7f3ac70 

Bill Meltsner 1819ef6 














Bill Meltsner 7f3ac70 
rude d362ae6 


/**
* Copyright (c) 2006-2011 LOVE Development Team
*
* This software is provided 'as-is', without any express or implied
* warranty.  In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
*    claim that you wrote the original software. If you use this software
*    in a product, an acknowledgment in the product documentation would be
*    appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
*    misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
**/
#include <common/config.h>
#include "Font.h"
#include <font/GlyphData.h>
#include "Quad.h"

#include <libraries/utf8/utf8.h>

#include <common/math.h>
#include <math.h>

#include <algorithm> // for max

namespace love
{
namespace graphics
{
namespace opengl
{

	Font::Font(love::font::Rasterizer * r, const Image::Filter& filter)
	: rasterizer(r), height(r->getHeight()), lineHeight(1), mSpacing(1), filter(filter)
	{
		r->retain();
		love::font::GlyphData * gd = r->getGlyphData(32);
		type = (gd->getFormat() == love::font::GlyphData::FORMAT_LUMINANCE_ALPHA ? FONT_TRUETYPE : FONT_IMAGE);
		delete gd;
		createTexture();
	}

	Font::~Font()
	{
		rasterizer->release();
		unloadVolatile();
	}
	
	void Font::createTexture()
	{
		texture_x = texture_y = rowHeight = 0;
		GLuint t;
		glGenTextures(1, &t);
		textures.push_back(t);
		glBindTexture(GL_TEXTURE_2D, t);
		
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
						(filter.mag == Image::FILTER_LINEAR) ? GL_LINEAR : GL_NEAREST);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
						(filter.min == Image::FILTER_LINEAR) ? GL_LINEAR : GL_NEAREST);
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
		GLint format = (type == FONT_TRUETYPE ? GL_LUMINANCE_ALPHA : GL_RGBA);
		glTexImage2D(GL_TEXTURE_2D, 
					 0, 
					 GL_RGBA, 
					 (GLsizei)TEXTURE_WIDTH, 
					 (GLsizei)TEXTURE_HEIGHT, 
					 0, 
					 format, 
					 GL_UNSIGNED_BYTE, 
					 NULL);
	}
	
	Font::Glyph * Font::addGlyph(int glyph)
	{
		Glyph * g = new Glyph;
		g->list = glGenLists(1);
		if (g->list == 0) { // opengl failed to generate the list
			delete g;
			return NULL;
		}
		love::font::GlyphData *gd = rasterizer->getGlyphData(glyph);
		g->spacing = gd->getAdvance();
		int w = gd->getWidth();
		int h = gd->getHeight();
		if (texture_x + w > TEXTURE_WIDTH) { // out of space - new row!
			texture_x = 0;
			texture_y += rowHeight;
			rowHeight = 0;
		}
		if (texture_y + h > TEXTURE_HEIGHT) { // totally out of space - new texture!
			createTexture();
		}
		GLuint t = textures.back();
		glBindTexture(GL_TEXTURE_2D, t);
		glTexSubImage2D(GL_TEXTURE_2D, 0, texture_x, texture_y, w, h, (type == FONT_TRUETYPE ? GL_LUMINANCE_ALPHA : GL_RGBA), GL_UNSIGNED_BYTE, gd->getData());
		
		Quad::Viewport v;
		v.x = texture_x;
		v.y = texture_y;
		v.w = w;
		v.h = h;
		Quad * q = new Quad(v, TEXTURE_WIDTH, TEXTURE_HEIGHT);
		const vertex * verts = q->getVertices();
		
		glEnableClientState(GL_VERTEX_ARRAY);
		glEnableClientState(GL_TEXTURE_COORD_ARRAY);
		glVertexPointer(2, GL_FLOAT, sizeof(vertex), (GLvoid *)&verts[0].x);
		glTexCoordPointer(2, GL_FLOAT, sizeof(vertex), (GLvoid *)&verts[0].s);
		
		glNewList(g->list, GL_COMPILE);
		glBindTexture(GL_TEXTURE_2D, t);
		glPushMatrix();
		glTranslatef(static_cast<float>(gd->getBearingX()), static_cast<float>(-gd->getBearingY()), 0.0f);
		glDrawArrays(GL_QUADS, 0, 4);
		glPopMatrix();
		glEndList();
		
		glDisableClientState(GL_TEXTURE_COORD_ARRAY);
		glDisableClientState(GL_VERTEX_ARRAY);
		
		delete q;
		delete gd;
		
		texture_x += w;
		rowHeight = std::max(rowHeight, h);
		
		glyphs[glyph] = g;
		return g;
	}

	float Font::getHeight() const
	{
		return static_cast<float>(height);
	}

	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);
		utf8::iterator<std::string::iterator> i (text.begin(), text.begin(), text.end());
		utf8::iterator<std::string::iterator> end (text.end(), text.begin(), text.end());
		while (i != end) {
			int g = *i++;
			if (g == '\n') { // wrap newline, but do not print it
				glTranslatef(-dx, floor(getHeight() * getLineHeight() + 0.5f), 0);
				dx = 0.0f;
				continue;
			}
			Glyph * glyph = glyphs[g];
			if (!glyph) glyph = addGlyph(g);
			glPushMatrix();
			// 1.25 is magic line height for true type fonts
			if (type == FONT_TRUETYPE) glTranslatef(0, floor(getHeight() / 1.25f + 0.5f), 0);
			glCallList(glyph->list);
			glPopMatrix();
			glTranslatef(static_cast<GLfloat>(glyph->spacing), 0, 0);
			dx += glyph->spacing;
		}
		glPopMatrix();
	}

	void Font::print(char character, float x, float y)
	{
		Glyph * glyph = glyphs[character];
		if (!glyph) glyph = addGlyph(character);
		glPushMatrix();
		glTranslatef(x, floor(y+getHeight() + 0.5f), 0.0f);
		glCallList(glyph->list);
		glPopMatrix();
	}

	int Font::getWidth(const std::string & line)
	{
		if(line.size() == 0) return 0;
		int temp = 0;
		
		Glyph * g;

		utf8::iterator<std::string::const_iterator> i (line.begin(), line.begin(), line.end());
		utf8::iterator<std::string::const_iterator> end (line.end(), line.begin(), line.end());
		while (i != end) {
			int c = *i++;
			g = glyphs[c];
			if (!g) g = addGlyph(c);
			temp += static_cast<int>(g->spacing * mSpacing);
		}

		return temp;
	}

	int Font::getWidth(const char * line)
	{
		return this->getWidth(std::string(line));
	}

	int Font::getWidth(const char character)
	{
		Glyph * g = glyphs[character];
		if (!g) g = addGlyph(character);
		return g->spacing;
	}

	int Font::getWrap(const std::string & line, float wrap, int * lines)
	{
		if(line.size() == 0) return 0;
		int maxw = 0;
		int linen = 1;
		int temp = 0;
		std::string text;
		Glyph * g;

		
		utf8::iterator<std::string::const_iterator> i (line.begin(), line.begin(), line.end());
		utf8::iterator<std::string::const_iterator> end (line.end(), line.begin(), line.end());
		while (i != end) {
			if(temp > wrap && text.find(" ") != std::string::npos)
			{
				unsigned int space = text.find_last_of(' ');
				std::string tmp = text.substr(0, space);
				int w = getWidth(tmp);
				if(w > maxw) maxw = w;
				text = text.substr(space+1);
				temp = getWidth(text);
				linen++;
			}
			int c = *i++;
			g = glyphs[c];
			if (!g) g = addGlyph(c);
			temp += static_cast<int>(g->spacing * mSpacing);
			utf8::append(c, text.end());
		}

		if(temp > maxw) maxw = temp;
		if(lines) *lines = linen;

		return maxw;
	}

	int Font::getWrap(const char * line, float wrap, int * lines)
	{
		return getWrap(std::string(line), wrap, lines);
	}

	void Font::setLineHeight(float height)
	{
		this->lineHeight = height;
	}

	float Font::getLineHeight() const
	{
		return lineHeight;
	}

	void Font::setSpacing(float amount)
	{
		mSpacing = amount;
	}

	float Font::getSpacing() const
	{
		return mSpacing;
	}

	bool Font::loadVolatile()
	{
		createTexture();
		return true;
	}

	void Font::unloadVolatile()
	{
		// nuke everything from orbit
		std::map<int, Glyph *>::iterator it = glyphs.begin();
		Glyph * g;
		while (it != glyphs.end()) {
			g = it->second;
			glDeleteLists(g->list, 1);
			delete g;
			glyphs.erase(it++);
		}
		std::vector<GLuint>::iterator iter = textures.begin();
		while (iter != textures.end()) {
			glDeleteTextures(1, (GLuint*)&*iter);
			iter++;
		}
		textures.clear();
	}

} // opengl
} // graphics
} // love