OpenGL字体绘制
/* glfont.hpp sdragonx 2019-08-15 00:03:33 opengl字体类,提供初学者参考学习 opengl初始化之后,创建字体
font.init(L"微软雅黑", 32, 512); 然后在绘制函数里面添加以下测试代码: //开启2D模式,后面的800x600要根据窗口的实际客户区大小设置,不然缩放之后效果不好
push_view2D(0, 0, 800, 600); wchar_t* str = L"abcdef字体绘制abcdef?123456ijk微软雅黑"; font.color = vec4ub(255, 255, 255, 128);
font.print(0, 0, str, wcslen(str)); font.tab_print(0, 32, L"abc\t123456\t7890", TEXT_MAX); wchar_t* tabled = L"abcdef字体绘制\tabc制表符\t123456";
font.color = vec4ub(255, 0, 0, 255);
font.tab_print(0, 64, tabled, wcslen(tabled)); font.color = vec4ub(255, 0, 0, 255);
font.draw_text(0, 200, 200, 400, str, wcslen(str), PT_LEFT);
font.color = vec4ub(0, 255, 0, 255);
font.draw_text(300, 200, 200, 400, str, wcslen(str), PT_CENTER);
font.color = vec4ub(255, 0, 255, 255);
font.draw_text(600, 200, 200, 400, str, wcslen(str), PT_RIGHT); pop_view();
//代码结束 */
#ifndef GLFONT_HPP_20190815000333
#define GLFONT_HPP_20190815000333 #include <windows.h> #include <stdint.h>
#include <map>
#include <vector> //opengl头文件,根据环境更改
#ifdef __glew_h__
#include <glew.h>
#elif defined(__glad_h_)
#include <glad.h>
#else
#include <gl/gl.h>
#endif #if defined(__GNUC__) || defined(__clang__)
#define TYPENAME typename
#else
#define TYPENAME
#endif #define CGL_DEFAULT_FONT_SIZE 16 //默认字体大小
#define TEXT_MAX UINT32_MAX //0xFFFFFFFF namespace cgl{ #pragma pack(push, 1) //大纹理里面小图块结构
class teximage
{
public:
typedef teximage this_type; public:
intptr_t image; //纹理
uint16_t x, y, width, height; //小图在大图里面的位置信息
float u1, v1, u2, v2; //小图的uv坐标信息 public:
teximage():image(), x(), y(), width(), height(), u1(0.0f), v1(0.0f), u2(1.0f), v2(1.0f)
{
} this_type& operator=(const this_type& div)
{
image = div.image;
x = div.x;
y = div.y;
width = div.width;
height = div.height;
u1 = div.u1;
v1 = div.v1;
u2 = div.u2;
v2 = div.v2;
return *this;
}
}; //字符信息
//如果一个字符需要输出到left、top的位置,字符实际位置是left+x、top+y
//输出完毕之后,下一个字符的位置是left+next_x、top+next_y
struct char_info
{
int16_t x; //字符偏移位置
int16_t y;
int16_t next_x;//字符大小,下一字符偏移位置
int16_t next_y;
}; //vec3<T>
template<typename T>
struct vec3
{
T x, y, z;
}; typedef vec3<int> vec3i;
typedef vec3<float> vec3f; //vec4<T>
template<typename T>
struct vec4
{
union{
T data[4];
struct{
T x, y, width, height;
};
struct{
T red, green, blue, alpha;
};
}; vec4() : x(), y(), width(), height(){/*void*/}
vec4(T vx, T vy, T vw, T vh) : x(vx), y(vy), width(vw), height(vh){/*void*/}
}; typedef vec4<int> vec4i;
typedef vec4<float> vec4f;
typedef vec4<BYTE> vec4ub; template<typename VT, typename TT, typename CT>
struct vtx3t2c4
{
typedef vtx3t2c4 this_type;
typedef vec4<CT> color_type; VT x, y, z;
TT u, v;
color_type color; vtx3t2c4() : x(), y(), z(), u(), v(), color(){/*void*/}
vtx3t2c4(const vec3<VT>& vtx, TT tu, TT tv, const color_type& cc) :
x(v.x), y(v.y), z(v.z), u(tu), v(tv), color(cc) { /*void*/ } vtx3t2c4(VT vx, VT vy, VT vz, TT vu, TT vv, const color_type& cc) :
x(vx), y(vy), z(vz), u(vu), v(vv), color(cc) { /*void*/ } this_type& operator=(const vec3<VT>& p)
{
x = p.x;
y = p.y;
z = p.z;
return *this;
}
}; typedef vtx3t2c4<float, float, uint8_t> vtx3f; #pragma pack(pop) //---------------------------------------------------------------------------
//opengl的一些扩展函数 //2D视觉模式,如果你使用的是矩阵操作,把这里面的函数替换成矩阵操作
void push_view2D(int left, int top, int width, int height)
{
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
/*
#if CGL_COORDINATE == CGL_LOWER_LEFT
//直角坐标系
this->ortho(left, width, top, height, 0, INT16_MAX);
//重新设置正面,默认GL_CCW
glFrontFace(GL_CCW); #else*/ //windows坐标系
glOrtho(left, left+width, top+height, top, 0, INT16_MAX);
glFrontFace(GL_CW);
//#endif //十字坐标系
//glOrtho(-width/2, width/2, -height/2, height/2, 0, INT_MAX);// //反转屏幕
//glScalef(1.0f, -1.0f, 1.0f);
//glTranslatef(0.0f, -height, 0.0f); glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.375f, 0.375f, 0.0f);//GL_POINTS and GL_LINES don't touch the right pixels
glDisable(GL_DEPTH_TEST);//关闭深度测试
glDisable(GL_CULL_FACE); //关闭面剔除
} //还原视觉模式
void pop_view()
{
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
} //绘图函数,这个根据使用的库更改和优化
void vtx_begin(const vtx3f* vtx)
{
glVertexPointer(3, GL_FLOAT, sizeof(vtx3f), vtx);
glTexCoordPointer(2, GL_FLOAT, sizeof(vtx3f), &vtx->u);
glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(vtx3f), vtx->color.data); glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
} void vtx_end(const vtx3f* vtx)
{
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
} int draw_arrays(int shape, const vtx3f* vtx, size_t pos, size_t size)
{
vtx_begin(vtx);
glDrawArrays(shape, pos, size);
vtx_end(vtx);
return 0;
} //绘制图片
int draw_image(intptr_t image, vec4ub color, float x, float y, float width, float height,
float u1 = 0.0f, float v1 = 0.0f, float u2 = 1.0f, float v2 = 1.0f)
{
vtx3f vtx[] = {
vtx3f(x, y, 0.0f, u1, v1, color),
vtx3f(x + width, y, 0.0f, u2, v1, color),
vtx3f(x + width, y + height, 0.0f, u2, v2, color),
vtx3f(x , y + height, 0.0f, u1, v2, color)
};
glBindTexture(GL_TEXTURE_2D, image);
return draw_arrays(GL_TRIANGLE_FAN, vtx, 0, 4);
} int draw_image(const teximage& image, vec4ub color, float x, float y, float width, float height)
{
return draw_image(image.image, color, x, y, width, height, image.u1, image.v1, image.u2, image.v2);
} //---------------------------------------------------------------------------
//GDI字体封装类
//有需要的,可以把这个类替换成freetype等其他字体库
//实现方法不变,直接替换掉这个类就好
//比如我用freetype2实现一个ftFont的类
//或者用stb_font(一个轻量级freetype库)实现一个stbFont类 class gdifont
{
private:
HDC m_dc; //内存DC
HFONT m_font; //字体句柄
GLYPHMETRICS m_gm; //字符模型信息
MAT2 m_mat; //转置矩阵,默认初始矩阵 std::wstring m_ttfile;//用于保存单独字体文件的路径
std::vector<BYTE> m_pixelbuf;//用于保存字符像素信息
//std::vector<BYTE> m_fontResource;//内存字体 public:
gdifont() : m_dc(NULL), m_font(NULL), m_ttfile(), m_pixelbuf()
{
//初始化字体转置矩阵,默认初始矩阵
//这个矩阵可以实现字体的旋转、偏移、缩放等效果
//2x2矩阵
//1 0
//0 1
m_mat.eM11.value = 1;m_mat.eM11.fract = 0;
m_mat.eM12.value = 0;m_mat.eM12.fract = 0;
m_mat.eM21.value = 0;m_mat.eM21.fract = 0;
m_mat.eM22.value = 1;m_mat.eM22.fract = 0;
} //字体句柄
HFONT handle()const
{
return m_font;
} //创建字体
int create(const wchar_t* fontname, int size, int charset = GB2312_CHARSET)
{
//如果需要,首先释放资源
if(this->handle()){
this->dispose();
} //创建内存DC
m_dc = CreateCompatibleDC(0); //创建字体
m_font = CreateFontW(
size, // logical height of font height
0, // logical average character width
0, // angle of escapement
0, // base-line orientation angle
0, // font weight
0, // italic attribute flag
0, // underline attribute flag
0, // strikeout attribute flag
charset, // character set identifier
0, // output precision
0, // clipping precision
DEFAULT_QUALITY, // output quality
DEFAULT_PITCH | FF_SWISS, // pitch and family
fontname // pointer to typeface name string
); //绑定字体到内存DC
SelectObject(m_dc, m_font); return 0;
} //加载单独的字体文件
/*例如:
font.load(
"myfont.ttf", //字体文件,windows系统支持的字体,目录可以是绝对路径,也可以是相对路径
"字体名称", //点开字体文件,上面显示的字体名称,比如“微软雅黑”
16, //字体大小
GB2312_CHARSET);//如果是中文字体,要设置中文字符集
*/ int load(const wchar_t* filename, const wchar_t* fontname, int size, int charset = 0)
{
if(this->handle()){
this->dispose();
} m_ttfile = filename;
AddFontResourceExW(m_ttfile.c_str(), FR_PRIVATE, 0);
this->create(fontname, size, charset); return 0;
} //加载内存、程序资源内的字体,这个暂时懒得实现了,有需要的可以查一下WINAPI实现
/*
void load_memory(...)
{
FILE* f = fopen(filename, "rb");
fseek(f, 0, SEEK_END);
m_fontResource.resize(ftell(f));
fseek(f, 0, SEEK_SET);
fread(&m_fontResource[0], 1, m_fontResource.size(), f);
fclose(f); DWORD dwFonts = 0;
m_fontH = (HFONT)AddFontMemResourceEx(&m_fontResource[0], m_fontResource.size(), 0, &dwFonts);
}
*/ //释放资源
void dispose()
{
if(m_dc){
DeleteDC(m_dc);
m_dc = null;
} if(m_font){
DeleteObject(m_font);
m_font = null;
} if(!m_ttfile.empty()){
RemoveFontResourceExW(m_ttfile.c_str(), FR_PRIVATE, 0);
m_ttfile.clear();
} //RemoveFontMemResourceEx(m_font);
} //获取一个字体的位图和字符信息
int render_char(wchar_t ch, char_info& info)
{
//获取字符位图空间大小
int size = GetGlyphOutlineW(m_dc, ch, GGO_GRAY8_BITMAP, &m_gm, 0, NULL, &m_mat);
//重新设置位图缓冲区大小
m_pixelbuf.resize(size);
//获得字符位图像素信息
GetGlyphOutlineW(m_dc, ch, GGO_GRAY8_BITMAP, &m_gm, 64*64, &m_pixelbuf[0], &m_mat);
//GetGlyphOutline获得的位图像素是64阶灰度,要转换成256阶灰度
//当然如果你要通过shader渲染,并希望获得一些其他效果,可以不转换,或进行其他转换
gray256();
//填写一下字符信息
info.x = m_gm.gmptGlyphOrigin.x;
info.y = m_gm.gmptGlyphOrigin.y;
info.next_x = m_gm.gmCellIncX;
info.next_y = m_gm.gmBlackBoxY;
return 0;
} //位图宽度
int width()const
{
return m_gm.gmBlackBoxX;
} //位图高度
int height()const
{
return m_gm.gmBlackBoxY;
} //位图像素数据
void* data()
{
return &m_pixelbuf[0];
} //64阶灰度转256阶灰度
void gray256()
{
BYTE* p = &m_pixelbuf[0];
int c;
//数据行是四字节对齐的
DWORD linewidth = (m_gm.gmBlackBoxX + 3) & 0xFFFFFFFC;
for(size_t y=0; y<m_gm.gmBlackBoxY; ++y){
for(size_t x = 0; x < m_gm.gmBlackBoxX; ++x){
c = p[x];
c *= 4;//64x4 = 256
if(c > 255)c = 255;//约束在0~255范围之内
p[x] = c;
}
p += linewidth;//移动到下一行
}
} //测试获取的位图,画到一个HDC上面
#ifdef _DEBUG
void paint(HDC dc)
{
BYTE* p = &m_pixelbuf[0];
int c;
//数据行是四字节对齐的
DWORD linewidth = (m_gm.gmBlackBoxX + 3) & 0xFFFFFFFC;
for(size_t y=0; y<m_gm.gmBlackBoxY; ++y){
for(size_t x = 0; x < m_gm.gmBlackBoxX; ++x){
c = p[x];
SetPixelV(dc, x, y, RGB(c, c, c));
}
p += linewidth;
}
}
#endif
}; //---------------------------------------------------------------------------
//imagelist 图集类,自动把小图拼成图集
//
//这个简单的图集类,用于拼合高度大小变化不大的图片,比如图标
//
//有需要的,可以github搜索maxrects库,可以把不同大小的字体拼成一个大图
//一般使用固定大小的字体,因为字符位图大小相对变化不大,空间浪费也不算太大
//使用一个高度(字体高度)作为每一行高度,每添加进一个小图,x方向向右偏移一个位置
//到达右边边界,换行。
//如果到达纹理右下角,则自动添加一个纹理页 template<typename T, typename U = int>
class imagelist
{
public:
struct ITEM
{
teximage image;
U data;
}; typedef const ITEM* item_type;
typedef typename std::map<T, ITEM> map_type;
typedef typename map_type::iterator iterator;
typedef typename map_type::const_iterator const_iterator; private:
std::vector<GLuint> m_texlist; //保存的纹理页
map_type m_itemlist; //小图信息列表,使用std::map组织,也可以根据需要用数组组织
GLenum m_format;//纹理格式
int m_width; //纹理大小
int m_height;
int m_filter; //纹理过滤方式
int m_size; //小图块大小,只记录高度
int m_u, m_v; //当前小图块添加位置 public:
imagelist():m_texlist(), m_itemlist(), m_format(GL_RGBA), m_filter(GL_LINEAR),
m_width(512), m_height(512), m_size(16), m_u(0), m_v(0)
{
} ~imagelist()
{
this->dispose();
} //初始化创建图集
int create(size_t width, size_t height, size_t size, GLenum format = GL_RGBA, GLenum filter = GL_LINEAR)
{
this->dispose();
m_width = width;
m_height = height;
m_format = format,
m_size = size;
m_filter = filter;
m_u = m_v = 0;
return 0;
} //释放资源
void dispose()
{
m_itemlist.clear();
if(!m_texlist.empty()){
//删除所有纹理页
glDeleteTextures(m_texlist.size(), &m_texlist[0]);
m_texlist.clear();
}
m_u = m_v = 0;
} //当前缓存的小图块数量
size_t size()const
{
return m_imglist.size();
} //添加一个小图块
int insert(const T& index, int width, int height, GLenum format, void* data, const U& userdata)
{
//首先移动坐标位置
position_move(width);
//绑定当前纹理,也就是图集的最后一个
glBindTexture(GL_TEXTURE_2D, m_texlist.back());
//更新纹理局部像素
glTexSubImage2D(GL_TEXTURE_2D, 0, m_u, m_v, width, std::min(m_size, height), format, GL_UNSIGNED_BYTE, data);
//保存信息
ITEM item;
item.image.image = m_texlist.back();
item.image.x = m_u;
item.image.y = m_v;
item.image.width = width;
item.image.height = std::min(height, m_size);
item.image.u1 = float(m_u) / m_width;
item.image.v1 = float(m_v) / m_height;
item.image.u2 = float(m_u+width)/m_width;
item.image.v2 = float(m_v+std::min(m_size, height))/m_height;
item.data = userdata;
m_itemlist[index] = item;
//x方向移动坐标
m_u += width + 1;//做一个像素的间距
return index;
} //查询图块信息
item_type items(const T& index)const
{
const_iterator itr = m_itemlist.find(index);
if(itr != m_itemlist.end()){
return &itr->second;
}
else{
return null;
}
} //查询图块是否存在
bool exist(const T& index)const
{
return items(index);
} private:
void position_move(int width)
{
GLuint tex = 0;
width += 1;//做一个像素的间距
if(m_u + width > m_width){//换行
m_u = 0;
m_v += m_size + 1;
} //创建新纹理页
if(m_texlist.empty() || m_v + m_size > m_height){
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
glTexImage2D(GL_TEXTURE_2D, 0, m_format, m_width, m_height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, m_filter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_filter); m_texlist.push_back(tex);
m_u = 0;
m_v = 0;
}
} teximage* BindTexture(int index)
{
iterator itr = m_imglist.find(index);
if(itr!=m_imglist.end())
{
glBindTexture(GL_TEXTURE_2D, itr->second.image.image);
return &itr->second.image;
}
return NULL;
}
}; //---------------------------------------------------------------------------
//glfont 字体类
//
//gles对GL_ALPHA8支持貌似不好,可以替换成GL_RGBA(需要将256灰度转换成RGBA格式)
//或者使用GL_RED等单通道格式,通过shader渲染字体
// //draw_text字符串绘制参数
#define PT_LEFT 0x00000000
#define PT_RIGHT 0x00000001
#define PT_CENTER 0x00000002
#define PT_SHADOW 0x00010000
#define PT_CALCRECT 0x80000000 class glfont
{
public:
typedef imagelist<wchar_t, char_info> imagelist_type; typedef TYPENAME imagelist_type::item_type char_item; //const static int SHADOW_SIZE = 2; //阴影大小,带阴影的字体,这个实现代码太长
enum{
TEXTURE_SIZE = 1024, //默认纹理大小 TEX_FORMAT = GL_ALPHA8, //PC默认使用GL_ALPHA8纹理格式
SRC_FORMAT = GL_ALPHA, //位图数据默认格式 TAB_WIDTH = 4 //制表符宽度
}; struct PT_WORD
{
const wchar_t* begin;
const wchar_t* end;
size_t width;
}; private:
gdifont m_font; //字体类,可以替换成其他字体类
std::wstring m_name;//字体名字
int m_size; //字体大小
imagelist_type m_imagelist;//图集类 public:
vec4ub color; //字体颜色 public:
glfont() : m_font(), m_name(), m_size(), m_imagelist(), color(255, 255, 255, 255)
{ } void init(const wchar_t* fontname, int size = CGL_DEFAULT_FONT_SIZE, int texture_size = TEXTURE_SIZE)
{
m_name = fontname;
m_size = size;
//m_imagelist = imagelist;
m_font.create(fontname, size);
m_imagelist.create(texture_size, texture_size, size, TEX_FORMAT, GL_NEAREST);
} void clear()
{
m_imagelist.dispose();
} void dispose()
{
m_imagelist.dispose();
m_size = 0;
} //获得字符item
char_item char_items(wchar_t ch)
{
if(!m_imagelist.exist(ch)){
make_char(ch);
}
return m_imagelist.items(ch);
} //获得字符宽度
int char_width(wchar_t ch)
{
char_item item;
if(!m_imagelist.exist(ch)){
make_char(ch);
}
item = m_imagelist.items(ch);
return item ? item->data.next_x : 0;
} //获取字符高度
int char_height() { return m_size; } //获取字符串宽度
int text_width(const wchar_t* text, size_t length)
{
int width = 0;
for(size_t i=0; i<length; ++i){
width += char_width(text[i]);
}
return width;
} //输出一个字符
int put_char(int x, int y, wchar_t ch, int flag = 0)
{
char_item item = m_imagelist.items(ch);
if(!item){
make_char(ch);
item = m_imagelist.items(ch);
}
draw_image(item->image,
color,
x + item->data.x,
y + m_size - item->data.y,
item->image.width,
item->image.height); return item->data.next_x;
} //绘制一行字体,不支持制表符
int print(int x, int y, const wchar_t* text, size_t length)
{
if(length == TEXT_MAX)length = wcslen(text);
for(size_t i=0; i<length; ++i){
x += put_char(x, y, text[i]);
}
return 0;
} //绘制一行字体,支持制表符
int tab_print(int x, int y, const wchar_t* text, size_t length)
{
int tab = TAB_WIDTH * (this->char_height() >> 1);
if(length == TEXT_MAX)length = wcslen(text);
for(size_t i=0; i<length; ++i)
{
if(text[i] == '\t'){
x = align_next(x, tab);
}
else{
x += put_char(x, y, text[i]);
}
}
return 0;
} //仿GDI函数DrawText
int draw_text(
int left, int top, int width, int height,
const wchar_t* text,
size_t length,
int style); private:
int make_char(wchar_t ch); //根据当前位置n,计算下一个tab的对齐位置 next_tab_position
int align_next(int n, int align)
{
n = n - n % align + align;
return n;
} int get_tabled_line(const wchar_t* &l_end, const wchar_t* end, int width);
}; //缓存一个字符
int glfont::make_char(wchar_t ch)
{
char_info info; //数据行4字节对齐
glPixelStorei(GL_UNPACK_ALIGNMENT, 4); //渲染字符
m_font.render_char(ch, info); //添加到图集
return m_imagelist.insert(ch, m_font.width(), m_font.height(), GL_ALPHA, m_font.data(), info);
} //返回下一个字符的绘制位置-1表示换行
int glfont::get_tabled_line(const wchar_t* &l_end, const wchar_t* end, int width)
{
int tab = TAB_WIDTH * (this->char_height() >> 1);
int n;// = 0;
int l_width = 0; for(; l_end < end; ++l_end){
if(*l_end == '\r'){
continue;
}
else if(*l_end == '\n'){//next line
break;
}
//else if(*l_end == ' ')//add word
else if(*l_end == '\t'){
n = align_next(l_width, tab);
if(n < width){
l_width = n;
}
else{
//break;
return l_width;
}
}
else{
n = this->char_width(*l_end);
if(l_width + n < width){
l_width += n;
}
else{//next line
//break;
return l_width;
}
}
}
return l_width;
} int glfont::draw_text(int left, int top, int width, int height, const wchar_t* text, size_t length, int style)
{
int px = 0, py = top; //字符绘制位置
//int chwidth = 0; //字符宽度
int ch_size = this->char_height();
if(length == TEXT_MAX)length = wcslen(text);
int tab = TAB_WIDTH * (ch_size >> 1); //vec4ub c = dc->color; const wchar_t* end = text + length;
const wchar_t* l_begin;
const wchar_t* l_end = text;
int l_width = 0;
std::vector<PT_WORD> words; int x = 0; while(l_end < end)
{
//l_width = 0;
l_begin = l_end;
//word_begin = l_end;
//get line
l_width = get_tabled_line(l_end, end, width); px = left;
if(style & PT_RIGHT){
px += width - l_width;
}
else if(style & PT_CENTER){
px += (width - l_width) / 2;
}
if(l_begin != l_end && !(style & PT_CALCRECT)){
if(style & PT_SHADOW){
//dc->color = shadow_color;
//draw_shadow(dc, px, py, text+begin, end-begin);
}
//dc->color = c; x = 0;
for(; l_begin < l_end; ++l_begin)
{
if(*l_begin == '\t'){
x = align_next(x, tab);
continue;
}
else if(*l_begin == '\r' || *l_begin == '\n'){
continue;
}
x += put_char(px + x, py, *l_begin);
}
} if(*l_end == '\n'){//next line
++l_end;
} py += ch_size + (ch_size / 8);// 1/8 line space
if(int(top + height) < py + ch_size){
break;
}
} return py - top;
} }//end namespace cgl #endif //GLFONT_HPP_20190815000333
OpenGL字体绘制的更多相关文章
- 【AR实验室】OpenGL ES绘制相机(OpenGL ES 1.0版本)
0x00 - 前言 之前做一些移动端的AR应用以及目前看到的一些AR应用,基本上都是这样一个套路:手机背景显示现实场景,然后在该背景上进行图形学绘制.至于图形学绘制时,相机外参的解算使用的是V-SLA ...
- CSharpGL(6)在OpenGL中绘制UI元素
CSharpGL(6)在OpenGL中绘制UI元素 2016-08-13 由于CSharpGL一直在更新,现在这个教程已经不适用最新的代码了.CSharpGL源码中包含10多个独立的Demo,更适合入 ...
- 使用OpenGL ES绘制3D图形
如果应用定义的顶点不在同一个平面上,并且使用三角形把合适的顶点连接起来,就可以绘制出3D图形了. 使用OpenGL ES绘制3D图形的方法与绘制2D图形的步骤大致相同,只是绘制3D图形需要定义更多的 ...
- 【Qt for Android】OpenGL ES 绘制彩色立方体
Qt 内置对OpenGL ES的支持.选用Qt进行OpenGL ES的开发是很方便的,很多辅助类都已经具备.从Qt 5.0開始添加了一个QWindow类,该类既能够使用OpenGL绘制3D图形,也能够 ...
- OpenGL学习-------绘制简单的几何图形
本次课程所要讲的是绘制简单的几何图形,在实际绘制之前,让我们先熟悉一些概念. 一.点.直线和多边形我们知道数学(具体的说,是几何学)中有点.直线和多边形的概念,但这些概念在计算机中会有所不同.数学上的 ...
- [转]关于OpenGL的绘制上下文
[转]关于OpenGL的绘制上下文 本文转自(http://www.cnblogs.com/Liuwq/p/5444641.html) 什么是绘制上下文(Rendering Context) 初学Op ...
- tao.opengl+C#绘制三维模型
一.tao.Opengl技术简介 Opengl是一种C风格的图形库,即opengl中没有类和对象,只有大量的函数.Opengl在内部就是一个状态机,利用不同的函数来修改opengl状态机的状态,以达到 ...
- 关于OpenGL的绘制上下文
什么是绘制上下文(Rendering Context) 初学OpenGL,打开红宝书,会告诉你OpenGL是个状态机,OpenGL采用了客户端-服务器模式,那时觉得好抽象,直到后来了解了绘制上下文才把 ...
- 2.x最终照着教程,成功使用OpenGL ES 绘制纹理贴图,添加了灰度图
在之前成功绘制变色的几何图形之后,今天利用Openg ES的可编程管线绘制出第一张纹理. 学校时候不知道OpenGL的重要性,怕晦涩的语法.没有跟老师学习OpenGL的环境配置,现在仅仅能利用coco ...
随机推荐
- IDEA mapping箭头要怎么样设置哈(Free MyBatis插件)
效果如下图: 当我们点击箭头的时候,会快速切换到我们相关联的类位置,就不用再像以前一样还要去找 而 Free MyBatis是一款让我们操作更加方便的插件,你值得拥有哦~~~ idea 选择 File ...
- 实战build-react(二)-------引入Ant Design(增加)
https://blog.csdn.net/zhan_lijian/article/details/85271906(copy) 1.肯定参考facebook关于react官网咯 快速搭建 creat ...
- 论文阅读:Elastic Scaling of Stateful Network Functions
摘要: 弹性伸缩是NFV的核心承诺,但在实际应用中却很难实现.出现这种困难的原因是大多数网络函数(NFS)是有状态的,并且这种状态需要在NF实例之间共享.在满足NFS上的吞吐量和延迟要求的同时实现状态 ...
- 2019.9.23JAVA课堂测试
1.题目 使用递归方式判断某个字串是否是回文( palindrome ) “回文”是指正着读.反着读都一样的句子.比如“我是谁是我”使用递归算法检测回文的算法描述如下:A single or zero ...
- java开发需掌握技能1
1.熟练掌握Java基础.语法规范.集合框架等,基础语法.Java关键字.内部类.泛型.集合类使用场景2.Java io/nio框架体系.文本文件.二进制文件读写.nio.buffer机制3.Jsp. ...
- [BZOJ1697][USACO2007 FEB]Cow Sorting牛排序:贪心+置换
分析 一个月前做的一道题补一下题解,就简单写一写吧. 单独考虑每一个循环节,如果只进行内部的调整,最优方案显然是把最小的绕这个循环交换一圈. 但是借助全局最小值可能使答案更优,两种情况取个\(\max ...
- Java 生成二进制加减法题目
日常算数,有益身心健康. int a; int b; int result; int symbol; int count = 50; Random random = new Random(); for ...
- [CSP-S模拟测试]:最小距离(最短路)
题目传送门(内部题97) 输入格式 第一行三个整数$n,m,p$,第二行$p$个整数$x_1\sim x_p$表示特殊点的编号.接下来$m$行每行三个整数$u,v,w$表示一条连接$u$和$v$,长度 ...
- leetcode-mid-Linked list- 200. Number of Islands¶
mycode 57.92% class Solution(object): def numIslands(self, grid): """ :type grid: Li ...
- mysql命令使用3
算术运算函数 sum()求和 mysql> select sum(price) from books;+------------+| sum(price) |+------------+| 10 ...