OpenGL中的3D文字绘制
来源:互联网 发布:商务双肩包 知乎 编辑:程序博客网 时间:2024/05/21 17:25
转自http://blog.csdn.net/augusdi/article/details/20572533
代码如下:
/*****************************************新添加的代码*****************************************/ #include <Windows.h> #include <stdio.h> //标准输入/输出库的头文件 #include <math.h> //数学库 #include <stdarg.h> //用来定义可变参数的头文件 /**********************************************************************************************/ #include <GL/glut.h> //包含OpenGL实用库 #pragma comment(lib,"glut32.lib") HDC hDC = NULL; //窗口着色描述表句柄 HWND hWnd = NULL; //保存窗口句柄 HGLRC hGLRC = NULL; //OpenGL渲染描述表句柄 HINSTANCE hInstance; //保存程序的实例 BOOL keys[256]; //保存键盘按键的数组 BOOL active = TRUE; //窗口的活动标志, 缺省为TRUE BOOL fullscreen = TRUE; //全屏标志, 缺省为全屏模式 UINT winWidth = 640, //窗体宽度 winHeight = 480, //窗体高度 winBits = 16; //颜色深度(可选8/16/32) /*****************************************新添加的代码*****************************************/ GLuint base; //绘制字体的显示列表的开始位置 GLYPHMETRICSFLOAT gmf[256]; //保存256个轮廓字体显示列表中对应的每一个列表的位置和方向的信息 void BuildFont() { HFONT font, oldfont; //字体句柄, 旧的字体句柄 base = glGenLists(256); //创建256个显示列表 font = CreateFont( //创建字体 -24, //字体高度(告诉Windows寻找基于CHARACTER高度的字体.如果是正数, 就寻找基于CELL的高度相匹配的字体) 0, //字体宽度(使用默认值) 0, //字体的旋转角度Angle Of Escapement 0, //字体底线的旋转角度Orientation Angle FW_BOLD, //字体的重量(0-1000)[FW_DONTCARE是0, FW_NORMAL是400, FW_BOLD是700, FW_BLACK是900] FALSE, //是否使用斜体 FALSE, //是否使用下划线 FALSE, //是否使用删除线 ANSI_CHARSET, //设置字符集 OUT_TT_PRECIS, //输出精度 CLIP_DEFAULT_PRECIS, //裁剪精度 ANTIALIASED_QUALITY, //输出质量 DEFAULT_PITCH | FF_DONTCARE, //Pitch And Family "Times New Roman" //字体名称 ); oldfont = (HFONT)SelectObject(hDC, font); //选择需要的字体 wglUseFontOutlines( //使用Windows的wgl函数来创建字体 hDC, //设置当前窗口设备描述表的句柄 0, //用于创建显示列表字体的第1个字符的ASCII值 255, //字符数 base, //第1个显示列表的名称 0.0f, //字体的光滑度, 越小越光滑, 0.0为最光滑的状态 0.2f, //在Z方向突出的距离(即轮廓字体的厚度) WGL_FONT_POLYGONS, //使用多边形来生成字符, 每个顶点具有独立的法线(WGL_FONT_LINES:使用线形生成字符) gmf //一个接收字形度量数据的数组的地址, 每个数组元素用它对应的显示列表字符的数据填充 ); SelectObject(hDC, oldfont); //选择原来的字体 DeleteObject(font); //删除字体 } void glPrintf(const char *fmt, ...) { if(!fmt) return; //如果无输入则返回 char text[256]; //保存文字串 va_list ap; //指向一个变量列表的指针 va_start(ap, fmt); //分析可变参数 vsprintf(text, fmt, ap); //把参数值写入字符串 va_end(ap); //结束分析 /////////////////////将字符串居中///////////////////// float length = 0.0f; //保存字符串的长度 for(UINT i=0;i<strlen(text);i++){ //查找整个字符串的长度 length += gmf[text[i]].gmfCellIncX; //计算轮廓后字符串的宽度(gmfCellIncX表示显示位置从已绘制上的上一个字符向右移动的真正距离) } glTranslatef(-length/2.0f, 0.0f, 0.0f); //把字符串置于最左边 ////////////////////////////////////////////////////// glPushAttrib(GL_LIST_BIT); //把显示列表属性压入属性堆栈 glListBase(base); //设置显示列表的基础值为0 glCallLists(strlen(text), GL_UNSIGNED_BYTE, text); //调用显示列表绘制字符串 glPopAttrib(); //弹出属性堆栈 } void KillFont() //删除显示列表 { glDeleteLists(base, 256); //删除256个显示列表 } /**********************************************************************************************/ //重置OpenGL窗口大小 GLvoid ReSizeGLScene(UINT width, UINT height) { if(height <= 0){ height = 1; } //防止被零除且防止负数存在 glViewport(0, 0, (GLsizei)width, (GLsizei)height); //重置当前的视口 glMatrixMode(GL_PROJECTION); //选择投影矩阵 glLoadIdentity(); //重置投影矩阵 gluPerspective(45.0f, (GLdouble)width / (GLdouble)height, 0.1f, 100.0f); //设置视口的大小 glMatrixMode(GL_MODELVIEW); //选择模型观察矩阵 glLoadIdentity(); //重置模型观察矩阵 } //对OpenGL窗口进行初始化设置 BOOL InitGL(GLvoid) { glShadeModel(GL_SMOOTH); //启用阴影平滑 glClearColor(0.0f, 0.0f, 0.0f, 0.5f); //黑色背景 glClearDepth(1.0f); //设置深度缓存 glEnable(GL_DEPTH_TEST); //启用深度测试 glDepthFunc(GL_LEQUAL); //所作深度测试的类型 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); //告诉系统对透视进行修正 /*****************************************新添加的代码*****************************************/ BuildFont(); //创建字体 /**********************************************************************************************/ return TRUE; //初始化成功 } //从这里开始进行所有的绘制 BOOL DrawGLScene(GLvoid) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //清除屏幕和深度缓存 glLoadIdentity(); //重置当前的模型观察矩阵 /*****************************************新添加的代码*****************************************/ static GLfloat rot = 0.0f; //旋转变量 glTranslatef(0.0f, 0.0f, -15.0f); //移入屏幕15个单位 glRotatef(rot, 1.0f, 0.0f, 0.0f); //沿X轴旋转 glRotated(rot * 1.5f, 0.0f, 1.0f, 0.0f); //沿Y轴旋转 glRotatef(rot * 1.4f, 0.0f, 0.0f, 1.0f); //沿Z轴旋转 /////////////////根据字体位置设置颜色///////////////// float r = 1.0f * float(cos(rot / 20.0f)), //红色 g = 1.0f * float(sin(rot / 25.0f)), //绿色 b = 1.0f - 0.5f * float(cos(rot / 17.0f)); //蓝色 glColor3f(r, g, b); //设置颜色 ////////////////////////////////////////////////////// glPrintf("3D Active OpenGL Text - %3.2f", rot / 50); //输出文字到屏幕 rot += 0.5f; //增加旋转变量 /**********************************************************************************************/ return TRUE; //绘制场景成功 } //销毁窗口 GLvoid KillGLWindow(GLvoid) { if(fullscreen) //是否处于全屏模式 { ChangeDisplaySettings(NULL, 0); //切换回桌面 ShowCursor(TRUE); //显示鼠标指针 } if(hGLRC) { //是否拥有OpenGL描述表 if(!wglMakeCurrent(NULL, NULL)) { //是否已释放DC和RC描述表 MessageBox(NULL, "释放DC或RC失败!", "错误", MB_OK | MB_ICONEXCLAMATION); } if(!wglDeleteContext(hGLRC)) { //是否已删除RC MessageBox(NULL, "释放RC失败!", "错误", MB_OK | MB_ICONEXCLAMATION); } hGLRC = NULL; //将RC设为NULL } if(hDC && !ReleaseDC(hWnd, hDC)) { //是否已释放DC MessageBox(NULL, "释放DC失败!", "错误", MB_OK | MB_ICONEXCLAMATION); hDC = NULL; //将DC设为NULL } if(hWnd && !DestroyWindow(hWnd)) { //是否已销毁窗口 MessageBox(NULL, "销毁窗口失败!", "错误", MB_OK | MB_ICONEXCLAMATION); hWnd = NULL; //将hWnd设为NULL } if(!UnregisterClass("OpenGL", hInstance)) { //是否已注销类 MessageBox(NULL, "注销窗口类失败!", "错误", MB_OK | MB_ICONEXCLAMATION); hInstance = NULL; //将hInstance设为NULL } /*****************************************新添加的代码*****************************************/ KillFont(); //删除字体 /**********************************************************************************************/ } LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam){ //WndProc(窗口的句柄, 窗口的消息, 附加的消息内容, 附加的消息内容) switch(uMsg) { //检查Windows消息 case WM_ACTIVATE: //监视窗口激活消息 if(!HIWORD(wParam)) { //检查最小化状态 active = TRUE; //程序处于激活状态 } else { active = FALSE; //程序不再激活 } return 0; //返回消息循环 case WM_CLOSE: //收到Close消息 PostQuitMessage(0); //发出退出消息 return 0; //返回 case WM_KEYDOWN: //有键被按下 keys[wParam] = TRUE; //设为TRUE return 0; //返回 case WM_KEYUP: //有键被放开 keys[wParam] = FALSE; //设为FALSE return 0; //返回 case WM_SIZE: //调整OpenGL窗口大小 ReSizeGLScene(LOWORD(lParam), HIWORD(lParam)); //LoWord=Width, HiWord=Height return 0; //返回 case WM_SYSCOMMAND: //系统中断命令 switch(wParam) { //检查系统调用 case SC_SCREENSAVE: //运行屏保 case SC_MONITORPOWER: //显示器要进入节电模式 return 0; //阻止发生 } break; //退出 } return DefWindowProc(hWnd, uMsg, wParam, lParam); } BOOL CreateGLWindow(const char *title, UINT width, UINT height, UINT bits, BOOL fullscreenflag) { //CreateGLWindow(标题, 宽度, 高度, 颜色的位深, 是否使用全屏模式) GLuint PixelFormat; //保存查找匹配的结果 DWORD dwStyle, dwExStyle; //窗口风格, 扩展窗口风格 RECT WindowRect; //取得矩形的左上角和右下角的坐标值 WNDCLASS wc; //窗口类结构 hInstance = GetModuleHandle(NULL); //取得我们窗口的实例 fullscreen = fullscreenflag; //设置全局全屏标志 WindowRect.top = (long)0; //将Top 设为 0 WindowRect.left = (long)0; //将Left 设为 0 WindowRect.right = (long)width; //将Right 设为要求的宽度 WindowRect.bottom = (long)height; //将Bottom 设为要求的高度 /* 像素格式明确了OpenGL绘制平面的特性, 如象素缓冲区是单缓冲还是双缓冲, 数据是 RGBA方式还是Color Index方式等.每个OpenGL显示设 备一般用名为PIXELFORMATDESCRIPTOR的结构来表示某个的像素格式, 这个结构包含26个属性信息.Win32定义PIXELFORMATDESCRIPTOR如下所示: typedef struct tagPIXELFORMATDESCRIPTOR { //pfd WORD nSize; //是象素格式描述子结构的大小, sizeof(PIXELFORMATDESCRIPTOR)设定其值 WORD nVersion; //是PIXELFORMATDESCRIPTOR结构的版本, 一般设为1 DWORD dwFlags; //是一组表明象素缓冲特性的标志位, 如缓冲是否支持GDI或OpenGL等 BYTE iPixelType; //说明象素数据类型是RGBA还是颜色索引 BYTE cColorBits; //每个颜色缓冲区中颜色位平面的数目, 对颜色索引方式是缓冲区大小 BYTE cRedBits; //每个RGBA颜色缓冲区中红色位平面的数目 BYTE cRedShift; //每个RGBA颜色缓冲区中红色位平面的偏移数 BYTE cGreenBits; //每个RGBA颜色缓冲区中绿色位平面的数目 BYTE cGreenShift; //每个RGBA颜色缓冲区中绿色位平面的偏移数 BYTE cBlueBits; //每个RGBA颜色缓冲区中蓝色位平面的数目 BYTE cBlueShift; //每个RGBA颜色缓冲区中蓝色位平面的偏移数 BYTE cAlphaBits; //每个RGBA颜色缓冲区中alpha位平面的数目(保留的, 现不支持) BYTE cAlphaShift; //每个RGBA颜色缓冲区中alpha位平面的偏移数(保留的, 现不支持) BYTE cAccumBits; //累加缓冲区中全部位平面的数目 BYTE cAccumRedBits; //累加缓冲区中红色位平面的数目 BYTE cAccumGreenBits; //累加缓冲区中绿色位平面的数目 BYTE cAccumBlueBits; //累加缓冲区中蓝色位平面的数目 BYTE cAccumAlphaBits; //累加缓冲区中alpha位平面的数目 BYTE cDepthBits; //Z(深度)缓冲区的深度 BYTE cStencilBits; //模板缓冲区的深度 BYTE cAuxBuffers; //轴向缓冲区的数量(一般1.0版本不支持) BYTE iLayerType; //被忽略, 为了一致性而包含的 BYTE bReserved; //表层和底层平面的数量::位0-3表最多15层表层平面, 位4-7表底层 DWORD dwLayerMask; //被忽略, 为了一致性而包含的 DWORD dwVisibleMask; //是透明色彩的值(RGBA方式)或是一个底层平面的索引(Index) DWORD dwDamageMask; //被忽略, 为了一致性而包含的 } PIXELFORMATDESCRIPTOR; */ const PIXELFORMATDESCRIPTOR pfd = //pfd告诉窗口使用的像素格式 { sizeof(PIXELFORMATDESCRIPTOR), //上述格式描述符的大小 1, //版本号 PFD_DOUBLEBUFFER | PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL, //格式支持双缓冲, 支持窗口, 支持OpenGL PFD_TYPE_RGBA, //申请RGBA格式 bits, //选定色彩深度 0, 0, 0, 0, 0, 0, 0, 0, //忽略的色彩位(前6位), 无Alpha缓存(第7位), 忽略Shift Bit(第8位) 0, //无累加缓存 0, 0, 0, 0, //忽略聚集位 16, //16位Z-缓存(深度缓存) 0, //无蒙板缓存 0, //无辅助缓存 PFD_MAIN_PLANE, //主绘图层 0, //不使用重叠层 0, 0, 0 //忽略层遮罩 }; wc.cbClsExtra = 0; //无额外窗口数据 wc.cbWndExtra = 0; //无额外窗口数据 wc.hbrBackground = NULL; //GL不需要背景 wc.hCursor = LoadCursor(NULL, IDC_ARROW); //装入鼠标指针 wc.hIcon = LoadIcon(NULL, IDI_WINLOGO); //装入缺省图标 wc.hInstance = hInstance; //设置实例 wc.lpfnWndProc = (WNDPROC)WndProc; //WndProc处理消息 wc.lpszClassName = "OpenGL"; //设定类名字 wc.lpszMenuName = NULL; //不需要菜单 wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; //移动时重画, 并为窗口取得DC if(!RegisterClass(&wc)) { //尝试注册窗口类 MessageBox(NULL, "注册窗口类错误!", "错误", MB_OK | MB_ICONEXCLAMATION); return FALSE; //退出并返回FALSE } if(fullscreen) { //尝试全屏模式 DEVMODE dmScreenSettings; //设备模式 memset(&dmScreenSettings, 0, sizeof(dmScreenSettings)); //确保内存清空为零 dmScreenSettings.dmSize = sizeof(dmScreenSettings); //DEVMODE结构的大小 dmScreenSettings.dmBitsPerPel = bits; //每象素所选的色彩深度 dmScreenSettings.dmPelsWidth = width; //所选屏幕宽度 dmScreenSettings.dmPelsHeight = height; //所选屏幕高度 dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; //尝试设置显示模式并返回结果(注:CDS_FULLSCREEN 移去了状态条) if(ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) { if(MessageBox(NULL, "全屏模式失败!是否使用窗口模式?", "错误", MB_YESNO | MB_ICONQUESTION) == IDYES) { fullscreen = FALSE; //选择窗口模式 } else { MessageBox(NULL, "程序退出!", "错误", MB_OK | MB_ICONSTOP); return FALSE; //退出并返回FALSE } } } if(fullscreen) { //仍处于全屏模式 dwStyle = WS_POPUP; //窗体风格 dwExStyle = WS_EX_APPWINDOW; //扩展窗体风格 ShowCursor(FALSE); //隐藏鼠标指针 } else { dwStyle = WS_OVERLAPPEDWINDOW; //窗体风格 dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; //扩展窗体风格 } AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle); //调整窗口达到真正要求的大小 if(!(hWnd = CreateWindowEx(dwExStyle, //扩展窗体风格 "OpenGL", //类名字 title, //窗口标题 dwStyle | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, //必须的窗体风格属性 0, 0, //窗口左上角X坐标和Y坐标位置 WindowRect.right - WindowRect.left, //计算调整好的窗口高度的宽度 WindowRect.bottom - WindowRect.top, //计算调整好的窗口高度的高度 NULL, //无父窗口 NULL, //无菜单 hInstance, //实例 NULL))){ //不向WM_CREATE传递任何信息 KillGLWindow(); //重置显示区 MessageBox(NULL, "窗口创建失败!", "错误", MB_OK | MB_ICONEXCLAMATION); return FALSE; //窗口创建失败 } if(!(hDC = GetDC(hWnd))) { //是否取得设备描述表 KillGLWindow(); //重置显示区 MessageBox(NULL, "创建设备描述表失败!", "错误", MB_OK | MB_ICONEXCLAMATION); return FALSE; //创建设备描述表失败 } if(!(PixelFormat = ChoosePixelFormat(hDC, &pfd))) { //是否Windows找到相应的象素格式 KillGLWindow(); //重置显示区 MessageBox(NULL, "没有相匹配的像素格式!", "错误", MB_OK | MB_ICONEXCLAMATION); return FALSE; //没有相匹配的像素格式 } if(!SetPixelFormat(hDC, PixelFormat, &pfd)) { //是否能设置象素格式 KillGLWindow(); //重置显示区 MessageBox(NULL, "设置像素格式失败!", "错误", MB_OK | MB_ICONEXCLAMATION); return FALSE; //设置像素格式失败 } if(!(hGLRC = wglCreateContext(hDC))) { //是否能取得OpenGL渲染描述表 KillGLWindow(); //重置显示区 MessageBox(NULL, "创建OpenGL渲染表失败!", "错误", MB_OK | MB_ICONEXCLAMATION); return FALSE; //创建OpenGL渲染表失败 } if(!wglMakeCurrent(hDC, hGLRC)) { //尝试激活着色描述表 KillGLWindow(); //重置显示区 MessageBox(NULL, "激活当前OpenGL渲染表失败!", "错误", MB_OK | MB_ICONEXCLAMATION); return FALSE; //激活当前OpenGL渲染表失败 } ShowWindow(hWnd, SW_SHOW); //显示窗口 SetForegroundWindow(hWnd); //略略提高优先级 SetFocus(hWnd); //设置键盘的焦点至此窗口 ReSizeGLScene(width, height); //设置透视GL屏幕 if(!InitGL()) { //初始化新建的GL窗口 KillGLWindow(); MessageBox(NULL, "初始化失败!", "错误", MB_OK | MB_ICONEXCLAMATION); return FALSE; //初始化失败 } return TRUE; //创建窗口成功 } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) { //WinMain(当前窗口实例, 前一个窗口实例, 命令行参数, 窗口显示状态) MSG msg; //Windowsx消息结构 BOOL done = FALSE; //用来退出循环的BOOL变量 winWidth = 640; //定义窗口宽度 winHeight = 480; //定义窗口高度 winBits = 16; //定颜色深度为 //提示用户选择运行模式 if(MessageBox(NULL, "是否使用全屏模式?", "OpenGL", MB_YESNO | MB_ICONQUESTION) == IDNO) { fullscreen = FALSE; //FALSE为窗口模式 } //创建OpenGL窗口 if(!CreateGLWindow("OpenGL", winWidth, winHeight, winBits, fullscreen)) { return 0; //失败退出 } while(!done) { //保持循环直到done=TRUE if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { //是否在等待消息 if(msg.message == WM_QUIT) { //收到退出消息 done = TRUE; //是, 则done=TRUE } else { //不是, 处理窗口消息 TranslateMessage(&msg); //翻译消息 DispatchMessage(&msg); //发送消息 } } else { //如果没有消息 //绘制场景。监视ESC键和来自DrawGLScene()的退出消息 if(active) { //程序是否激活 if(keys[VK_ESCAPE]) { //是否ESC按下 done = TRUE; //ESC发出退出信号 } else { //不是退出的时候, 刷新屏幕 DrawGLScene(); //绘制场景 SwapBuffers(hDC); //交换缓存(双缓存) } } if(keys[VK_F1]) { //是否按下F1键 keys[VK_F1] = FALSE; //若是, 使对应的Key数组中的值为FALSE KillGLWindow(); //销毁当前的窗口 //切换全屏/窗口模式 if(!CreateGLWindow("OpenGL", winWidth, winHeight, winBits, !fullscreen)) { //重建OpenGL窗口 return 0; //如果窗口未能创建, 程序退出 } } } } //关闭程序 KillGLWindow(); //销毁窗口 return msg.wParam; //退出程序 }
(暂时只支持英文)
0 0
- OpenGL中的3D文字绘制
- OpenGL ES绘制3D
- opengl绘制3D图形
- OPENGL绘制文字
- OpenGL文字绘制
- OpenGL ES绘制3D图形
- OpenGL ES绘制3D图形
- OpenGL ES绘制3D图形
- OpenGL ES绘制3D图形
- OpenGL ES绘制3D图形
- OpenGL ES绘制3D图形
- OpenGL ES 绘制 3D 图形
- OpenGL ES绘制3D图形
- OpenGL ES 绘制 3D 图形
- Android OpenGL ES 3D图形绘制
- OpenGL 3D图形常用绘制函数
- 使用OpenGL ES绘制3D图形
- 图解opengl 3D 图形绘制实例
- Head first PHP&MySQL 学习笔记(一)
- HTML4和HTML5差距
- SMS短信的PDU编码规则
- ubuntu下Android Studio 提交代码至Github
- Spark Streaming实时读取Kafka
- OpenGL中的3D文字绘制
- NSURLSession和NSURLConnection
- Flask Web 开发 用户资料
- 在限定期限内索取一套专属于您的免费Delphi 10.1 Berlin Starter版本软件开发工具
- Linux-- 安装软件(centos下)
- Spring AOP + Redis缓存数据库查询
- MySQL:讨人喜欢的 MySQL replace into 用法(insert into 的增强版)
- Service学习之路(02)之Service启动和停止Service
- android 编译类型