在以后进行图形的二文用户坐标计算,二文设备坐标计算以及显示的过程中,只要判断Back==TRUE,就可以省去这些计算的过程。
屏后缓冲和用户交互——视图类(CView类)的实现
(1).屏后缓冲的技术
在视图类第一次初始化的时候,我们创建一个新的DC作为屏后缓冲。
void CGraphicView::OnInitialUpdate()
{
CView::OnInitialUpdate();
static BOOL Initalize=FALSE;
if(!Initalize) //保证仅执行一次
{
CDC *dc;
CRect view_rect;
dc=GetDC();
GetClientRect(view_rect);
MemDC.CreateCompatibleDC(dc);
MemDCBitmap.CreateCompatibleBitmap(dc,800,600);
MemDC.SelectObject(MemDCBitmap);
//创建缓冲区
DeleteObject(*dc);
Initalize=TRUE;
}
}
在以后需要绘图时,我们的OnDraw()函数这样重载:
void CGraphicView::OnDraw(CDC* pDC)
{
CRect view_rect;
CString Datas;
GetClientRect(view_rect);
MemDC.BitBlt(0,0,view_rect.Width(),view_rect.Height(),NULL,0,0,WHITENESS);
int i;
for(i=0;i<Polygons.GetCount();i++)
Polygons.GetAt(Polygons.FindIndex(i)).Draw(&MemDC);
Datas.Format("ViewPoint X=%3.1f,Y=%3.1f,Z=%3.1f",ViewPoint[0],ViewPoint[1],ViewPoint[2]);
MemDC.TextOut(0,0,Datas);
MemDC.TextOut(0,view_rect.Height()-20,"Copyright Brothers Studio ?2000");
pDC->BitBlt(0,0,view_rect.Width(),view_rect.Height(),
&MemDC,0,0,SRCCOPY);
}
请注意,前面的一切绘图操作都是在MemDC上完成的,因为绘图操作相对较慢,我们用MemDC来绘图,对于用户来说是不可见的,直到所有图形绘制完毕,整个函数最后一句把缓冲区快速复制过来,可以实现象素级的平滑动画效果。更好的办法是采用DirectDraw实现屏后缓冲,当然我们这里没必要实现得那么复杂了。
(2).用户交互的实现
首先,我们响应OnKeyDown的消息,用一个switch语句对于下述键码进行处理:
case 33: //PageUp 视点沿Z轴正向移动
case 34: //PageDown 视点沿Z轴反向移动
case ?A?: //视点沿X轴反向移动
case ?D?: //视点沿X轴正向移动
case ?W?: //视点沿Y轴正向移动
case ?S?: //视点沿Y轴反向移动
case ?R?: //物体沿X轴放大
case ?T?: //物体沿X轴缩小
case ?F?: //物体沿Y轴放大
case ?G?: //物体沿Y轴缩小
case ?V?: //物体沿Z轴放大
case ?B?: //物体沿Z轴缩小
(注意:上述放缩可能导致图形切变)
case 104: //NumPad 8 物体沿X轴正向移动
case 102: //NumPad 6 物体沿Y轴正向移动
case 101: //NumPad 5 物体沿Z轴正向移动
case 100: //NumPad 4 物体沿X轴反向移动
case 98: //NumPad 2 物体沿Y轴反向移动
case 96: //NumPad 0 物体沿Z轴反向移动
case VK_LEFT: // 物体沿Y轴旋转
case VK_RIGHT: // 物体沿Y轴旋转
case VK_UP: // 物体沿X轴旋转
case VK_DOWN: // 物体沿X轴旋转
case 36: //Home 物体沿Z轴旋转
case 35: //End 物体沿Z轴旋转
上面的这24个键是我们可以响应的,对于这些键,OnKeyDown函数首先调用MoveObject(nChar)生成变换矩阵,然后调用Draw()函数重新计算二文用户坐标,二文设备坐标,并利用屏后缓冲写屏,从而实现动画效果。
这里的一个关键是MoveObject(char)函数,我们截取一部分代码:
void CGraphicView::MoveObject(char type)
{
CMatrix MoveMatrix(4,4);
MoveMatrix.Fill(0);
MoveMatrix.MakeUnit();
//生成单位矩阵
switch(type)
{
case ?R?:
MoveMatrix[0][0]=1.02;
Break;
.
.
.
case 35: //End
Sin=sin(move_angle);
Cos=cos(move_angle);
MoveMatrix[1][1]=Cos; //这里矩阵类重载了[]运算符
MoveMatrix[0][0]=Cos;
MoveMatrix[0][1]=Sin;
MoveMatrix[1][0]=-Sin;
break;
} //生成变换矩阵
for(i=0;i<Polygons.GetCount();i++)
{
Polygons.GetAt(Polygons.FindIndex(i)).Move(&MoveMatrix);
} //对所有的多边形重新计算坐标
}
这里不难看出,我们利用前面的CMatrix矩阵类方便地实现了变换矩阵的生成和多边形的坐标变换。
读入数据文件——文档类(CDocment类)的实现
(1).两个重要的全局变量
在CDocument派生类中我们有如下定义的两个全局变量
CList<BCPoint,BCPoint&> Points;
CList<CPolygon,CPolygon&> Polygons;
这两个全局变量实际上是使用MFC的CList(链表类)保存整个图形中所有的点和多边形。实际上,只要能保存所有的多边形就足够了,因为多边形中也包含全部点的信息,但由于在读数据文件时,需要先读出点的信息,然后才能用点去组成多边形,所以我们保留了Points变量。
(2).数据文件的定义
请先看数据文件的一个简单示例:
POINT
0 0 1
1 0 1
1 1 1
0 1 1
0 0 0
1 0 0
1 1 0
0 1 0
POLYGON 4
1 5 6 2
2 6 7 3
3 7 8 4
4 8 5 1
1 2 3 4
5 8 7 6
VIEW -5 7 -15
END
上面的数据文件标识了一个棱长为1的立方体。关键字POINT表示下面每行的坐标是点坐标;POLYGON n(n是一个大于2的整数)表示下面的数据每行是一个n边形各顶点的索引;VIEW x y z表示视点坐标是(x,y,z);END表示一个数据文件的结束。
(3).读入数据文件
在CDocument的派生类中重载Serialize()函数,其中关键是下面所示的代码:
上一页 [1] [2] [3] [4] [5] [6] [7] [8] [9] 下一页