就按转载说吧,其实自己就是把win32平台,改到了Qt平台,然后去掉了一些原作者自己封装的类,基本都是OpenGL的原生函数,没啥技术,就是交流学习吧。
下面就贴代码吧。
这是头文件
#pragma once
#include <freetype2/ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H
#include <QOpenGLFunctions_3_3_Core>
#include <QOpenGLShaderProgram>
#include <glm/glm.hpp>
#include <glm/ext.hpp>
#include <vector>
#include <QOpenGLContext>
#include <QSurface>
#define FOR(q,n) for(int q=0;q<n;q++)
using std::string;
class freeTypeFont :protected QOpenGLFunctions_3_3_Core
{
public:
freeTypeFont(QOpenGLContext * context,QSurface * surface);
bool loadFont(std::string sFile, int iPXSize);
int getTextWidth(string sText, int iPXSize);
void print(string sText, int x, int y, int iPXSize = -1);
void releaseFont();
void setShaderProgram(QOpenGLShaderProgram * a_shShaderProgram);
~freeTypeFont(void);
private:
void createChar(int iIndex);
int iAdvX[256], iAdvY[256];
int iBearingX[256], iBearingY[256];
int iCharWidth[256], iCharHeight[256];
int iLoadedPixelSize, iNewLine;
bool bLoaded;
GLuint texID[256];
GLuint uiVAO;
GLuint uiVBOPosintions;
GLuint uiVBOTexCoods;
FT_Library ftLib;
FT_Face ftFace;
std::vector<glm::vec2> positions;
std::vector<glm::vec2> texcoods;
QOpenGLShaderProgram * shShaderProgram;
QOpenGLContext* ftContext;
QSurface * ftSurface;
};
这是源文件
#include "freeTypeFont .h"
#include <freetype2/freetype.h>
#include <QDebug>
#define max(a,b) (((a) > (b)) ? (a) : (b))
#pragma comment (lib,"freeType.lib")
freeTypeFont::freeTypeFont(QOpenGLContext *context, QSurface * surface)
{
ftContext = context;
ftSurface = surface;
ftContext->makeCurrent(ftSurface);
initializeOpenGLFunctions();
}
inline int next_p2(int n){ int res = 1; while (res < n)res <<= 1; return res; }
void freeTypeFont::createChar(int iIndex)
{
qDebug() << " Index " << iIndex;
ftContext->makeCurrent(ftSurface);
FT_Load_Glyph(ftFace, FT_Get_Char_Index(ftFace, iIndex), FT_LOAD_DEFAULT);
FT_Render_Glyph(ftFace->glyph, FT_RENDER_MODE_NORMAL);
FT_Bitmap * pBitmap = &ftFace->glyph->bitmap;
int iW = pBitmap->width;
int iH = pBitmap->rows;
int iTW = next_p2(iW);
int iTH = next_p2(iH);
GLubyte* bData = new GLubyte[iTW*iTH];
FOR(ch, iTH)FOR(cw,iTW)
bData[ch*iTW + cw] = (ch >= iH || cw >= iW) ? 0 : pBitmap->buffer[(iH - ch - 1)*iW + cw];
/*
* 生成纹理
*/
glGenTextures(1, &texID[iIndex]);
glBindTexture(GL_TEXTURE_2D, texID[iIndex]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, iTW, iTH, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, bData);
iAdvX[iIndex] = ftFace->glyph->advance.x >> 6;
iBearingX[iIndex] = ftFace->glyph->metrics.horiBearingX >> 6;
iCharWidth[iIndex] = ftFace->glyph->metrics.width >> 6;
iAdvY[iIndex] = (ftFace->glyph->metrics.height - ftFace->glyph->metrics.horiBearingY) >> 6;
iBearingY[iIndex] = ftFace->glyph->metrics.horiBearingY >> 6;
iCharHeight[iIndex] = ftFace->glyph->metrics.height >> 6;
iNewLine = 0;
iNewLine = max(iNewLine, int(ftFace->glyph->metrics.height >> 6));
glm::vec2 vQuad[] =
{
glm::vec2(0.0f, float(-iAdvY[iIndex] + iTH)),
glm::vec2(0.0f, float(-iAdvY[iIndex])),
glm::vec2(float(iTW), float(-iAdvY[iIndex] + iTH)),
glm::vec2(float(iTW), float(-iAdvY[iIndex]))
};
glm::vec2 vTexQuad[] = { glm::vec2(0.0f, 1.0f), glm::vec2(0.0f, 0.0f), glm::vec2(1.0f, 1.0f), glm::vec2(1.0f, 0.0f) };
FOR(i, 4)
{
positions.push_back(vQuad[i]);
texcoods.push_back(vTexQuad[i]);
}
delete[] bData;
}
bool freeTypeFont::loadFont(std::string sFile, int iPXSize)
{
ftContext->makeCurrent(ftSurface);
bool bError = FT_Init_FreeType(&ftLib);
bError = FT_New_Face(ftLib, sFile.c_str(), 0, &ftFace);
if (bError)return false;
FT_Set_Pixel_Sizes(ftFace, iPXSize, iPXSize);
iLoadedPixelSize = iPXSize;
glGenVertexArrays(1, &uiVAO);
glBindVertexArray(uiVAO);
FOR(i, 128) createChar(i);
bLoaded = true;
glGenBuffers(1, &uiVBOPosintions);
glBindBuffer(GL_ARRAY_BUFFER, uiVBOPosintions);
glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec2)*positions.size(), (GLvoid*)&positions[0][0], GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0);
glGenBuffers(1, &uiVBOTexCoods);
glBindBuffer(GL_ARRAY_BUFFER, uiVBOTexCoods);
glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec2)*texcoods.size(), (GLvoid*)&texcoods[0][0], GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0);
FT_Done_Face(ftFace);
FT_Done_FreeType(ftLib);
glBindVertexArray(0);
return true;
}
void freeTypeFont::print(string sText, int x, int y, int iPXSize /* = -1 */)
{
ftContext->makeCurrent(ftSurface);
if (!bLoaded) return;
glBindVertexArray(uiVAO);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
int iCurX = x, iCurY = y;
if (iPXSize == -1)iPXSize = iLoadedPixelSize;
float fScale = float(iPXSize) / float(iLoadedPixelSize);
FOR(i, (int)sText.size())
{
if (sText[i] == '\n')
{
iCurX = x;
iCurY -= iNewLine*iPXSize / iLoadedPixelSize;
continue;
}
int iIndex = int(sText[i]);
iCurX += iBearingX[iIndex] * iPXSize / iLoadedPixelSize;
if (sText[i] != ' ')
{
glBindTexture(GL_TEXTURE_2D,texID[iIndex]);
glm::mat4 mModelView = glm::translate(glm::mat4(1.0f), glm::vec3(float(iCurX), float(iCurY), 0.0f));
mModelView = glm::scale(mModelView, glm::vec3(fScale));
GLint locMV =glGetUniformLocation(shShaderProgram->programId(), "modelViewMatrix");
glUniformMatrix4fv(locMV, 1, GL_FALSE, &mModelView[0][0]);
// Draw character
glDrawArrays(GL_TRIANGLE_STRIP, iIndex*4, 4);
}
iCurX += (iAdvX[iIndex] - iBearingX[iIndex])*iPXSize / iLoadedPixelSize;
}
glDisable(GL_BLEND);
}
void freeTypeFont::setShaderProgram(QOpenGLShaderProgram* a_shShaderProgram)
{
shShaderProgram = a_shShaderProgram;
}
void freeTypeFont::releaseFont()
{
glDeleteBuffers(1, &uiVBOPosintions);
glDeleteBuffers(1, &uiVBOTexCoods);
glDeleteVertexArrays(1, &uiVAO);
}
freeTypeFont::~freeTypeFont(void)
{
}
使用的时候就是
在类中声明个该类的指针font
然后ftFont = new freeTypeFont(m_context,this);//Qt需要上下文环境
在初始时,传入字体处理的着色器程序,载入字体
ftFont->setShaderProgram(ftProgram);
ftFont->loadFont("comic.ttf", 64);
glDisable(GL_DEPTH_TEST);
glDepthFunc(GL_ALWAYS);
/*
* 字体渲染
*/
ftProgram->bind();
GLfloat color[] = { 1.0f, 0.0f, 0.0f, 1.0f };
glm::mat4 orthoMatrix = glm::ortho(0.0f, float(width()), 0.0f, float(height()));
GLuint locOrtho = glGetUniformLocation(ftProgram->programId(), "projectionMatrix");
GLuint locColor = glGetUniformLocation(ftProgram->programId(), "vColor");
GLuint locftSampler = glGetUniformLocation(ftProgram->programId(), "gSampler");
glUniformMatrix4fv(locOrtho, 1, GL_FALSE, &orthoMatrix[0][0]);
glUniform4fv(locColor, 1, color);
glUniform1i(locftSampler, 0);
ftFont->print("GLuint locOrtho = glGetUniformLocation(ftProgram->programId(), projectionMatrix);", 20, height() - 10 - 16, 16);
ftFont->print("GLuint locOrtho = glGetUniformLocation(ftProgram->programId(), projectionMatrix);", 20, height() - 40 - 16, 16);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
着色器代码 顶点着色器
#version 330
uniform mat4 projectionMatrix;
uniform mat4 modelViewMatrix;
layout (location = 0) in vec2 inPosition;
layout (location = 1) in vec2 inCoord;
out vec2 texCoord;
void main()
{
gl_Position = projectionMatrix * modelViewMatrix*vec4(inPosition,0.0f, 1.0f);
texCoord = inCoord;
}
片段着色器
#version 330
in vec2 texCoord;
out vec4 outputColor;
uniform sampler2D gSampler;
uniform vec4 vColor;
void main()
{
vec4 vTexColor = texture2D(gSampler, texCoord);
outputColor = vec4(vTexColor.r, vTexColor.r,vTexColor.r, vTexColor.r) * vColor;
}
参考
http://www.mbsoftworks.sk/index.php?page=tutorials&series=1&tutorial=12