Qt 中使用freeType2实现简单的文本渲染

      就按转载说吧,其实自己就是把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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值