- 浏览: 40457 次
- 性别:
- 来自: 大连
最新评论
初识标签云是在去年年末,一看到这个应用我就特别感兴趣。还记得08年在北京做Mobile应用的时候就在想,是不是可以通过某种方式做界面扩展,让相对狭小的手机屏幕只显示有效部分,而扩展部分可以在屏幕以外,通过某种方式将他们调到屏幕以内。后来证实做这种思考的人不只是我自己,因为现在划屏应用已经是移动终端的基本应用模式了。当时也想过能不能在纵向做界面延伸,让界面深入到屏幕里面,要知道那可是无限的空间,不过没有想到什么好的方式。见到标签云的那一刻,我知道这就是我想要的,所以当时我就决定用OpenGL模拟一下,然后拿出来和大家共同探讨,看看有没有可能做成一个更成熟些应用。不过过年回来工作比较忙,所以也就搁置了。这两天刚阶段性的完成一个项目,所以得了空可以写这篇博客。
要实现功能就要先分析原理,通过使用和观察我觉得标签云的每一个标签都分布在一个球体上,球在视平面上的投影是一个圆,而整个球就根据鼠标和这个投影圆的位置关系不同而旋转。鼠标离圆心越远转速愉快,反之则越慢。球体旋转是围绕一根通过球心且与视平面平行的转轴进行的,鼠标和投影圆圆心的位置关系同样控制者转轴的方向,那就是转轴垂直于投影圆圆心和鼠标的连线。最后一点,旋转过程总是迎着鼠标进行。
知道了基本原理就要开始分析算法了,实现三维空间用OpenGL这自不必说,我曾经写过一篇日志《OpenGL控件》介绍了一个内置OpenGL基本框架环境的自定义控件,这次就是极基于这个控件的一个扩展应用。我还曾经在《三维向量类》一文中介绍过我自己写的一个进行三维程序设计时很实用的向量类CVector,当然这次建模还是要依靠它。唯一的问题是OpenGL对于中文支持的不好,有没有什么方法可以方便的显示中文呢?我这里采用的方法是在内存中生成一张文字的贴图,然后用Alpha混合的方式赋予一个plan,这样就可以利用系统字库在OpenGL中显示各种类型丰富的文字了。好了,主要问题都解决了,开始写代码。
首先定义一个结构体来代表标签元中的一个标签:
这个函数是生成标签的核心函数,在程序里标签表现出来的形式就是文本,所以函数支持对文本的几乎一切定制,这包括内容、颜色、字体、字号、样式等。函数首先会创建一个字体,然后根据文本内容需要的大小创建一个内存位图,将文字绘制于这个位图之上。准备好文字的位图就要通过它来制作材质了,这里有一个问题,位图是没有Alpha通道的,怎么办呢,有没有什么相对简单的方法处理呢?这里我的处理方法是这样的,看代码,通过GetBitmap获取位图信息然后观察bmData.bmWidth和bmData.bmWidthBytes的值,可以发现bmWidthBytes是bmWidth的四倍。原来位图在内存里是以RGBA的方式存储的,所以通过GetBitmapBits获取到的数据就是4位的。众所周知,内存位图创建时是黑色的,这里我认定标签文字不能为黑色,所以检测数据如果是黑色的就把Alpha设为透明,不是就设为不透明,然后创建贴图。最后设置向量,在一个范围内随机生成一个长度做一个指向屏幕外的向量,在以x、y、z三个轴随机旋转一个角度,这样就完成了一个标签的建模。
渲染的部分很简单,就是常规的OpenGL绘制,只不过加上了材质设置了Alpha透明。其实这个Demo做的比较粗糙,文字周围存在黑边,不过做这个例子不是特别追求表现所以也就没有特别处理,代码如下:
CWnd::OnTimer(nIDEvent);
} 到此基本的功能就已经全部实现了,在我的资源里上传了这个Demo有兴趣朋友可以下载研究一下,有什么好的想法可以和我进一步交流。做这个东西,写这篇文章权当抛砖引玉,希望能给大家些灵感,从三维的角度作出有更好用户体验的界面设计。最后贴一个效果图,见笑见笑。
[img][/img]
转(http://blog.csdn.net/xianglitian/article/details/6590687)
要实现功能就要先分析原理,通过使用和观察我觉得标签云的每一个标签都分布在一个球体上,球在视平面上的投影是一个圆,而整个球就根据鼠标和这个投影圆的位置关系不同而旋转。鼠标离圆心越远转速愉快,反之则越慢。球体旋转是围绕一根通过球心且与视平面平行的转轴进行的,鼠标和投影圆圆心的位置关系同样控制者转轴的方向,那就是转轴垂直于投影圆圆心和鼠标的连线。最后一点,旋转过程总是迎着鼠标进行。
知道了基本原理就要开始分析算法了,实现三维空间用OpenGL这自不必说,我曾经写过一篇日志《OpenGL控件》介绍了一个内置OpenGL基本框架环境的自定义控件,这次就是极基于这个控件的一个扩展应用。我还曾经在《三维向量类》一文中介绍过我自己写的一个进行三维程序设计时很实用的向量类CVector,当然这次建模还是要依靠它。唯一的问题是OpenGL对于中文支持的不好,有没有什么方法可以方便的显示中文呢?我这里采用的方法是在内存中生成一张文字的贴图,然后用Alpha混合的方式赋予一个plan,这样就可以利用系统字库在OpenGL中显示各种类型丰富的文字了。好了,主要问题都解决了,开始写代码。
首先定义一个结构体来代表标签元中的一个标签:
typedef struct tagTAGNODE { CVector m_vtrPos; // 标签位置 float m_fWidth, // 标签长 m_fHeight; // 标签宽 UINT m_uTexture; // 贴图号 }CloudTag, *lpCloudTag;然后在COpenGLCtrl里维护一个CloudTag数组用来管理所有标签,也就是整个云。函数AddCloud用来添加一个标签,其代码如下:
view plaincopyprint?void COpenGLCtrl::AddCloud(CString strName, COLORREF clrText, CString strFontName, int nPointSize, int nWeight, UINT uCharset) { int nMode; CSize sizeText; CRect rectTag; CBitmap bitmapTemp, *pOldBitmap; CFont fontTag, *pOldFont; COLORREF clrOld; LOGFONT lf; CDC* pDC = GetDC(); CDC* pMemDC = new CDC; lpCloudTag pCloudTag = new CloudTag; int nExtend = 5; float fTemp; //设置字体 memset(&lf, 0, sizeof(LOGFONT)); //设置字体样式 wcscpy_s(lf.lfFaceName, strFontName); lf.lfHeight = nPointSize; lf.lfWeight = nWeight; lf.lfCharSet = uCharset; fontTag.CreateFontIndirect(&lf); //创建位图内存 pMemDC->CreateCompatibleDC(pDC); pOldFont = pMemDC->SelectObject(&fontTag); nMode = pMemDC->SetBkMode(TRANSPARENT); clrOld = pMemDC->SetTextColor(clrText); sizeText = pMemDC->GetTextExtent(strName, strName.GetLength()); pCloudTag->m_fWidth = float(sizeText.cx+nExtend)/40; pCloudTag->m_fHeight = float(sizeText.cy+nExtend)/40; rectTag.SetRect(0, 0, sizeText.cx+nExtend, sizeText.cy+nExtend); bitmapTemp.CreateCompatibleBitmap(pDC, rectTag.Width(), rectTag.Height()); pOldBitmap = pMemDC->SelectObject(&bitmapTemp); //填充客户区 pMemDC->DrawText(strName, strName.GetLength(), rectTag, DT_SINGLELINE|DT_CENTER|DT_VCENTER); pMemDC->SetBkMode(nMode); pMemDC->SelectObject(pOldFont); pMemDC->SelectObject(pOldBitmap); pMemDC->SetTextColor(clrOld); delete pMemDC; BITMAP bmData; bitmapTemp.GetBitmap(&bmData); unsigned char* pData = new unsigned char[bmData.bmWidthBytes*bmData.bmHeight]; bitmapTemp.GetBitmapBits(bmData.bmWidthBytes*bmData.bmHeight, pData); for(int i=0; i<bmData.bmWidth; i++) { for(int j=0; j<bmData.bmHeight; j++) { if(pData[i*4+j*bmData.bmWidthBytes]!=0 || pData[i*4+j*bmData.bmWidthBytes+1]!=0 || pData[i*4+j*bmData.bmWidthBytes+2]!=0) pData[i*4+j*bmData.bmWidthBytes+3]=255; } } glGenTextures(1, &pCloudTag->m_uTexture); glBindTexture(GL_TEXTURE_2D, pCloudTag->m_uTexture); gluBuild2DMipmaps(GL_TEXTURE_2D, 4, bmData.bmWidth, bmData.bmHeight, GL_RGBA, GL_UNSIGNED_BYTE, pData); delete pData; fTemp = (rand()%50)/10.0f+3; pCloudTag->m_vtrPos = CVector(0, 0, fTemp); fTemp = (rand()%360-180)/360.0f; pCloudTag->m_vtrPos.Rotate(fTemp, CVector(1, 0, 0)); fTemp = (rand()%360-180)/360.0f; pCloudTag->m_vtrPos.Rotate(fTemp, CVector(0, 1, 0)); fTemp = (rand()%360-180)/360.0f; pCloudTag->m_vtrPos.Rotate(fTemp, CVector(0, 0, 1)); m_tcDemo.Add(pCloudTag); } void COpenGLCtrl::AddCloud(CString strName, COLORREF clrText, CString strFontName, int nPointSize, int nWeight, UINT uCharset) { int nMode; CSize sizeText; CRect rectTag; CBitmap bitmapTemp, *pOldBitmap; CFont fontTag, *pOldFont; COLORREF clrOld; LOGFONT lf; CDC* pDC = GetDC(); CDC* pMemDC = new CDC; lpCloudTag pCloudTag = new CloudTag; int nExtend = 5; float fTemp; //设置字体 memset(&lf, 0, sizeof(LOGFONT)); //设置字体样式 wcscpy_s(lf.lfFaceName, strFontName); lf.lfHeight = nPointSize; lf.lfWeight = nWeight; lf.lfCharSet = uCharset; fontTag.CreateFontIndirect(&lf); //创建位图内存 pMemDC->CreateCompatibleDC(pDC); pOldFont = pMemDC->SelectObject(&fontTag); nMode = pMemDC->SetBkMode(TRANSPARENT); clrOld = pMemDC->SetTextColor(clrText); sizeText = pMemDC->GetTextExtent(strName, strName.GetLength()); pCloudTag->m_fWidth = float(sizeText.cx+nExtend)/40; pCloudTag->m_fHeight = float(sizeText.cy+nExtend)/40; rectTag.SetRect(0, 0, sizeText.cx+nExtend, sizeText.cy+nExtend); bitmapTemp.CreateCompatibleBitmap(pDC, rectTag.Width(), rectTag.Height()); pOldBitmap = pMemDC->SelectObject(&bitmapTemp); //填充客户区 pMemDC->DrawText(strName, strName.GetLength(), rectTag, DT_SINGLELINE|DT_CENTER|DT_VCENTER); pMemDC->SetBkMode(nMode); pMemDC->SelectObject(pOldFont); pMemDC->SelectObject(pOldBitmap); pMemDC->SetTextColor(clrOld); delete pMemDC; BITMAP bmData; bitmapTemp.GetBitmap(&bmData); unsigned char* pData = new unsigned char[bmData.bmWidthBytes*bmData.bmHeight]; bitmapTemp.GetBitmapBits(bmData.bmWidthBytes*bmData.bmHeight, pData); for(int i=0; i<bmData.bmWidth; i++) { for(int j=0; j<bmData.bmHeight; j++) { if(pData[i*4+j*bmData.bmWidthBytes]!=0 || pData[i*4+j*bmData.bmWidthBytes+1]!=0 || pData[i*4+j*bmData.bmWidthBytes+2]!=0) pData[i*4+j*bmData.bmWidthBytes+3]=255; } } glGenTextures(1, &pCloudTag->m_uTexture); glBindTexture(GL_TEXTURE_2D, pCloudTag->m_uTexture); gluBuild2DMipmaps(GL_TEXTURE_2D, 4, bmData.bmWidth, bmData.bmHeight, GL_RGBA, GL_UNSIGNED_BYTE, pData); delete pData; fTemp = (rand()%50)/10.0f+3; pCloudTag->m_vtrPos = CVector(0, 0, fTemp); fTemp = (rand()%360-180)/360.0f; pCloudTag->m_vtrPos.Rotate(fTemp, CVector(1, 0, 0)); fTemp = (rand()%360-180)/360.0f; pCloudTag->m_vtrPos.Rotate(fTemp, CVector(0, 1, 0)); fTemp = (rand()%360-180)/360.0f; pCloudTag->m_vtrPos.Rotate(fTemp, CVector(0, 0, 1)); m_tcDemo.Add(pCloudTag);
这个函数是生成标签的核心函数,在程序里标签表现出来的形式就是文本,所以函数支持对文本的几乎一切定制,这包括内容、颜色、字体、字号、样式等。函数首先会创建一个字体,然后根据文本内容需要的大小创建一个内存位图,将文字绘制于这个位图之上。准备好文字的位图就要通过它来制作材质了,这里有一个问题,位图是没有Alpha通道的,怎么办呢,有没有什么相对简单的方法处理呢?这里我的处理方法是这样的,看代码,通过GetBitmap获取位图信息然后观察bmData.bmWidth和bmData.bmWidthBytes的值,可以发现bmWidthBytes是bmWidth的四倍。原来位图在内存里是以RGBA的方式存储的,所以通过GetBitmapBits获取到的数据就是4位的。众所周知,内存位图创建时是黑色的,这里我认定标签文字不能为黑色,所以检测数据如果是黑色的就把Alpha设为透明,不是就设为不透明,然后创建贴图。最后设置向量,在一个范围内随机生成一个长度做一个指向屏幕外的向量,在以x、y、z三个轴随机旋转一个角度,这样就完成了一个标签的建模。
渲染的部分很简单,就是常规的OpenGL绘制,只不过加上了材质设置了Alpha透明。其实这个Demo做的比较粗糙,文字周围存在黑边,不过做这个例子不是特别追求表现所以也就没有特别处理,代码如下:
view plaincopyprint?void COpenGLCtrl::OnPaint() { CPaintDC dc(this); //绘背景色 COLORREF clrBkgnd = GetSysColor(COLOR_BTNFACE); glClearColor(float(GetRValue(clrBkgnd))/255, float(GetGValue(clrBkgnd))/255, float(GetBValue(clrBkgnd))/255, 0.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //设置场景坐标系 glLoadIdentity(); //设置观察点 gluLookAt(0, 0, 30, 0, 0, 0, 0, 1, 0); INT_PTR nCount = m_tcDemo.GetCount(); for(int i=0; i<nCount; i++) { lpCloudTag pCloudTag = m_tcDemo.GetAt(i); glBindTexture(GL_TEXTURE_2D, pCloudTag->m_uTexture); glEnable(GL_BLEND); glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_GREATER, 0.1f); glBegin(GL_QUADS); glTexCoord2i(0, 0), glVertex3f(pCloudTag->m_vtrPos.m_fVectorX-pCloudTag->m_fWidth/2, pCloudTag->m_vtrPos.m_fVectorY+pCloudTag->m_fHeight/2, pCloudTag->m_vtrPos.m_fVectorZ); glTexCoord2i(1, 0), glVertex3f(pCloudTag->m_vtrPos.m_fVectorX+pCloudTag->m_fWidth/2, pCloudTag->m_vtrPos.m_fVectorY+pCloudTag->m_fHeight/2, pCloudTag->m_vtrPos.m_fVectorZ); glTexCoord2i(1, 1), glVertex3f(pCloudTag->m_vtrPos.m_fVectorX+pCloudTag->m_fWidth/2, pCloudTag->m_vtrPos.m_fVectorY-pCloudTag->m_fHeight/2, pCloudTag->m_vtrPos.m_fVectorZ); glTexCoord2i(0, 1), glVertex3f(pCloudTag->m_vtrPos.m_fVectorX-pCloudTag->m_fWidth/2, pCloudTag->m_vtrPos.m_fVectorY-pCloudTag->m_fHeight/2, pCloudTag->m_vtrPos.m_fVectorZ); glEnd(); glDisable(GL_ALPHA_TEST); glDisable(GL_BLEND); } //翻页 SwapBuffers(m_pDC->m_hDC); } void COpenGLCtrl::OnPaint() { CPaintDC dc(this); //绘背景色 COLORREF clrBkgnd = GetSysColor(COLOR_BTNFACE); glClearColor(float(GetRValue(clrBkgnd))/255, float(GetGValue(clrBkgnd))/255, float(GetBValue(clrBkgnd))/255, 0.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //设置场景坐标系 glLoadIdentity(); //设置观察点 gluLookAt(0, 0, 30, 0, 0, 0, 0, 1, 0); INT_PTR nCount = m_tcDemo.GetCount(); for(int i=0; i<nCount; i++) { lpCloudTag pCloudTag = m_tcDemo.GetAt(i); glBindTexture(GL_TEXTURE_2D, pCloudTag->m_uTexture); glEnable(GL_BLEND); glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_GREATER, 0.1f); glBegin(GL_QUADS); glTexCoord2i(0, 0), glVertex3f(pCloudTag->m_vtrPos.m_fVectorX-pCloudTag->m_fWidth/2, pCloudTag->m_vtrPos.m_fVectorY+pCloudTag->m_fHeight/2, pCloudTag->m_vtrPos.m_fVectorZ); glTexCoord2i(1, 0), glVertex3f(pCloudTag->m_vtrPos.m_fVectorX+pCloudTag->m_fWidth/2, pCloudTag->m_vtrPos.m_fVectorY+pCloudTag->m_fHeight/2, pCloudTag->m_vtrPos.m_fVectorZ); glTexCoord2i(1, 1), glVertex3f(pCloudTag->m_vtrPos.m_fVectorX+pCloudTag->m_fWidth/2, pCloudTag->m_vtrPos.m_fVectorY-pCloudTag->m_fHeight/2, pCloudTag->m_vtrPos.m_fVectorZ); glTexCoord2i(0, 1), glVertex3f(pCloudTag->m_vtrPos.m_fVectorX-pCloudTag->m_fWidth/2, pCloudTag->m_vtrPos.m_fVectorY-pCloudTag->m_fHeight/2, pCloudTag->m_vtrPos.m_fVectorZ); glEnd(); glDisable(GL_ALPHA_TEST); glDisable(GL_BLEND); } //翻页 SwapBuffers(m_pDC->m_hDC); }剩下的事情就是鼠标控制和动画实现了,由于我的向量类很好的支持了旋转功能,而且标签云建模就是通过向量实现的,所以这一步也就好说了。所有标签都是通过以原点为起点的向量定位的,所以转轴也是通过原点的在XOZ面上的向量。在OnMouseHover中计算状态和转速,然后在OnTimer里旋转每个标签的向量就是了,代码如下:
view plaincopyprint?LRESULT COpenGLCtrl::OnMouseHover(WPARAM wParam, LPARAM lParam) { CRect rectView; CPoint point; GetWindowRect(rectView); GetCursorPos(&point); m_vtrRotate.SetVector(float(-point.x), float(point.y), 0, -float(rectView.right+rectView.left)/2, float(rectView.bottom+rectView.top)/2, 0); m_vtrRotate.Rotate(-PI/2, CVector(0, 0, 1)); m_fAngle = m_vtrRotate.GetMod()/2000; return 1; } LRESULT COpenGLCtrl::OnMouseHover(WPARAM wParam, LPARAM lParam) { CRect rectView; CPoint point; GetWindowRect(rectView); GetCursorPos(&point); m_vtrRotate.SetVector(float(-point.x), float(point.y), 0, -float(rectView.right+rectView.left)/2, float(rectView.bottom+rectView.top)/2, 0); m_vtrRotate.Rotate(-PI/2, CVector(0, 0, 1)); m_fAngle = m_vtrRotate.GetMod()/2000; return 1; } [cpp] view plaincopyprint?void COpenGLCtrl::OnTimer(UINT_PTR nIDEvent) { switch(nIDEvent) { case TIMER_MOVE: { if(m_fAngle==0) return; INT_PTR nCount = m_tcDemo.GetCount(); for(int i=0; i<nCount; i++) { lpCloudTag pCloudTag = m_tcDemo.GetAt(i); pCloudTag->m_vtrPos.Rotate(m_fAngle, m_vtrRotate); Invalidate(); } }break; } CWnd::OnTimer(nIDEvent); } void COpenGLCtrl::OnTimer(UINT_PTR nIDEvent) { switch(nIDEvent) { case TIMER_MOVE: { if(m_fAngle==0) return; INT_PTR nCount = m_tcDemo.GetCount(); for(int i=0; i<nCount; i++) { lpCloudTag pCloudTag = m_tcDemo.GetAt(i); pCloudTag->m_vtrPos.Rotate(m_fAngle, m_vtrRotate); Invalidate(); } }break; }
CWnd::OnTimer(nIDEvent);
} 到此基本的功能就已经全部实现了,在我的资源里上传了这个Demo有兴趣朋友可以下载研究一下,有什么好的想法可以和我进一步交流。做这个东西,写这篇文章权当抛砖引玉,希望能给大家些灵感,从三维的角度作出有更好用户体验的界面设计。最后贴一个效果图,见笑见笑。
[img][/img]
转(http://blog.csdn.net/xianglitian/article/details/6590687)
发表评论
-
c++操作符优先级总结
2013-12-03 14:47 754优先级从上到下依次递减,最上面具有最高的优先级,逗号操作符具有 ... -
Qt状态机实例
2013-12-03 14:01 1054#include <QApplication> ... -
c++数据类型的隐形转换
2013-09-02 09:51 1633(1)隐式转换发生的时机:当传递给操作符或者函数的参数与指定类 ... -
C中的野指针
2013-08-30 16:11 994讨论一 什么是野指针 ... -
STL学习(转)
2012-08-28 15:38 1390STL就是Standard Template Libr ... -
STL详解
2012-08-28 14:33 1693STL概述 STL的一个重要 ... -
c++的三种继承(转)
2012-08-23 18:47 1022http://blog.csdn.net/wang_lime ... -
MFC中ADO方式操作数据库实例(转)
2012-08-22 11:12 2391连接ACCESS为例: //头文件 #pragma on ... -
派生类的构造函数(转)
2012-08-20 18:05 934派生类的数据成员由所 ... -
元算符重载时友元函数和成员函数的选择
2012-08-18 20:14 1371一般情况下,单目运算符最好重载为类的成员函数;双目运算符则最好 ... -
C++面试题(转)
2012-08-16 17:25 7831.是不是一个父类写了一个virtual 函数,如果子类覆盖它 ... -
8皇后问题c++的递归实现
2012-08-16 16:18 1455最近用C++递归形式实现了8皇后问题,可能效率有点低 #i ... -
c++实现的一些排序算法
2012-08-15 11:37 1343最近用c++简单实现了一些排序算法,记下来,以便以后用到 ... -
mfc 常用控件使用方法及常见数据类型转换
2012-04-18 20:31 2016最近做了几个mfc小程序,想把我们经常用到而又经常忘记的的小知 ...
相关推荐
在MFC中用 OpenGL 实现三维模型旋转
学习OpenGL,想用到MFC的话可以看看这个入门。从老师那得到的。
MFC 单文档 实现opengl 三维旋转 缩放 光照MFC 单文档 实现opengl 三维旋转 缩放 光照MFC 单文档 实现opengl 三维旋转 缩放 光照MFC 单文档 实现opengl 三维旋转 缩放 光照MFC 单文档 实现opengl 三维旋转 缩放 光照...
基于MFC通过OpenGL和MFC实现的标签云
mfc+opengl 开发框架,有缩放、旋转、移动功能。
本教程是在vs2010(对更高版本同样适用)下实现opengl在mfc应用,边做边编写的。
软件平台VS2010,使用的是MFC+OpenGL,旋转是通过ArcBall实现。左键按下旋转,鼠标滚轮实现缩放,右键平移。
MFC与OpenGL的简单例子和说明. 搭建用MFC进行OpenGL编程的框架. 调试完成的源码一份.
mfc开发opengl.rar mfc开发opengl.rar
基于MFC单文档OpenGL打开3D模型,可以打开3DMAX另存为的3ds文件,并将读取文件进行移动、旋转和缩放功能
mfc opengl 动画 exe文件 QQ登陆窗口会闪烁
对于OpenGL的应用,常常是基于GDI接口来实现的。在Windows下做开发,自然 就需要了解OpenGL在MFC下的开发,本工程是MFC下OpenGL开发的一个简单实例。
基于mfc的opengl绘图案例,主要为在mfc下绘制opengl图形提供一个框架。
MFC+OpenGL的初级入门教程,描述了如何在VC++环境下编写OpenGL图像。
利用MFC制作的opengl开发框架,opengl变成爱好者可在此基础上进行二次开发
发了一天功夫才把多线程的问题搞定,上传以后使用。若其他读者看到,希望能看懂我的苦心。thread相关的CPP需要你自己加上去,它们在压缩文件里面。
基于MFC的opengl图形 采用几何算法生成图形 实现旋转功能
用mfc opengl画圆画线 单击开始画线 双击停止画线
MFC的OpenGL纹理贴图技术 MFC的OpenGL纹理贴图技术
功能 绘制:直线段、多边形、圆等简单二维图形 处理:裁剪和变换 交互:参数由鼠标或键盘输入;选中并修改图形 存储:图形数据可以保存到文件中,并能读文件