关于使用opengl编程时绘制动态界面的问题

oliveshaw 2009-04-29 08:42:50
我在openglview.cpp文件中定义了一个global变量,结构体QNode* display,QNode是一个队列。
然后我想让程序进行循环,每次从QNode中取出一个结点,根据结点的值绘图,这个图是动态的,实现n个小人(n的值由QNode中的结点的值决定)从界面的一边走到另外一边,也就是说,在程序中,这些小人会从界面的左边走到右边,再从右边走回左边(具体怎么走,有多少小人,都由QNode的结点的值决定),一直到QNode到达队列尾为止,OnDraw函数中代码如下:

COpenGLDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);

// TODO: add draw code for native data here
// 准备一个标志信号
static BOOL bBusy = FALSE;
if(bBusy) return; //如果忙,则返回
bBusy = TRUE; //置标志为忙,下面开始场景绘制

// 获取设备描述表
wglMakeCurrent(m_pDC->GetSafeHdc(), m_hRC);

// 清除颜色缓冲区和深度缓冲区
glClearColor(1.0f, 1.0f, 1.0f, 0.f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

//设置光照和深度模型
Init();

// 调用场景绘制函数
if (m_Show==1)
OnFlash();

// 完成图形的绘制
glFinish();

// 启用双缓冲
SwapBuffers(m_pDC->GetSafeHdc());

// 绘制完毕,置标志为空闲
bBusy = FALSE;

// 释放OpenGL绘制描述表
wglMakeCurrent(NULL,NULL);

在函数OnFlash();中进行具体的绘制操作
while(p !=output.rear){
...//控制小人在界面上移动的代码
}
但是程序一执行就死掉,我把上面代码中的while换成if就没问题,所以应该是循环的问题。请问如果想要实现我的目的,这个while循环应该加在哪里呢?谢谢!
或者请大家给我推荐一本书,里面有类似代码实现的也行,我找的书里面ms都没有这种程序,谢谢!
...全文
159 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
oliveshaw 2009-05-13
  • 打赏
  • 举报
回复
ms可以了,我再调调,谢谢hearofmaple!非常感谢!
heartofmaple 2009-05-13
  • 打赏
  • 举报
回复
CClientDC dc(this);
OnPrepareDC(&dc);
OnDraw(&dc);
oliveshaw 2009-05-13
  • 打赏
  • 举报
回复
可是调用OnDraw()需要给出参数CDC *pDc,那个不是系统自动调用的吗?
heartofmaple 2009-05-13
  • 打赏
  • 举报
回复
把Invalidate改成直接调用OnDraw试试,MFC对消息的处理过程我也不太清楚.
oliveshaw 2009-05-12
  • 打赏
  • 举报
回复
其他部分的程序还是不变
在OnDraw()里面

//设置光照和深度模型
Init();
// 调用场景绘制函数
f (m_Show==2)
{
OnFlash();
}
// 完成图形的绘制
glFinish();
// 启用双缓冲
SwapBuffers(m_pDC->GetSafeHdc());


OnFlash():

void CMycodeView::OnFlash() //动态演示过河过程
{
int lc, rc; //左、右岸小人个数
rc = 0;
int mc; //需要移动的小人个数
mc = 0;
int i; //循环变量
int c_last;
c_last = p->node.cannibal;
if(p->node.boat == 0)
{ //如果船在左岸,人移动到右岸,并修改船标志
lc = p->node.cannibal;
//计算要移动的人数
mc = abs(c_last - lc);
//计算右岸人数
rc = Max_p - lc - mc;
//画左岸小人
for(i=0; i <lc; i++)
{
glLoadIdentity(); // Reset The Current Modelview Matrix
glBegin(GL_TRIANGLES); // Draw A Triangle
glColor3f(0.0f,1.0f,0.0f); // Set The Color To green
glVertex3f( -0.5f-i*0.12f, 0.37f, 1.0f);
glVertex3f( -0.45f-i*0.12f, 0.5f, 1.0f);
glVertex3f( -0.4f-i*0.12f, 0.37f, 1.0f);
glEnd();
}
//画移动的人
for(i=0; i <mc; i++)
{
glLoadIdentity();
glTranslatef(t_c1,0.0f,0.0f); //Translate along x axis
glBegin(GL_TRIANGLES);
glColor3f(0.0f,1.0f,0.0f);
glVertex3f( -0.5f-i*0.12f, 0.37f, 1.0f);
glVertex3f( -0.45f-i*0.12f, 0.5f, 1.0f);
glVertex3f( -0.4f-i*0.12f, 0.37f, 1.0f);
glEnd();
}
//控制移动变量
if(t_c1 <1.2f)
{
t_c1+=0.005f;
}
if(t_c1==1.2f)
{
t_c1 = 0.f;
}
c_last = p->node.cannibal;
rc+=mc;
}
//如果船在右岸代码同上,省略
//画界河的代码省略
}


谢谢了!
oliveshaw 2009-05-12
  • 打赏
  • 举报
回复
好像不行,我的程序是

void CMycodeView::OnShow()
{
// TODO: Add your command handler code here
m_Show = 2;

QNode *p = output.front->next;

while(p!=output.rear) {
p = p->next;
Invalidate(TRUE);
}
}


但是我单步执行的时候发现,调用OnFlash函数的时候,p指针已经执行output的最后一个结点了
也就是说,我觉得程序是在while循环执行完之后才调用OnFlash函数的。
而且,我把Invalidate(TRUE);改成Invalidate(FALSE);也一样不行T_T
请大家帮我看看,这到底是怎么回事?谢谢!
oliveshaw 2009-05-12
  • 打赏
  • 举报
回复
谢谢 heartofmaple!
我再试试
heartofmaple 2009-05-05
  • 打赏
  • 举报
回复
if(m_Show==2)
{
QNode *p = output.front->next;

p = p->next;
while(p !=output.rear){
OnFlash();
p = p->next;
InvalidateRect(NULL,FALSE);
}

1.InvalidateRect本身会发送WM_PAINT消息,不要在ondraw里边使用.
2.SwapBuffers(m_pDC->GetSafeHdc())将当前绘制信息显示出来,但在这之前,你的队列已经全部结束了,没法动态显示,只有显示最后一次的场景。正确的应该是,每进行一步,交换缓存一次。
3.你的OnFlash()里每次处理的都是相同的结点...QNode *p = output.front->next; p = p->next; 每次处理的都是这个...
4.个人建议:在外部设立一个函数,负责队列的前进,每进行一步,用InvalidateRect向系统发送WM_PAINT绘制出当前场景。在ondraw里对当前位置进行绘制。当前位置使用全局变量.
QNode *p;

void CMycodeView::OnFlash() //动态演示过河过程
{
int lc, rc; //左、右岸小人个数
rc = 0;
int mc; //需要移动的小人个数
mc = 0;
int i; //循环变量
int c_last;
c_last = p->node.cannibal;
if(p->node.boat == 0)
{ //如果船在左岸,人移动到右岸,并修改船标志
lc = p->node.cannibal;
//计算要移动的人数
mc = abs(c_last - lc);
//计算右岸人数
rc = Max_p - lc - mc;
//画左岸小人
for(i=0; i <lc; i++)
{
glLoadIdentity(); // Reset The Current Modelview Matrix
glBegin(GL_TRIANGLES); // Draw A Triangle
glColor3f(0.0f,1.0f,0.0f); // Set The Color To green
glVertex3f( -0.5f-i*0.12f, 0.37f, 1.0f);
glVertex3f( -0.45f-i*0.12f, 0.5f, 1.0f);
glVertex3f( -0.4f-i*0.12f, 0.37f, 1.0f);
glEnd();
}
//画移动的人
for(i=0; i <mc; i++)
{
glLoadIdentity();
glTranslatef(t_c1,0.0f,0.0f); //Translate along x axis
glBegin(GL_TRIANGLES);
glColor3f(0.0f,1.0f,0.0f);
glVertex3f( -0.5f-i*0.12f, 0.37f, 1.0f);
glVertex3f( -0.45f-i*0.12f, 0.5f, 1.0f);
glVertex3f( -0.4f-i*0.12f, 0.37f, 1.0f);
glEnd();
}
//控制移动变量
if(t_c1 <1.2f)
{
t_c1+=0.005f;
}
if(t_c1==1.2f)
{
t_c1 = 0.f;
}
c_last = p->node.cannibal;
rc+=mc;
}
//如果船在右岸代码同上,省略
//画界河的代码省略
}

在OnDraw()里边

//设置光照和深度模型
Init();
// 调用场景绘制函数
f (m_Show==2)
{
OnFlash();
}
// 完成图形的绘制
glFinish();
// 启用双缓冲
SwapBuffers(m_pDC->GetSafeHdc());

新加的函数,调用一次即可.

p = output.front->next;
while(p!=output.rear)
{
p = p->next;
InvalidateRect(NULL,FALSE);
}
oliveshaw 2009-05-05
  • 打赏
  • 举报
回复
ms没人回帖呀,是不是我程序贴的不够详细?以下是OnFlash()中的部分代码,由于水平有限,暂时用三角形代替小人
void CMycodeView::OnFlash() //动态演示过河过程
{
int lc, rc; //左、右岸小人个数
rc = 0;

int mc; //需要移动的小人个数
mc = 0;

int i; //循环变量
int c_last;

QNode *p = output.front->next;
c_last = p->node.cannibal;

p = p->next;

if(p->node.boat == 0) { //如果船在左岸,人移动到右岸,并修改船标志

lc = p->node.cannibal;

//计算要移动的人数
mc = abs(c_last - lc);

//计算右岸人数
rc = Max_p - lc - mc;

//画左岸小人
for(i=0; i<lc; i++){
glLoadIdentity(); // Reset The Current Modelview Matrix
glBegin(GL_TRIANGLES); // Draw A Triangle
glColor3f(0.0f,1.0f,0.0f); // Set The Color To green
glVertex3f( -0.5f-i*0.12f, 0.37f, 1.0f);
glVertex3f( -0.45f-i*0.12f, 0.5f, 1.0f);
glVertex3f( -0.4f-i*0.12f, 0.37f, 1.0f);
glEnd();

}

//画移动的人
for(i=0; i<mc; i++){
glLoadIdentity();
glTranslatef(t_c1,0.0f,0.0f); //Translate along x axis
glBegin(GL_TRIANGLES);
glColor3f(0.0f,1.0f,0.0f);
glVertex3f( -0.5f-i*0.12f, 0.37f, 1.0f);
glVertex3f( -0.45f-i*0.12f, 0.5f, 1.0f);
glVertex3f( -0.4f-i*0.12f, 0.37f, 1.0f);
glEnd();
}
//控制移动变量
if(t_c1<1.2f){
t_c1+=0.005f;
}
if(t_c1==1.2f){
t_c1 = 0.f;
}

c_last = p->node.cannibal;
rc+=mc;
p = p->next;

}
//如果船在右岸代码同上,省略
//画界河的代码省略
}

最后是用定时器控制小人的行走速度,不是用ls所说的sleep函数。
void COpenGLView::OnTimer(UINT nIDEvent)
{
// TODO: Add your message handler code here and/or call default
//添加定时器响应函数和场景更新函数
Invalidate(FALSE);

CView::OnTimer(nIDEvent);
}

基本上程序就是这个样子了,请高手指点下,我按照heartofmaple同学所说的在OnFlash()函数外面套一个循环以后还是不能实现小人从右岸移到左岸,再从左岸移动到右岸的全过程,而是只能实现QNode中第一个结点对应数值的移动,即只能把两个小人从左岸移动到右岸,然后就不动了。
谢谢!
oliveshaw 2009-05-02
  • 打赏
  • 举报
回复
ls,我按照你说的做的,好像不行,我在OnDraw函数中当m_Show=1时添加了一个循环,具体程序如下
COpenGLDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);

// TODO: add draw code for native data here
// 准备一个标志信号
static BOOL bBusy = FALSE;
if(bBusy) return; //如果忙,则返回
bBusy = TRUE; //置标志为忙,下面开始场景绘制

// 获取设备描述表
wglMakeCurrent(m_pDC->GetSafeHdc(), m_hRC);

// 清除颜色缓冲区和深度缓冲区
glClearColor(1.0f, 1.0f, 1.0f, 0.f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

//设置光照和深度模型
Init();

// 调用场景绘制函数
f (m_Show==2)
{
QNode *p = output.front->next;

p = p->next;
while(p !=output.rear){
OnFlash();
p = p->next;
InvalidateRect(NULL,FALSE);
}

// 完成图形的绘制
glFinish();

// 启用双缓冲
SwapBuffers(m_pDC->GetSafeHdc());

// 绘制完毕,置标志为空闲
bBusy = FALSE;

// 释放OpenGL绘制描述表
wglMakeCurrent(NULL,NULL);

然后OnFlash中的程序保持不变,只是把原来的
while(p !=output.rear){
}
那一层循环去掉了。

但是程序在运行的时候就只显示当p指向output的第一个结点的时候对应参数的移动过程,然后就什么也不显示了。也就是说,界面上的小人只是一开始从屏幕的左边移动到右边,然后就不会再回去了。可是我是想要它先从左边移动到右边(两个小人),再从右边回到左边(一个小人),等等等等

请问是不是还少了点儿什么呢?请大家帮帮忙,谢谢!
heartofmaple 2009-04-30
  • 打赏
  • 举报
回复
函数A中的InvalidateRect前得加句sleep()控制小人行走的速度。
heartofmaple 2009-04-30
  • 打赏
  • 举报
回复
在函数A中使用while(p!=output.rear){p=p.next;InvalidateRect(NULL,FALSE);}
OnFlash()只对当前的p进行绘制.
程序中调用函数A一次即可.

19,464

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 图形处理/算法
社区管理员
  • 图形处理/算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧