Changed the font handling in the SDL OpenGL port. Previously, all 256

characters were stored in one texture, and pieces of that were carved
out when a particular character was needed.  That approach left visual
artifacts in GL_LINEAR mode because of the way OpenGL divides up
textures (clamped to [0,1]).

The new approach is to use 256 8x8 textures, and draw them separately.
It actually makes the drawText() and drawChar() methods much shorter.
This may be slightly slower than before, but since large numbers of
characters are only ever drawn when needed (versus at the current
framerate), I don't think the speed difference will be noticed.


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@203 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2003-11-12 15:12:06 +00:00
parent 34addb87c6
commit 505a38057d
2 changed files with 45 additions and 69 deletions

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: FrameBufferGL.cxx,v 1.2 2003-11-09 23:53:20 stephena Exp $
// $Id: FrameBufferGL.cxx,v 1.3 2003-11-12 15:12:06 stephena Exp $
//============================================================================
#include <SDL.h>
@ -38,6 +38,9 @@ FrameBufferGL::~FrameBufferGL()
{
if(myTexture)
SDL_FreeSurface(myTexture);
glDeleteTextures(1, &myTextureID);
glDeleteTextures(256, myFontTextureID);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -243,7 +246,6 @@ void FrameBufferGL::drawMediaSource() // FIXME - maybe less copying can be done?
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, myTexture->w, myTexture->h,
GL_RGBA, GL_UNSIGNED_BYTE, myTexture->pixels);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
glColor3f(0.0, 0.0, 0.0);
glBegin(GL_QUADS);
glTexCoord2f(myTexCoord[0], myTexCoord[1]); glVertex2i(0, 0);
@ -285,26 +287,10 @@ void FrameBufferGL::drawBoundedBox(uInt32 x, uInt32 y, uInt32 w, uInt32 h)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferGL::drawText(uInt32 xorig, uInt32 yorig, const string& message)
void FrameBufferGL::drawText(uInt32 x, uInt32 y, const string& message)
{
glBindTexture(GL_TEXTURE_2D, myFontTextureID);
glEnable(GL_BLEND);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND);
// We place the loop here to avoid multiple calls to glBegin/glEnd
glBegin(GL_QUADS);
for(uInt32 i = 0; i < message.length(); i++)
{
uInt32 x = xorig + i*8;
uInt32 y = yorig;
uInt8 c = message[i];
glTexCoord2f(myFontCoord[c].minX, myFontCoord[c].minY); glVertex2i(x, y );
glTexCoord2f(myFontCoord[c].maxX, myFontCoord[c].minY); glVertex2i(x+8, y );
glTexCoord2f(myFontCoord[c].maxX, myFontCoord[c].maxY); glVertex2i(x+8, y+8);
glTexCoord2f(myFontCoord[c].minX, myFontCoord[c].maxY); glVertex2i(x, y+8);
}
glEnd();
drawChar(x + i*8, y, (uInt32) message[i]);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -313,14 +299,14 @@ void FrameBufferGL::drawChar(uInt32 x, uInt32 y, uInt32 c)
if(c >= 256 )
return;
glBindTexture(GL_TEXTURE_2D, myFontTextureID);
glBindTexture(GL_TEXTURE_2D, myFontTextureID[c]);
glEnable(GL_BLEND);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_BLEND);
glBegin(GL_QUADS);
glTexCoord2f(myFontCoord[c].minX, myFontCoord[c].minY); glVertex2i(x, y );
glTexCoord2f(myFontCoord[c].maxX, myFontCoord[c].minY); glVertex2i(x+8, y );
glTexCoord2f(myFontCoord[c].maxX, myFontCoord[c].maxY); glVertex2i(x+8, y+8);
glTexCoord2f(myFontCoord[c].minX, myFontCoord[c].maxY); glVertex2i(x, y+8);
glTexCoord2f(0, 0); glVertex2i(x, y );
glTexCoord2f(1, 0); glVertex2i(x+8, y );
glTexCoord2f(1, 1); glVertex2i(x+8, y+8);
glTexCoord2f(0, 1); glVertex2i(x, y+8);
glEnd();
}
@ -364,15 +350,16 @@ bool FrameBufferGL::createTextures()
glGenTextures(1, &myTextureID);
glBindTexture(GL_TEXTURE_2D, myTextureID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, param);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, param);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE,
myTexture->pixels);
// Now create the font texture. There are 256 fonts of 8x8 pixels.
// These will be stored in a texture of size 256x64, which is 32 characters
// per line, and 8 lines.
SDL_Surface* fontTexture = SDL_CreateRGBSurface(SDL_SWSURFACE, 256, 64, 32,
// Now create the font textures. There are 256 fonts of 8x8 pixels.
// These will be stored in 256 textures of size 8x8.
SDL_Surface* fontTexture = SDL_CreateRGBSurface(SDL_SWSURFACE, 8, 8, 32,
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000);
#else
@ -382,52 +369,41 @@ bool FrameBufferGL::createTextures()
if(fontTexture == NULL)
return false;
// First clear the texture
SDL_Rect tmp;
tmp.x = 0; tmp.y = 0; tmp.w = 256; tmp.h = 64;
SDL_FillRect(fontTexture, &tmp,
SDL_MapRGBA(fontTexture->format, 0xff, 0xff, 0xff, 0x0));
// Create a texture for each character
glGenTextures(256, myFontTextureID);
// Now fill the texture with font data
for(uInt32 lines = 0; lines < 8; lines++)
for(uInt32 c = 0; c < 256; c++)
{
for(uInt32 x = lines*32; x < (lines+1)*32; x++)
// First clear the texture
SDL_Rect tmp;
tmp.x = 0; tmp.y = 0; tmp.w = 8; tmp.h = 8;
SDL_FillRect(fontTexture, &tmp,
SDL_MapRGBA(fontTexture->format, 0xff, 0xff, 0xff, 0x0));
// Now fill the texture with font data
for(uInt32 y = 0; y < 8; y++)
{
for(uInt32 y = 0; y < 8; y++)
for(uInt32 x = 0; x < 8; x++)
{
for(uInt32 z = 0; z < 8; z++)
if((ourFontData[(c << 3) + y] >> x) & 1)
{
if((ourFontData[(x << 3) + y] >> z) & 1)
{
tmp.x = ((x-lines*32)<<3) + z;
tmp.y = y + lines*8;
tmp.w = tmp.h = 1;
SDL_FillRect(fontTexture, &tmp,
SDL_MapRGBA(fontTexture->format, 0x10, 0x10, 0x10, 0xff));
}
tmp.x = x;
tmp.y = y;
tmp.w = tmp.h = 1;
SDL_FillRect(fontTexture, &tmp,
SDL_MapRGBA(fontTexture->format, 0x10, 0x10, 0x10, 0xff));
}
}
}
}
// Generate the character coordinates
for(uInt32 i = 0; i < 256; i++)
{
uInt32 row = i / 32;
uInt32 col = i - (row*32);
myFontCoord[i].minX = (GLfloat) (col*8) / 256;
myFontCoord[i].maxX = (GLfloat) (col*8+8) / 256;
myFontCoord[i].minY = (GLfloat) (row*8) / 64;
myFontCoord[i].maxY = (GLfloat) (row*8+8) / 64;
}
glGenTextures(1, &myFontTextureID);
glBindTexture(GL_TEXTURE_2D, myFontTextureID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, param);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, param);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE,
glBindTexture(GL_TEXTURE_2D, myFontTextureID[c]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, param);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, param);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE,
fontTexture->pixels);
}
SDL_FreeSurface(fontTexture);

View File

@ -13,7 +13,7 @@
// See the file "license" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id: FrameBufferGL.hxx,v 1.2 2003-11-09 23:53:20 stephena Exp $
// $Id: FrameBufferGL.hxx,v 1.3 2003-11-12 15:12:06 stephena Exp $
//============================================================================
#ifndef FRAMEBUFFER_GL_HXX
@ -34,7 +34,7 @@ class MediaSource;
This class implements an SDL OpenGL framebuffer.
@author Stephen Anthony
@version $Id: FrameBufferGL.hxx,v 1.2 2003-11-09 23:53:20 stephena Exp $
@version $Id: FrameBufferGL.hxx,v 1.3 2003-11-12 15:12:06 stephena Exp $
*/
class FrameBufferGL : public FrameBufferSDL
{
@ -141,8 +141,8 @@ class FrameBufferGL : public FrameBufferSDL
// OpenGL texture coordinates for the main surface
GLfloat myTexCoord[4];
// The OpenGL font texture handle
GLuint myFontTextureID;
// The OpenGL font texture handles (one for each character)
GLuint myFontTextureID[256];
// Structure to hold a characters coordinates
struct Coordinates