Commit 9f030717abc4831b33e00cd27a59dc07221de65e

henry 2001-08-19T22:43:50

Major change to enable multiple textures. If all the glyphs for a given face and size don't fit within the max texture size we now create as many textures as required and switch automatically when rendering.

diff --git a/include/FTGLTextureFont.h b/include/FTGLTextureFont.h
index 2cf0f1b..4057886 100755
--- a/include/FTGLTextureFont.h
+++ b/include/FTGLTextureFont.h
@@ -11,11 +11,12 @@ class	FTGLTextureFont : public FTFont
 	public:
 		// methods
 		FTGLTextureFont();
-		~FTGLTextureFont();
+		virtual ~FTGLTextureFont();
 		
-		int TextureSize() const { return textureSize;}
+		virtual int TextureWidth() const { return textureWidth;}
+		virtual int TextureHeight() const { return textureHeight;}
 		
-		void render( const char* string);
+		virtual void render( const char* string);
 
 		
 	private:
@@ -23,9 +24,11 @@ class	FTGLTextureFont : public FTFont
 		FTTextureGlyph* tempGlyph;
 		
 		long maxTextSize;
-		int textureSize;
+		int textureWidth;
+		int textureHeight;
 		
-		unsigned long glTextureID;
+		unsigned long glTextureID[16];
+		int numTextures;
 		unsigned char* textMem;
 		
 		int glyphHeight;
@@ -38,7 +41,9 @@ class	FTGLTextureFont : public FTFont
 		
 		// methods
 		bool MakeGlyphList();
-		bool CreateTexture();
+		void CreateTexture( int id, int width, int height, unsigned char* data);
+		void GetSize();
+		int FillGlyphs( int glyphStart, int textID, int textureWidth, int textureHeight, unsigned char* textMem);
 		
 		
 };
diff --git a/include/FTTextureGlyph.h b/include/FTTextureGlyph.h
index 1efc237..349737c 100755
--- a/include/FTTextureGlyph.h
+++ b/include/FTTextureGlyph.h
@@ -12,10 +12,11 @@ class	FTTextureGlyph : public FTGlyph
 {
 	public:
 		// methods
-		FTTextureGlyph( FT_Glyph glyph, int gi, unsigned char* data, int stride, float u, float v);
+		FTTextureGlyph( FT_Glyph glyph, int gi, int id, unsigned char* data, int stride, int height, float u, float v);
 		virtual ~FTTextureGlyph();
 		virtual float Render( const FT_Vector& v);
 		
+		static int activeTextureID;
 	private:
 		// attributes
 		// What about the other point class in vectoriser?
@@ -31,6 +32,7 @@ class	FTTextureGlyph : public FTGlyph
 		int numGreys;
 		
 		FTPoint uv[2];
+		int glTextureID;
 };
 
 
diff --git a/src/FTGLTextureFont.cpp b/src/FTGLTextureFont.cpp
index 1bb994e..9cf1448 100755
--- a/src/FTGLTextureFont.cpp
+++ b/src/FTGLTextureFont.cpp
@@ -24,122 +24,167 @@ inline UInt32 NextPowerOf2( UInt32 in)
 
 
 FTGLTextureFont::FTGLTextureFont()
-:	glTextureID(0),
+:	numTextures(1),
 	textMem(0),
-	padding(15),
+	padding(1),
 	tempGlyph(0),
 	maxTextSize(0),
-	textureSize(0),
+	textureWidth(0),
+	textureHeight(0),
 	glyphHeight(0),
-	glyphWidth(0),
-	horizGlyphs(0),
-	vertGlyphs(0)
-
+	glyphWidth(0)
 {}
 
 
 FTGLTextureFont::~FTGLTextureFont()
 {
-	glDeleteTextures( 1, &glTextureID);
-	delete [] textMem;
+	glDeleteTextures( numTextures, glTextureID);
 }
 
 
 bool FTGLTextureFont::MakeGlyphList()
 {
-	FT_Face* ftFace = face.Face();
+	if( !maxTextSize)
+		glGetIntegerv( GL_MAX_TEXTURE_SIZE, &maxTextSize);
+	
+	glyphHeight = ( charSize.Height()) + padding;
+	glyphWidth = ( charSize.Width()) + padding;
+	
+	GetSize();
+	int totalMem;
 	
-	CreateTexture();
+	if( textureHeight > maxTextSize)
+	{
+		numTextures = static_cast<int>( textureHeight / maxTextSize) + 1;
+		if( numTextures > 15)
+			numTextures = 15;
+		
+		int heightRemain = NextPowerOf2( textureHeight % maxTextSize);
+		totalMem = ((maxTextSize * ( numTextures - 1)) + heightRemain) * textureWidth;
 
+		glGenTextures( numTextures, &glTextureID[0]);
+
+		textMem = new unsigned char[totalMem]; // GL_ALPHA texture;
+		std::memset( textMem, 0, totalMem);
+			
+		int glyphNum = 0;
+		unsigned char* currTextPtr = textMem;
+		
+		for( int x = 0; x < numTextures - 1; ++x)
+		{
+			glyphNum = FillGlyphs( glyphNum, glTextureID[x], textureWidth, maxTextSize, currTextPtr);
+			
+			CreateTexture( x, textureWidth, maxTextSize, currTextPtr);
+			
+			currTextPtr += ( textureWidth * maxTextSize);
+			++glyphNum;
+		}
+		
+		glyphNum = FillGlyphs( glyphNum, glTextureID[numTextures - 1], textureWidth, heightRemain, currTextPtr);
+		CreateTexture( numTextures - 1, textureWidth, heightRemain, currTextPtr);
+	}
+	else
+	{
+		textureHeight = NextPowerOf2( textureHeight);
+		totalMem = textureWidth * textureHeight;
+		
+		glGenTextures( numTextures, &glTextureID[0]);
+
+		textMem = new unsigned char[totalMem]; // GL_ALPHA texture;
+		std::memset( textMem, 0, totalMem);
+
+		FillGlyphs( 0, glTextureID[0], textureWidth, textureHeight, textMem);
+		CreateTexture( 0, textureWidth, textureHeight, textMem);
+	}
+
+	delete [] textMem;
+	return !err;
+}
+
+
+int FTGLTextureFont::FillGlyphs( int glyphStart, int id, int width, int height, unsigned char* textdata)
+{
+	FT_Face* ftFace = face.Face();
+	
 	int currentTextX = padding;
-	int currentTextY = padding + padding;
+	int currentTextY = padding;// + padding;
 	
-	float currTextU = (float)padding / (float)textureSize;
-	float currTextV = (float)padding / (float)textureSize;
+	float currTextU = (float)padding / (float)width;
+	float currTextV = (float)padding / (float)height;
 	
 //	numGlyphs = 256; // FIXME hack
+	int n;
 	
-	for( int n = 0; n <= numGlyphs; ++n)
+	for( n = glyphStart; n <= numGlyphs; ++n)
 	{
-		err = FT_Load_Glyph( *ftFace, n, FT_LOAD_DEFAULT);
+		err = FT_Load_Glyph( *ftFace, n, FT_LOAD_NO_HINTING); // FT_LOAD_DEFAULT
 		FT_Glyph ftGlyph;
 		
 		err = FT_Get_Glyph( (*ftFace)->glyph, &ftGlyph);
 	
-		unsigned char* data = textMem + ( ( currentTextY * textureSize) + currentTextX);
+		unsigned char* data = textdata + (( currentTextY * width) + currentTextX);
 		
-		currTextU = (float)currentTextX / (float)textureSize;
+		currTextU = (float)currentTextX / (float)width;
 		
-		tempGlyph = new FTTextureGlyph( ftGlyph, n, data, textureSize, currTextU, currTextV);
+		tempGlyph = new FTTextureGlyph( ftGlyph, n, id, data, width, height, currTextU, currTextV);
 		glyphList->Add( tempGlyph);
 		
 		currentTextX += glyphWidth;
-		if( currentTextX > ( textureSize - glyphWidth))
+		if( currentTextX > ( width - glyphWidth))
 		{
 			currentTextY += glyphHeight;
+			if( currentTextY > ( height - glyphHeight))
+				return n;
+				
 			currentTextX = padding;
-			currTextV = (float)currentTextY / (float)textureSize;
+			currTextV = (float)currentTextY / (float)height;
 		}
 	}
 
-	
-	glPixelStorei(GL_UNPACK_ALIGNMENT, 1); //What does this do exactly?
-	glBindTexture( GL_TEXTURE_2D, glTextureID);
-	glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
-	glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
-	glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-	glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+	return n;
+}
 
-	glTexImage2D( GL_TEXTURE_2D, 0, GL_ALPHA, textureSize, textureSize, 0, GL_ALPHA, GL_UNSIGNED_BYTE, textMem);
 
-	return !err;
+void FTGLTextureFont::GetSize()
+{
+	//work out the max width. Most likely maxTextSize!
+	textureWidth = NextPowerOf2( numGlyphs * glyphWidth);
+	if( textureWidth > maxTextSize)
+	{
+		textureWidth = maxTextSize;
+	}
+	
+	int h = static_cast<int>( textureWidth / glyphWidth);
+	textureHeight = (( numGlyphs / h) + 1) * glyphHeight;
 }
 
 
-bool FTGLTextureFont::CreateTexture()
+void FTGLTextureFont::CreateTexture( int id, int width, int height, unsigned char* data)
 {
-	glGetIntegerv( GL_MAX_TEXTURE_SIZE, &maxTextSize);
-	glGenTextures( 1, &glTextureID);
+	glPixelStorei( GL_UNPACK_ALIGNMENT, 1); //What does this do exactly?
+	glBindTexture( GL_TEXTURE_2D, glTextureID[id]);
+	glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+	glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+	glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+	glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
 
-//	There is a fixed relationship between ppem, point size, and the
-//	resulting pixel size.  The real dimension of the glyphs are not
-//	covered by this.  The field `bbox' in FT_Face gives a maximal bounding
-//	box large enough to hold all bboxes of single glyphs.
-	
-	// calc the area required for this font
-	glyphHeight = ( charSize.Height()) + padding;
-	glyphWidth = ( charSize.Width()) + padding;
-	
-	//FIXME	
-//	textureSize = 1024;
-	int t;
-	for( t = 64; t <= maxTextSize; t *=2)
-	{		
-		int h = static_cast<int>( t / glyphWidth);
-		if( t > ( ( numGlyphs / h) * glyphHeight))
-			break;
-	}
-	
-	textureSize = t;
-	
-	horizGlyphs = static_cast<int>( textureSize / glyphWidth);
-	vertGlyphs = static_cast<int>(( numGlyphs / horizGlyphs) + 1);
-	
-	// build the texture.
-	textMem = new unsigned char[ textureSize * textureSize]; // GL_ALPHA texture;
-	
-	//FIXME
-	for( int i = 0; i < ( textureSize * textureSize); ++i)
-		textMem[i] = 0;
+	glTexImage2D( GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, data);
 }
 
 
 void FTGLTextureFont::render( const char* string)
 {	
-	glBindTexture( GL_TEXTURE_2D, glTextureID);
+	glPushAttrib( GL_ENABLE_BIT | GL_HINT_BIT | GL_LINE_BIT | GL_PIXEL_MODE_BIT);
+	
+	glEnable(GL_BLEND);
+ 	glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // GL_ONE
+ 	
+	glBindTexture( GL_TEXTURE_2D, FTTextureGlyph::activeTextureID);
+
+ 	// QUADS are faster!? Less function call overhead?
+ 	glBegin( GL_QUADS);
+ 		FTFont::render( string);
+ 	glEnd();
 	
-	// QUADS are faster!? Less function call overhead?
-	glBegin( GL_QUADS);
-		FTFont::render( string);
-	glEnd();
+	glPopAttrib();
 }
diff --git a/src/FTTextureGlyph.cpp b/src/FTTextureGlyph.cpp
index 84b4d65..9ad2d76 100755
--- a/src/FTTextureGlyph.cpp
+++ b/src/FTTextureGlyph.cpp
@@ -4,11 +4,14 @@
 #include	"FTGL.h"
 
 
-FTTextureGlyph::FTTextureGlyph( FT_Glyph glyph, int gi, unsigned char* data, int stride, float u, float v)
+int FTTextureGlyph::activeTextureID = 0;
+
+FTTextureGlyph::FTTextureGlyph( FT_Glyph glyph, int gi, int id, unsigned char* data, int stride, int height, float u, float v)
 :	FTGlyph(gi),
 	destWidth(0),
 	destHeight(0),
-	numGreys(0)
+	numGreys(0),
+	glTextureID(id)
 {
 	if( !glyph->format == ft_glyph_format_bitmap)
 	{ return;}
@@ -18,7 +21,7 @@ FTTextureGlyph::FTTextureGlyph( FT_Glyph glyph, int gi, unsigned char* data, int
 	if( err)
 	{return;}
 
-	FT_BitmapGlyph  bitmap = (FT_BitmapGlyph)glyph;
+	FT_BitmapGlyph  bitmap = ( FT_BitmapGlyph)glyph;
 	FT_Bitmap*      source = &bitmap->bitmap;
 
 	//check the pixel mode
@@ -56,11 +59,11 @@ FTTextureGlyph::FTTextureGlyph( FT_Glyph glyph, int gi, unsigned char* data, int
 	uv[0].x = u;
 	uv[0].y = v;
 	uv[1].x = uv[0].x + ( (float)destWidth / (float)stride);
-	uv[1].y = uv[0].y + ( (float)destHeight / (float)stride);
+	uv[1].y = uv[0].y + ( (float)destHeight / (float)height);
 
 	// discard glyph image (bitmap or not)
 	// Is this the right place to do this?
-	FT_Done_Glyph( glyph );
+	FT_Done_Glyph( glyph);
 }
 
 
@@ -74,6 +77,15 @@ float FTTextureGlyph::Render( const FT_Vector& pen)
 {
 //	int adv = advance/* + pos.x */+ ( v.x >> 16); // FIXME ??? pos.x = bearing X
 
+	// This could be really ugly!!
+	if( activeTextureID != glTextureID)
+	{
+		glEnd();
+		glBindTexture( GL_TEXTURE_2D, glTextureID);
+		activeTextureID = glTextureID;
+		glBegin( GL_QUADS);
+	}
+	
 	glTexCoord2f( uv[0].x, uv[0].y); glVertex2f( pen.x,				pen.y + pos.y);
 	glTexCoord2f( uv[1].x, uv[0].y); glVertex2f( pen.x + destWidth,	pen.y + pos.y);
 	glTexCoord2f( uv[1].x, uv[1].y); glVertex2f( pen.x + destWidth,	pen.y + pos.y - destHeight);