Rainyboy 发表于 2011-5-3 20:43

OpenGL练习(一):二维图形和鼠标键盘事件

本帖最后由 Rainyboy 于 2011-5-3 20:58 编辑

作为工程师的基本技能,无论是机械设计图还是规律变化图,画图本身不是什么难事。然而OpenGL作为使用得最广泛的底层绘图库类之一,是值得学习的。本帖包含了四个例子,是近来在重新学习这一图形工具时的习作,分别是:
1,一个单摆的演示动画;
         


2,一个旋转的正方形(可以通过键盘控制转动方向);
      


3,一个可以画圆、矩形和直线的小绘图工具(可以通过键盘控制绘图类型,有最简单的绘图预览);
      


4,一个弹性球在窗口内四处碰撞的演示动画。
      


=========================================================


主程序的代码和预编译头文件的内容在这里给出,后续四个楼层分别给出这四个练习的具体代码。



===程序的入口点:OpenGLTest.cpp====

#include "stdafx.h"
#include "Simple_Pendulum.h"
#include "Rotat_Block.h"
#include "SimplePaint.h"
#include "ElasticBall.h"


int _tmain(int argc, _TCHAR* argv[])
{
      system("cls");
      cout<<"OpenGL练习 StageA: 二维图形和鼠标事件"<<endl;
      cout<<"1,单摆"<<endl;
      cout<<"2,旋转正方形"<<endl;
      cout<<"3,简单鼠标绘图器"<<endl;
      cout<<"4,弹性碰撞球"<<endl;
      cout<<"输入选项:";
      int c;
      cin>>c;
      switch(c)
      {
      case 1:
                Simple_Pendulum(argc,argv);
                break;
      case 2:
                Rotat_Block(argc,argv);
                break;
      case 3:
                Simple_Paint(argc,argv);
                break;
      case 4:
                Elastic_Ball(argc,argv);
                break;
      }
      return 0;
}

===预编译头文件 stdafx.h =====

#pragma once

#include "targetver.h"

#include <stdio.h>
#include <tchar.h>



// TODO: 在此处引用程序需要的其他头文件
#include <windows.h>
#include <gl/GL.h>
#include <gl/GLU.h>
#include <gl/glut.h>
#include <math.h>
#include <stdlib.h>
#include <iostream>
#include <vector>
using namespace std;




Rainyboy 发表于 2011-5-3 20:46

本帖最后由 Rainyboy 于 2011-5-3 20:49 编辑

====单摆演示动画,头文件:Simple_Pendulum.h=======#include "stdafx.h"
class struct_SP_Global
{
public:
      struct_SP_Global()
      {
                theta = 0;
                theta_inc =1.0;
                amplitude = 10.0;
                DEG_TO_RAD = 0.017453;
      }
public:
      GLsizei ww;
      GLsizei hh;
      GLfloat theta;
      GLfloat theta_inc;
      GLfloat amplitude;
      GLfloat DEG_TO_RAD;
};
void SP_userReshape(GLsizei w,GLsizei h);
void SP_display();
void SP_init();
void SP_myidle();
int Simple_Pendulum(int argc, _TCHAR* argv[]);

====单摆演示动画,代码文件:Simple_Pendulum.cpp======

#include "stdafx.h"
#include "Simple_Pendulum.h"

struct_SP_Global SP_Global;
void SP_userReshape(GLsizei w,GLsizei h)
{
      glMatrixMode(GL_PROJECTION);
      glLoadIdentity();
      gluOrtho2D(-(GLdouble)w/2,(GLdouble)w/2,-(GLdouble)h/2,(GLdouble)h/2);
      glMatrixMode(GL_MODELVIEW);
      glViewport(0,0,w,h);
      SP_Global.ww=w;
      SP_Global.hh=h;
}
void SP_display()
{
      glClear(GL_COLOR_BUFFER_BIT);
      GLfloat startLoc = {0,SP_Global.hh/2};
      GLfloat Length = SP_Global.hh*9/10;
      GLfloat Angle = SP_Global.amplitude*SP_Global.DEG_TO_RAD*sin(2*SP_Global.DEG_TO_RAD*SP_Global.theta);
      GLfloat endLoc = {startLoc+Length*sin(Angle),startLoc-Length*cos(Angle)};
      GLfloat EdgeLoc ={0.0,0.0};
      //画摆线
      glBegin(GL_LINES);
      {
                glColor3f(1.0,1.0,1.0);
                glVertex2fv(startLoc);
                glVertex2fv(endLoc);
      }
      glEnd();
      //画圆:以多边形边界逼近
      glBegin(GL_LINE_LOOP);
      {
                glColor3f(1.0,1.0,1.0);
                for(int i=0;i<20;++i)
                {
                        GLfloat da = 360/20;
                        EdgeLoc = endLoc + 20*cos(i*SP_Global.DEG_TO_RAD*da);
                        EdgeLoc = endLoc + 20*sin(i*SP_Global.DEG_TO_RAD*da);
                        glVertex2fv(EdgeLoc);;
                }
      }
      glEnd();
      //抗锯齿
      glLineWidth(2);
      glEnable(GL_LINE_SMOOTH|GL_POINT_SMOOTH);
      glutSwapBuffers();
}

void SP_init()
{
      glClearColor(0.0,0.0,0.0,0.0);

      glColor3f(1.0,1.0,1.0);

      glMatrixMode(GL_PROJECTION);
      glLoadIdentity();
      gluOrtho2D(-1.0,1.0,-1.0,1.0);
}
void SP_myidle()
{
      SP_Global.theta += SP_Global.theta_inc;
      if(SP_Global.theta > 360.0)
      {
                SP_Global.theta -=360.0;
      }
      glutPostRedisplay();
}
int Simple_Pendulum(int argc, _TCHAR* argv[])
{
      glutInit(& argc,argv);
      glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB);
      glutInitWindowSize(150,400);
      glutInitWindowPosition(0,0);
      glutCreateWindow("Simple Pendulum");
      //设置回调函数
      glutDisplayFunc(SP_display);
      glutReshapeFunc(SP_userReshape);
      glutIdleFunc(SP_myidle);
      //进入主消息循环
      SP_init();
      glutMainLoop();
      return 0;
}


Rainyboy 发表于 2011-5-3 20:49

====旋转正方形:头文件Rotat_Block.h============#include "stdafx.h"

class struct_RB_Global
{
public:
        struct_RB_Global()
        {
                theta=0.0;
                DEG_TO_RAD=0.017453;
                theta_inc =2.0;
        }
public:
        GLsizei ww,hh;
        GLfloat theta;
        GLfloat DEG_TO_RAD;
        GLfloat theta_inc;
};

void RB_userReshape(GLsizei w,GLsizei h);
void RB_display();
void RB_init();
void RB_myidle();
void RB_mykey(unsigned char key,int x,int y);
int Rotat_Block(int argc, _TCHAR* argv[]);


====旋转正方形:代码文件Rotat_Block.cpp============


#include "stdafx.h"
#include "Rotat_Block.h"


struct_RB_Global RB_Global;
void RB_userReshape(GLsizei w,GLsizei h)
{
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluOrtho2D(-(GLdouble)w/2,(GLdouble)w/2,-(GLdouble)h/2,(GLdouble)h/2);
        glMatrixMode(GL_MODELVIEW);
        glViewport(0,0,w,h);
        RB_Global.ww=w;
        RB_Global.hh=h;
}
void RB_display()
{
        glClear(GL_COLOR_BUFFER_BIT);
        GLsizei lw = RB_Global.ww>RB_Global.hh?RB_Global.hh:RB_Global.ww;
        lw = lw/2;
        GLfloat ALPHA = RB_Global.DEG_TO_RAD*RB_Global.theta;
        glBegin(GL_POLYGON);
        {
                glColor3f(0.0,1.0,0.0);
                glVertex2f(lw * sin(ALPHA),lw * cos(ALPHA));
                glColor3f(1.0,0.0,0.0);
                glVertex2f(-lw * cos(ALPHA),lw * sin(ALPHA));
                glColor3f(0.0,0.0,1.0);
                glVertex2f(-lw * sin(ALPHA),-lw * cos(ALPHA));
                glColor3f(0.0,1.0,0.0);
                glVertex2f(lw * cos(ALPHA),-lw * sin(ALPHA));
        }
        glEnd();
       
        glutSwapBuffers();
}

void RB_init()
{
        glClearColor(0.0,0.0,0.0,0.0);

        glColor3f(1.0,1.0,1.0);

        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluOrtho2D(-1.0,1.0,-1.0,1.0);
}
void RB_myidle()
{
        RB_Global.theta += RB_Global.theta_inc;
        if(RB_Global.theta > 360.0)
        {
                RB_Global.theta -=360.0;
        }
        glutPostRedisplay();
}
void RB_mykey(unsigned char key,int x,int y)
{
        printf("%d,%d\n",x,y);
        if (key=='R'||key=='r')
        {
                RB_Global.theta_inc *= -1;
        }
        else if(key=='S'||key=='s')
        {
                glutIdleFunc(NULL);
        }
        else if(key=='G'||key=='g')
        {
                glutIdleFunc(RB_myidle);
        }
        glutPostRedisplay();
}

int Rotat_Block(int argc, _TCHAR* argv[])
{
        glutInit(& argc,argv);
        glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB);
        glutInitWindowSize(500,500);
        glutInitWindowPosition(0,0);
        glutCreateWindow("Rotat Block");
        //设置回调函数
        glutDisplayFunc(RB_display);
        glutReshapeFunc(RB_userReshape);
        glutIdleFunc(RB_myidle);
        glutKeyboardFunc(RB_mykey);
        //进入主消息循环
        RB_init();
        //
        cout<<"R :反转选装方向"<<endl;
        cout<<"S :停止旋转"<<endl;
        cout<<"G :重新开始旋转"<<endl;
        //
        glutMainLoop();
        return 0;
}




Rainyboy 发表于 2011-5-3 20:51

====简单绘图器,头文件SimplePaint.h===============#include "stdafx.h"

#define PT_FIRST_CLICK 0
#define PT_SENCOND_CLICK 1
#define PT_NEVER_CLICK 2
#define ST_LINE 10
#define ST_BLOCK 11
#define ST_CIRCLE 12

struct PicItem
{
        GLint x_1,x_2,y_1,y_2;
        int PaintTag;
        int StyleTag;
};

typedef vector<PicItem> PicItem_vec;

class struct_SPAINT_Global
{
public:
        struct_SPAINT_Global()
        {
                PaintTag = PT_NEVER_CLICK;
                StyleTag = ST_CIRCLE;
                DEG_TO_RAD = 0.017453;
        }
public:
        GLfloat DEG_TO_RAD;
        GLsizei ww,hh;
        GLint x_1,x_2,y_1,y_2;
        int PaintTag;
        int StyleTag;
        PicItem_vec PicItemHist;
};




void PlotItem(int x_1,int y_1,int x_2,int y_2,int PaintTag,int StyleTag);
void SPAINT_userReshape(GLsizei w,GLsizei h);
void SPAINT_display();
void SPAINT_init();
void SPAINT_mykey(unsigned char key,int x,int y);
void SPAINT_mymouse(int button, int state, int x,int y);
int Simple_Paint(int argc, _TCHAR* argv[]);
void SPAINT_myPasstiveMotion(int x,int y);



====简单绘图器,代码文件SimplePaint.cpp==============
#include "stdafx.h"
#include "SimplePaint.h"

struct_SPAINT_Global SPAINT_Global;
void SPAINT_userReshape(GLsizei w,GLsizei h)
{
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluOrtho2D(-(GLdouble)w/2,(GLdouble)w/2,-(GLdouble)h/2,(GLdouble)h/2);
        glMatrixMode(GL_MODELVIEW);
        glViewport(0,0,w,h);
        SPAINT_Global.ww=w;
        SPAINT_Global.hh=h;
}
void SPAINT_display()
{
        glClear(GL_COLOR_BUFFER_BIT);
        glColor3f(0.0,0.0,0.0);
        //绘制已有的图形
        for(int i=0;i<SPAINT_Global.PicItemHist.size();++i)
        {
                PlotItem(
                        SPAINT_Global.PicItemHist.x_1,
                        SPAINT_Global.PicItemHist.y_1,
                        SPAINT_Global.PicItemHist.x_2,
                        SPAINT_Global.PicItemHist.y_2,
                        SPAINT_Global.PicItemHist.PaintTag,
                        SPAINT_Global.PicItemHist.StyleTag
                        );
        }
        glColor3f(1.0,0.0,0.0);
        //绘制试探的图形
        PlotItem(
        SPAINT_Global.x_1,
        SPAINT_Global.y_1,
        SPAINT_Global.x_2,
        SPAINT_Global.y_2,
        PT_SENCOND_CLICK,
        SPAINT_Global.StyleTag
        );
        //抗锯齿
        glLineWidth(1.5);
        glPolygonMode(GL_FRONT,GL_LINE);
        glPolygonMode(GL_BACK,GL_LINE);
        glEnable(GL_LINE_SMOOTH|GL_POINT_SMOOTH);
        glutSwapBuffers();
}

void PlotItem(int x_1,int y_1,int x_2,int y_2,int PaintTag,int StyleTag)
{
        GLfloat da;
        GLfloat R =(x_1 - x_2)*(x_1 - x_2) + (y_1 - y_2)*(y_1 - y_2);
        R = pow((float)R,(float)0.5)/2;
        switch(PaintTag)
        {
        case PT_FIRST_CLICK:
        case PT_NEVER_CLICK:
                return;
        case PT_SENCOND_CLICK:
                switch(StyleTag)
                {
                case ST_BLOCK:
                        glBegin(GL_POLYGON);
                        {
                                glVertex2i(x_1,y_1);
                                glVertex2i(x_1,y_2);
                                glVertex2i(x_2,y_2);
                                glVertex2i(x_2,y_1);
                        }
                        glEnd();
                        break;
                case ST_LINE:
                        glBegin(GL_LINES);
                        {
                                glVertex2i(x_1,y_1);
                                glVertex2i(x_2,y_2);
                        }
                        glEnd();
                        break;
                case ST_CIRCLE:
                        glBegin(GL_LINE_LOOP);
                        {
                                for(int i=0;i<40;++i)
                                {
                                        da= 360/40;
                                        glVertex2f((x_1+x_2)/2 + R*cos(i*SPAINT_Global.DEG_TO_RAD*da),
                                                (y_1+y_2)/2 + R*sin(i*SPAINT_Global.DEG_TO_RAD*da));
                                }
                        }
                        glEnd();
                        break;
                }
        }
}

void SPAINT_init()
{
        glClearColor(1.0,1.0,1.0,1.0);

        glColor3f(1.0,1.0,1.0);

        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluOrtho2D(-1.0,1.0,-1.0,1.0);
}
void SPAINT_mykey(unsigned char key,int x,int y)
{
        if (key=='L'||key=='l')
                SPAINT_Global.StyleTag = ST_LINE;
        else if(key=='B'||key=='b')
                SPAINT_Global.StyleTag = ST_BLOCK;
        else if(key=='C'||key=='c')
                SPAINT_Global.StyleTag = ST_CIRCLE;
}
void SPAINT_mymouse(int button, int state, int x,int y)
{
        if(state == GLUT_DOWN && button == GLUT_LEFT_BUTTON)
        {
                if(SPAINT_Global.PaintTag == PT_FIRST_CLICK || SPAINT_Global.PaintTag == PT_NEVER_CLICK)
                {
                        SPAINT_Global.x_2 = x - SPAINT_Global.ww/2;
                        SPAINT_Global.y_2 = SPAINT_Global.hh/2 - y;
                        SPAINT_Global.PaintTag = PT_SENCOND_CLICK;
                }
                else if(SPAINT_Global.PaintTag == PT_SENCOND_CLICK)
                {
                        SPAINT_Global.x_1 = x - SPAINT_Global.ww/2;
                        SPAINT_Global.y_1 = SPAINT_Global.hh/2 - y;
                        PicItem tPI;
                        tPI.x_1 = SPAINT_Global.x_1;
                        tPI.x_2 = SPAINT_Global.x_2;
                        tPI.y_1 = SPAINT_Global.y_1;
                        tPI.y_2 = SPAINT_Global.y_2;
                        tPI.PaintTag = SPAINT_Global.PaintTag;
                        tPI.StyleTag = SPAINT_Global.StyleTag;
                        SPAINT_Global.PicItemHist.push_back(tPI);
                        SPAINT_Global.PaintTag = PT_FIRST_CLICK;
                }
        }

        glutPostRedisplay();
}
void SPAINT_myPasstiveMotion(int x,int y)
{
        if(SPAINT_Global.PaintTag == PT_FIRST_CLICK || SPAINT_Global.PaintTag == PT_NEVER_CLICK)
                return;
        SPAINT_Global.x_1 = x - SPAINT_Global.ww/2;
        SPAINT_Global.y_1 = SPAINT_Global.hh/2 - y;
        glutPostRedisplay();
}
int Simple_Paint(int argc, _TCHAR* argv[])
{
        glutInit(& argc,argv);
        glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB);
        glutInitWindowSize(500,500);
        glutInitWindowPosition(0,0);
        glutCreateWindow("Simple");
        //设置回调函数
        glutDisplayFunc(SPAINT_display);
        glutReshapeFunc(SPAINT_userReshape);
        glutKeyboardFunc(SPAINT_mykey);
        glutMouseFunc(SPAINT_mymouse);
        glutPassiveMotionFunc(SPAINT_myPasstiveMotion);
        //
        cout<<"C : 画圆环"<<endl;
        cout<<"L : 画直线"<<endl;
        cout<<"B : 画矩形"<<endl;
        //
        //进入主消息循环
        SPAINT_init();
        glutMainLoop();
        return 0;
}




Rainyboy 发表于 2011-5-3 20:53

=====弹性小球演示动画,头文件   ElasticBall.h================#include "stdafx.h"
class struct_EB_Global
{
public:
        struct_EB_Global()
        {
                R = 40.0;
                DEG_TO_RAD = 0.017453;
                CenterLoc = 0;
                CenterLoc = 0;
                Velocity=1.4;
                Velocity=2.7;
                Step = 1.0;
        }
public:
        GLsizei ww;
        GLsizei hh;
        GLfloat R;
        GLfloat DEG_TO_RAD;
        GLint CenterLoc;
        GLfloat Velocity;
        GLfloat Step;
};

void EB_userReshape(GLsizei w,GLsizei h);
void EB_display();
void EB_init();
void EB_myidle();
int Elastic_Ball(int argc, _TCHAR* argv[]);



=====弹性小球演示动画,代码文件   ElasticBall.cpp===============

#include "stdafx.h"
#include "ElasticBall.h"
struct_EB_Global EB_Global;
void EB_userReshape(GLsizei w,GLsizei h)
{
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluOrtho2D(-(GLdouble)w/2,(GLdouble)w/2,-(GLdouble)h/2,(GLdouble)h/2);
        glMatrixMode(GL_MODELVIEW);
        glViewport(0,0,w,h);
        EB_Global.ww=w;
        EB_Global.hh=h;
}
void EB_display()
{
        glClear(GL_COLOR_BUFFER_BIT);
        //画圆:以多边形边界逼近
        GLfloat EdgeLoc;
        glBegin(GL_LINE_LOOP);
        {
                glColor3f(1.0,1.0,1.0);
                for(int i=0;i<20;++i)
                {
                        GLfloat da = 360/20;
                        EdgeLoc = EB_Global.CenterLoc + EB_Global.R*cos(i*EB_Global.DEG_TO_RAD*da);
                        EdgeLoc = EB_Global.CenterLoc + EB_Global.R*sin(i*EB_Global.DEG_TO_RAD*da);
                        glVertex2fv(EdgeLoc);
                }
        }
        glEnd();
        //抗锯齿
        glLineWidth(2);
        glEnable(GL_LINE_SMOOTH|GL_POINT_SMOOTH);
        glutSwapBuffers();
}

void EB_init()
{
        glClearColor(0.0,0.0,0.0,0.0);

        glColor3f(1.0,1.0,1.0);

        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluOrtho2D(-1.0,1.0,-1.0,1.0);
}
void EB_myidle()
{
        EB_Global.CenterLoc+=EB_Global.Velocity*EB_Global.Step;
        if(abs(EB_Global.CenterLoc) + EB_Global.R >EB_Global.hh/2)
        {
                EB_Global.Velocity *= -1;
        }
        EB_Global.CenterLoc+=EB_Global.Velocity*EB_Global.Step;
        if(abs(EB_Global.CenterLoc) + EB_Global.R >EB_Global.ww/2)
        {
                EB_Global.Velocity *= -1;
        }
        glutPostRedisplay();
}
int Elastic_Ball(int argc, _TCHAR* argv[])
{
        glutInit(& argc,argv);
        glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB);
        glutInitWindowSize(500,500);
        glutInitWindowPosition(0,0);
        glutCreateWindow("Simple Pendulum");
        //设置回调函数
        glutDisplayFunc(EB_display);
        glutReshapeFunc(EB_userReshape);
        glutIdleFunc(EB_myidle);
        //进入主消息循环
        EB_init();
        glutMainLoop();
        return 0;
}




meiyongyuandeze 发表于 2011-5-4 08:12

院长,猛男!程序运行了下,感觉不错,多谢分享哈!

Rainyboy 发表于 2011-5-4 09:52

回复 6 # meiyongyuandeze 的帖子

哪里,过奖了……远未触及OpenGL的精髓……路还长啊,呵呵

hityrj 发表于 2011-5-19 15:22

恩……我想问下……我编写OpenGL代码时,主函数如果是 _tmain(int argc, _TCHAR* argv[])
会报错,只可以在int main(int argc, char **argv) 或int main(int argc, char *argv[])……这是什么原因呢

Rainyboy 发表于 2011-5-19 15:28

回复 8 # hityrj 的帖子

哦,可能是由于UNICODE兼容方面的问题吧,你看看这个
http://baike.baidu.com/view/3478231.htm

impulse 发表于 2011-5-19 15:58

采用Java 3d来做也不错,用它做个输电塔振型动画。

Rainyboy 发表于 2011-5-19 16:03

回复 10 # impulse 的帖子

嗯嗯,做动画的方式还是很多的,达到目的就行

dafo2006 发表于 2011-5-28 10:54

学习了!

wizardyjh 发表于 2012-3-30 14:28

学习了~~~~~~~~~~
页: [1]
查看完整版本: OpenGL练习(一):二维图形和鼠标键盘事件