NeHe教程Qt实现——lesson17
来源:互联网 发布:国内互联网网络股票 编辑:程序博客网 时间:2024/06/02 16:46
NeHe 系列教程之十四:2D纹理字体
英文教程地址:lesson17
本课展示2D纹理生成字体。
首先是字体库的建立及相关字符输出函数:
namespace { GLuint texture[2]; // Storage For Our Font Texture GLuint loop; // Generic Loop Variable GLfloat cnt1; // 1st Counter Used To Move Text & For Coloring GLfloat cnt2; // 2nd Counter Used To Move Text & For Coloring struct FyjBitmapChar { QVector<QVector2D> texCoords; int right; //字符宽度 int height;//字符高度 int ascillValue; }; struct FyjBitmapFont { char *name; int quality; FyjBitmapChar *characters; }; static FyjBitmapChar chars1[128]; static FyjBitmapChar chars2[128]; const FyjBitmapFont font1 = {"standard", 128, chars1}; const FyjBitmapFont font2 = {"Itatic", 128, chars2}; void buildFont() { float cx; // Holds Our X Character Coord float cy; // Holds Our Y Character Coord glBindTexture(GL_TEXTURE_2D, texture[0]); for (loop = 0; loop < 256; loop++) { cx = float(loop%16)/16.0f; //当前字符的x纹理坐标 cy = float(loop/16)/16.0f; //当前字符的y纹理坐标 if (loop < 128) { chars1[loop].texCoords<<QVector2D(cx, cy + 0.0625f) <<QVector2D(cx+0.0625f, cy+0.0625f) <<QVector2D(cx+0.0625f, cy) <<QVector2D(cx, cy); chars1[loop].height = 16; chars1[loop].right = 10; chars1[loop].ascillValue = loop+32; } else { chars2[loop-128].texCoords<<QVector2D(cx, cy + 0.0625f) <<QVector2D(cx+0.0625f, cy+0.0625f) <<QVector2D(cx+0.0625f, cy) <<QVector2D(cx, cy); chars2[loop-128].height = 12; chars2[loop-128].right = 10; chars2[loop-128].ascillValue = loop-128+32; } } } void renderBitmapCharacter(FyjBitmapChar c, int fontSize) { Q_ASSERT_X(c.ascillValue >= 32 && c.ascillValue <= 127, "renderBitmapCharacter", "unspported char"); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); QVector<QVector2D> vertices; vertices<<QVector2D(0, 0) <<QVector2D(fontSize, 0) <<QVector2D(fontSize, fontSize) <<QVector2D(0, fontSize); glVertexPointer(2, GL_FLOAT, 0, vertices.constData()); glTexCoordPointer(2, GL_FLOAT, 0, c.texCoords.constData()); glDrawArrays(GL_QUADS, 0, 4); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); } void renderBitmapString(GLint x, GLint y, QString string, int set, int fontSize) { int numOfReturnChar = 0; if (string.isNull() || string.isEmpty()) return; if (set > 1) set = 1; FyjBitmapFont currentFont; if (set == 0) currentFont = font1; else currentFont = font2; glBindTexture(GL_TEXTURE_2D, texture[0]); glDisable(GL_DEPTH_TEST); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glOrtho(0,640,0,480,-1,1); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glTranslated(x, y, 0); for(int i = 0; i < string.length(); i++) { char c = string.at(i).toAscii(); if (c == '\n') { numOfReturnChar++; glLoadIdentity(); glTranslated(x, y - numOfReturnChar * currentFont.characters[0].height, 0); continue; } renderBitmapCharacter(currentFont.characters[c-32], fontSize); glTranslated(currentFont.characters[c-32].right * fontSize/16, 0, 0); } glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); glEnable(GL_DEPTH_TEST); } void glPrint(GLint x, GLint y, int set, int fontSize, const char *fmt, ...) { char text[256]; // Holds Our String va_list ap; // Pointer To List Of Arguments if (fmt == NULL) // If There's No Text return; // Do Nothing va_start(ap, fmt); // Parses The String For Variables vsprintf(text, fmt, ap); // And Converts Symbols To Actual Numbers va_end(ap); // Results Are Stored In Text renderBitmapString(x, y, QString(text), set, fontSize); } void drawTextureMappedQuad() { QVector<QVector2D> vertices; QVector<QVector2D> texCoords; glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); vertices<<QVector2D(-1.0f, 1.0f) <<QVector2D(1.0f, 1.0f) <<QVector2D(1.0f,-1.0f) <<QVector2D(-1.0f,-1.0f); texCoords<<QVector2D(0.0f,0.0f) <<QVector2D(1.0f,0.0f) <<QVector2D(1.0f,1.0f) <<QVector2D(0.0f,1.0f); glTexCoordPointer(2, GL_FLOAT, 0, texCoords.constData()); glVertexPointer(2, GL_FLOAT, 0, vertices.constData()); glDrawArrays(GL_QUADS, 0, 4); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); }}
接着是字体纹理加载:
void MyGLWidget::loadTextures(){ texture[0] = bindTexture(QString(":/Font.bmp"), GL_TEXTURE_2D, GL_RGBA, QGLContext::LinearFilteringBindOption); // Create Nearest Filtered Texture glBindTexture(GL_TEXTURE_2D, texture[0]); texture[1] = bindTexture(QString(":/Bumps.bmp"), GL_TEXTURE_2D, GL_RGBA, QGLContext::LinearFilteringBindOption); // Create Linear Filtered Texture glBindTexture(GL_TEXTURE_2D, texture[1]);}
初始化:
void MyGLWidget::initializeGL(){ loadTextures(); glEnable(GL_TEXTURE_2D); buildFont(); glBlendFunc(GL_SRC_ALPHA,GL_ONE); glShadeModel(GL_SMOOTH); // Enables Smooth Shading glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // Black Background glClearDepth(1.0f); // Depth Buffer Setup glEnable(GL_DEPTH_TEST); // Enables Depth Testing glDepthFunc(GL_LEQUAL); // The Type Of Depth Test To Do glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really Nice Perspective Calculations}
绘制:
void MyGLWidget::paintGL(){ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer glLoadIdentity(); // Reset The Current Modelview Matrix glBindTexture(GL_TEXTURE_2D, texture[1]); glTranslatef(0.0f,0.0f,-5.0f); glRotatef(45.0f,0.0f,0.0f,1.0f); glRotatef(cnt1*30.0f,1.0f,1.0f,0.0f); glDisable(GL_BLEND); glColor3f(1.0f,1.0f,1.0f); drawTextureMappedQuad(); glRotatef(90.0f,1.0f,1.0f,0.0f); drawTextureMappedQuad(); glEnable(GL_BLEND); glLoadIdentity(); glColor3f(1.0f*float(cos(cnt1)),1.0f*float(sin(cnt2)),1.0f-0.5f*float(cos(cnt1+cnt2))); glPrint(int((280+250*cos(cnt1))),int(235+200*sin(cnt2)),0, 16, "NeHe"); glColor3f(1.0f*float(sin(cnt2)),1.0f-0.5f*float(cos(cnt1+cnt2)),1.0f*float(cos(cnt1))); glPrint(int((280+230*cos(cnt2))),int(235+200*sin(cnt1)), 1, 24, "OpenGL"); glColor3f(0.0f,0.0f,1.0f); glPrint(int(240+200*cos((cnt2+cnt1)/5)),2, 0, 16, "Giuseppe D'Agata"); glColor3f(1.0f,1.0f,1.0f); glPrint(int(242+200*cos((cnt2+cnt1)/5)),2, 0, 16, "Giuseppe D'Agata"); cnt1+=0.01f; cnt2+=0.0081f;}
运行效果图:
- NeHe教程Qt实现——lesson17
- NeHe教程Qt实现——lesson01
- NeHe教程Qt实现——lesson02
- NeHe教程Qt实现——lesson03
- NeHe教程Qt实现——lesson04
- NeHe教程Qt实现——lesson05
- NeHe教程Qt实现——lesson06
- NeHe教程Qt实现——lesson07
- NeHe教程Qt实现——lesson08
- NeHe教程Qt实现——lesson09
- NeHe教程Qt实现——lesson10
- NeHe教程Qt实现——lesson11
- NeHe教程Qt实现——lesson12
- NeHe教程Qt实现——lesson13
- NeHe教程Qt实现——lesson14
- NeHe教程Qt实现——lesson15
- NeHe教程Qt实现——lesson16
- 用OpenInventor实现的NeHe OpenGL教程-第一课
- PE文件结构(五)
- CF Spiral Maximum
- java设计模式之适配器模式
- PE文件结构(六)
- jquery 验证框架
- NeHe教程Qt实现——lesson17
- Winpcap打开适配器并捕获数据包
- Android 将少量的数据文件保存在 data/data 目录下
- 浅谈C++ 之RAII
- Winpcap打开适配器并捕获数据包:不用回调方法捕获数据包
- hdu1753 大明A+B
- Winpcap打开适配器并捕获数据包:过滤数据包
- 一个简单的注册页面
- Winpcap打开适配器并捕获数据包:解析所捕获的数据包的协议首部