纹理映射字体(OpenGL ES的使用)

2011-02-07 | 分类: 塞班编程 | 编辑: admin | 118 次浏览 | 发表评论

在OpenGL中完成字体显示的有效方法就是为每个字符使用一个单独的纹理映射区域。这个方法非常奏效,效果也很好。

glFont 这里的glFont工具是一个知名的Windows程序和API,可以用来生成字体的纹理映射。根据它的使用许可,这个工具可以为任何商业或非商业程序使用。原作者是Brad Fish (brad.fish@gmail.com).

下面将这个字体类移植到Symbian OS API(原作者已许可此移植工作,并允许发布在这里)

//*******************************************************************

// glfont2.h -- Header for glfont2.cpp

// Copyright (c) 1998-2002 Brad Fish

// See glfont.html for terms of use

// May 14, 2002

//

// Symbian OS port - June 2007

// Luis Valente - lpvalente (http://wiki.forum.nokia.com/index.php/User:Lpvalente)

//

//*******************************************************************

#ifndef GLFONT2_H

#define GLFONT2_H

#include <e32base.h>

#include <GLES/gl.h>

//_____________________________________________________________________________

//

// Simple class to output text as texture-mapped triangles. Does not support

// unicode strings. Reference point when drawing: top-left.

//

class GLFont

{

public:

/**

* Factory-method.

*/

static GLFont* NewL (const TDesC & aFilename);

public:

/**

* Destructor.

*/

~GLFont ();

public:

/**

* Retrieves the texture width and height.

*/

void GetTexSize (TInt & aWidth, TInt & aHeight);

/**

* Retrieves the character interval.

*/

void GetCharInterval (TInt & aStart, TInt & aEnd);

/**

* Retrieves the character dimensions.

*/

void GetCharSize (TText8 c, TInt & aWidth, TInt aHeight);

/**

* Calculates the dimensions of a string.

*/

void GetStringSize (const TDesC8 & aText, TInt & aWidth, TInt & aHeight);

/**

* Renders a string.

*/

void DrawString (const TDesC8 & aText, GLfixed aX, GLfixed aY);

/**

* Sets required states for the font.

*/

void BeginDraw ()

{

glEnable (GL_BLEND);

glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

glEnable (GL_TEXTURE_2D);

glEnableClientState (GL_TEXTURE_COORD_ARRAY);

}

/**

* Turns off required states.

*/

void EndDraw ()

{

glDisable (GL_BLEND);

glDisable (GL_TEXTURE_2D);

glDisableClientState (GL_TEXTURE_COORD_ARRAY);

}

private:

/**

* Default constructor.

*/

GLFont ();

/**

* Final part of the two-phase constructor.

*/

void ConstructL (const TDesC & aFilename);

/**

* Loads the font file.

*/

void LoadFileL (RFs & aFs, const TDesC & aFilename);

/**

* Destroys the font.

*/

void Destroy ();

private:

// single character

struct GLFontChar

{

GLfixed dx, dy;

GLfixed tx1, ty1;

GLfixed tx2, ty2;

};

// font header

struct GLFontHeader

{

GLuint tex;

TInt texWidth, texHeight;

TInt startChar, endChar;

GLFontChar *chars;

};

private:

GLFontHeader iHeader;

};

//*******************************************************************

#endif

下面是类的实现

//*******************************************************************

// glfont2.cpp -- glFont Version 2.0 implementation

// Copyright (c) 1998-2002 Brad Fish

// See glfont.html for terms of use

// May 14, 2002

//

// Symbian OS port - June 2007

// Luis Valente - lpvalente@gmail.com

//

//*******************************************************************

// Symbian OS headers

#include <s32file.h>

#include <eikenv.h>

#include <eikappui.h>

#include <eikapp.h>

#include "glfont2.h"

#include "FixedMath.h"

// GLFontChar structure as stored in file

struct GLFontCharFile

{

TReal32 dx, dy;

TReal32 tx1, ty1;

TReal32 tx2, ty2;

};

// GLFontHeaderFile structure as stored in file

struct GLFontHeaderFile

{

TInt32 tex;

TInt32 texWidth, texHeight;

TInt32 startChar, endChar;

TUint32 chars;

};

//_____________________________________________________________________________

//

// Default constructor.

//

GLFont::GLFont ()

{

// Initialize iHeader to safe state

iHeader.tex = 0;

iHeader.texWidth = 0;

iHeader.texHeight = 0;

iHeader.startChar = 0;

iHeader.endChar = 0;

iHeader.chars = NULL;

// OpenGL texture

glGenTextures (1, &iHeader.tex);

}

//_____________________________________________________________________________

//

// Destructor.

//

GLFont::~GLFont ()

{

// Destroy the font

Destroy();

// delete texture

glDeleteTextures (1, &iHeader.tex);

}

//_____________________________________________________________________________

//

// Factory-method.

//

GLFont * GLFont::NewL (const TDesC & aFilename)

{

GLFont* f = new (ELeave) GLFont();

CleanupStack::PushL (f);

f->ConstructL (aFilename);

CleanupStack::Pop ();

return f;

}

//_____________________________________________________________________________

//

// Second part of the two-phase construction.

//

void GLFont::ConstructL (const TDesC & aFilename)

{

// Destroy the old font if there was one, just to be safe

Destroy();

// Open file session with server

RFs session;

User::LeaveIfError (session.Connect());

CleanupClosePushL (session);

// retrieve private application folder

TFileName path;

session.PrivatePath (path);

// retrieve full application path on device

#ifndef __WINS__

TFileName appFullName =

CEikonEnv::Static()->EikAppUi()->Application()->AppFullName();

TParse parse;

parse.Set (appFullName, NULL, NULL);

path.Insert (0, parse.Drive());

#endif

// update filename with full path

TFileName fullFilename (path);

fullFilename.Append (aFilename);

// load file

LoadFileL (session, fullFilename);

// close server session

CleanupStack::PopAndDestroy();

}

//_____________________________________________________________________________

//

// Loads the font file.

//

void GLFont::LoadFileL (RFs & aFs, const TDesC & aFilename)

{

// Open input file

RFileReadStream readStream;

User::LeaveIfError (readStream.Open (aFs, aFilename, EFileRead));

readStream.PushL();

// Read the iHeader from file

GLFontHeaderFile headerFile;

headerFile.tex = readStream.ReadInt32L ();

headerFile.texWidth = readStream.ReadInt32L();

headerFile.texHeight = readStream.ReadInt32L();

headerFile.startChar = readStream.ReadInt32L();

headerFile.endChar = readStream.ReadInt32L();

headerFile.chars = readStream.ReadUint32L();

// copy iHeader file to actual iHeader

iHeader.texWidth = headerFile.texWidth;

iHeader.texHeight = headerFile.texHeight;

iHeader.startChar = headerFile.startChar;

iHeader.endChar = headerFile.endChar;

// Allocate space for character array

TInt numChars = iHeader.endChar - iHeader.startChar + 1;

iHeader.chars = new (ELeave) GLFontChar [numChars];

// Read character array

for (TInt i = 0; i < numChars; ++i)

{

iHeader.chars [i].dx = FloatToFixed (readStream.ReadReal32L () );

iHeader.chars [i].dy = FloatToFixed (readStream.ReadReal32L () );

iHeader.chars [i].tx1 = FloatToFixed (readStream.ReadReal32L () );

iHeader.chars [i].ty1 = FloatToFixed (readStream.ReadReal32L () );

iHeader.chars [i].tx2 = FloatToFixed (readStream.ReadReal32L () );

iHeader.chars [i].ty2 = FloatToFixed (readStream.ReadReal32L () );

}

// Read texture pixel data

TInt numTexBytes = iHeader.texWidth * iHeader.texHeight * 2;

TUint8 * texBytes = new (ELeave) TUint8 [numTexBytes]; CleanupStack::PushL (texBytes);

readStream.ReadL (texBytes, numTexBytes);

// Create OpenGL texture

glBindTexture (GL_TEXTURE_2D, iHeader.tex);

glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);

glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

glTexImage2D (GL_TEXTURE_2D,

0,

GL_LUMINANCE_ALPHA,

iHeader.texWidth,

iHeader.texHeight,

0,

GL_LUMINANCE_ALPHA,

GL_UNSIGNED_BYTE,

(GLvoid *)texBytes);

// Free texture pixels memory

CleanupStack::Pop ();

delete [] texBytes;

// Close input file

readStream.Close();

readStream.Pop();

}

//_____________________________________________________________________________

//

// Font destruction.

//

void GLFont::Destroy ()

{

//Delete the character array if necessary

if (iHeader.chars)

{

delete [] iHeader.chars;

iHeader.chars = 0;

}

}

//_____________________________________________________________________________

//

// Retrieves the texture dimensions.

//

void GLFont::GetTexSize (TInt & aWidth, TInt & aHeight)

{

aWidth = iHeader.texWidth;

aHeight = iHeader.texHeight;

}

//_____________________________________________________________________________

//

// Retrieves the character interval.

//

void GLFont::GetCharInterval (TInt & aStart, TInt & aEnd)

{

aStart = iHeader.startChar;

aEnd = iHeader.endChar;

}

//_____________________________________________________________________________

//

// Retrieves the dimensions of a character.

//

void GLFont::GetCharSize (TText8 aChar, TInt & aWidth, TInt aHeight)

{

// Make sure character is in range

if (aChar < iHeader.startChar || aChar > iHeader.endChar)

{

// Not a valid character, so it obviously has no size

aWidth = 0;

aHeight = 0;

}

else

{

GLFontChar* fontChar;

// Retrieve character size

fontChar = & iHeader.chars [aChar - iHeader.startChar];

aWidth = FixedToInt (MultiplyFixed (fontChar->dx, IntToFixed (iHeader.texWidth) ) );

aHeight = FixedToInt (MultiplyFixed (fontChar->dy, IntToFixed (iHeader.texHeight) ) );

}

}

//_____________________________________________________________________________

//

// Retrieves the dimensions of a string.

//

void GLFont::GetStringSize (const TDesC8 & aText, TInt & aWidth, TInt & aHeight)

{

// Height is the same for now...might change in future

aHeight = FixedToInt (MultiplyFixed (iHeader.chars [iHeader.startChar].dy, IntToFixed (iHeader.texHeight) )

);

// texWidth as fixed

const GLfixed texWidthx = IntToFixed (iHeader.texWidth);

// Calculate width of string

GLfixed widthx = 0;

for (TInt i = 0; i < aText.Length(); i++)

{

// Make sure character is in range

const TText8 c = aText [i];

if (c < iHeader.startChar || c > iHeader.endChar)

continue;

// Get pointer to glFont character

const GLFontChar* fontChar = & iHeader.chars [c - iHeader.startChar];

// Get width and height

widthx += MultiplyFixed (fontChar->dx, texWidthx);

}

// Save width

aWidth = FixedToInt (widthx);

}

//_____________________________________________________________________________

//

// Renders a string. Reference point is top-left.

//

void GLFont::DrawString (const TDesC8 & aText, GLfixed aX, GLfixed aY)

{

// vertex arrays to render the string

GLfixed vertices [4*2];

GLfixed texCoords [4*2];

const GLubyte indices [] = {1, 2, 0, 3};

glVertexPointer (2, GL_FIXED, 0, vertices);

glTexCoordPointer (2, GL_FIXED, 0, texCoords);

// Bind texture

glBindTexture (GL_TEXTURE_2D, iHeader.tex);

// Loop through characters

for (TInt i = 0; i < aText.Length(); i++)

{

// Make sure character is in range

TText8 c = aText [i];

if (c < iHeader.startChar || c > iHeader.endChar)

continue;

// Get pointer to glFont character

GLFontChar* fontChar = &iHeader.chars [c - iHeader.startChar];

// Get width and height

GLfixed width = MultiplyFixed (fontChar->dx, IntToFixed (iHeader.texWidth) );

GLfixed height = MultiplyFixed (fontChar->dy, IntToFixed (iHeader.texHeight) );

// Specify texture coordinates

texCoords [0] = fontChar->tx1; texCoords [1] = fontChar->ty1;

texCoords [2] = fontChar->tx1; texCoords [3] = fontChar->ty2;

texCoords [4] = fontChar->tx2; texCoords [5] = fontChar->ty2;

texCoords [6] = fontChar->tx2; texCoords [7] = fontChar->ty1;

// and vertices

vertices [0] = aX; vertices [1] = aY;

vertices [2] = aX; vertices [3] = aY - height;

vertices [4] = aX + width; vertices [5] = aY - height;

vertices [6] = aX + width; vertices [7] = aY;

// draw

glDrawElements (GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, indices);

// Move to next character

aX += width;

}

}

还有代码需要的整型数学运算方法

//------------------------------

#ifndef FIXED_MATH_H_

#define FIXED_MATH_H_

//------------------------------

// INCLUDES

#include <e32base.h>

#include <e32std.h>

#include <e32math.h>

#include <GLES/gl.h>

// FUNCTIONS

inline GLfixed IntToFixed (GLint aValue)

{ return aValue << 16; }

inline GLfixed FloatToFixed (GLfloat aValue)

{ return (GLfixed) (aValue * 65536.0f); }

inline GLint FixedToInt (GLfixed aValue)

{ return aValue >> 16; }

inline GLfloat FixedToFloat (GLfixed aValue)

{ return (GLfloat) (aValue * (1 / 65536.0f)); }

inline GLfixed MultiplyFixed (GLfixed op1, GLfixed op2)

{

TInt64 r = (TInt64)op1 * (TInt64)op2;

return (GLfixed) (r >> 16);

}

//------------------------------

#endif

注意事项和限制

这个字体类适用于2D字体,我们要注意的是在渲染前构造所需的正投影。下列是示例代码

// Rect() is a method that returns the current drawing rectangle.

// The (0,0) point will be the on bottom-left corner.

glViewport (0, 0, Rect().Width(), Rect().Height());

glMatrixMode (GL_PROJECTION);

glLoadIdentity ();

glOrthox (0, IntToFixed (Rect().Width()), 0, IntToFixed (Rect().Height()), -1, 1);

glMatrixMode (GL_MODELVIEW);

glLoadIdentity ();

注意BeginDraw()和EndDraw()方法需要在建造渲染所需状态前调用。例如,如果透明绑定不被允许,那么就要注意和字符相关的映射区域。

目前,这个类只支持8位描述符,未来将会扩展为支持16位的描述符和资源字符。

(来自:Forum Nokia Wiki)

关键字:

发表评论

您的昵称 *

您的邮箱 *

您的网站

icon_wink.gif icon_neutral.gif icon_mad.gif icon_twisted.gif icon_smile.gif icon_eek.gif icon_sad.gif icon_rolleyes.gif icon_razz.gif icon_redface.gif icon_surprised.gif icon_mrgreen.gif icon_lol.gif icon_idea.gif icon_biggrin.gif icon_evil.gif icon_cry.gif icon_cool.gif icon_arrow.gif icon_confused.gif icon_question.gif icon_exclaim.gif 
返回首页 | 关于我们 | 联系我们 | 广告合作 | 网站地图 | 标签页 | 友情链接 | 版权声明
Top