九大行星运行

九大行星运行

基于opengl实现

background类实现背景加载

/*backgrounbd.h*/
#pragma once
#include "windows.h"
#include <gl/GL.h>

// 宇宙背景
class background  
{
public :
    void Init();
    void draw();

    background();
    virtual ~background();
private :
    // 纹理
    GLuint m_uText;
};

/*backgrounbd.cpp*/
#include "background.h"
#include <gl\GLAux.h>
#include "io.h"
#pragma warning(disable : 4996)

background::background()
    : m_uText(0)
{
}

background::~background()
{
    glDeleteTextures(1, &m_uText);
}

void background::Init()
{
    if (access("tex\\bk.bmp", 0) == -1)
        return;

    AUX_RGBImageRec* irec = auxDIBImageLoad("tex\\bk.bmp");

    // 加载贴图
    glGenTextures(1, &m_uText);
    glBindTexture(GL_TEXTURE_2D, m_uText);
    glTexImage2D(GL_TEXTURE_2D, 0, 3, irec->sizeX, irec->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, irec->data);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);    // 线形滤波
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
    glBindTexture(GL_TEXTURE_2D, 0);

    //释放资源
    if (irec)
    {
        if (irec->data)
            free(irec->data);
        free(irec);
    }
}

void background::draw()
{
    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
    glDepthMask(FALSE);
    glEnable(GL_TEXTURE_2D);

    glMatrixMode(GL_PROJECTION);
    glPushMatrix();
    glLoadIdentity();
    gluOrtho2D(0, 1, 0, 1);

    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();
    glLoadIdentity();

    glBindTexture(GL_TEXTURE_2D, m_uText);
    glBegin(GL_POLYGON);
    glColor3f(1, 1, 1);
    glTexCoord2f(0, 0);
    glVertex2f(0, 0);
    glTexCoord2f(1, 0);
    glVertex2f(1, 0);
    glTexCoord2f(1, 1);
    glVertex2f(1, 1);
    glTexCoord2f(0, 1);
    glVertex2f(0, 1);
    glEnd();
    glBindTexture(GL_TEXTURE_2D, 0);

    glPopMatrix();

    glMatrixMode(GL_PROJECTION);
    glPopMatrix();

    glMatrixMode(GL_MODELVIEW);

    glDepthMask(TRUE);
}

camera类实现移动

/*camera.h*/
#pragma once

//相机类的声明
class camera  
{
public:
    camera();
    virtual ~camera();

    // 更新相机位置
    void update();

    // 响应键盘消息
    void keyfunc(int key);

    // 响应鼠标消息
    void mousefunc(int button, int state, int x, int y);
    void motion(int x, int y);

private:
    // 是否左键按下
    bool m_leftkey;
    // 是否右键按下
    bool m_rigtkey;

    // 上一次x坐标
    int m_px;
    // 上一次y坐标
    int m_py;

    // x轴移动
    int m_dx;
    // y轴移动
    int m_dy;
    // z轴移
    int m_dz;

    // x轴旋转
    int m_rx;
    // y轴旋转
    int m_ry;
};

/*camera.cpp*/
#include "camera.h"
#include "glut.h"
#include "stdio.h"

camera::camera()
    : m_leftkey(false), m_rigtkey(false),
      m_dx(0), m_dy(0), m_dz(0),
      m_rx(25), m_ry(2)
{

}

camera::~camera()
{
}


//响应键盘输入
void camera::keyfunc(int key)
{
    switch (key)
    {
    case 'A' :
    case 'a' :
        {
            m_dx += 50;
        }
        break;
    case 'D' :
    case 'd' :
        {
            m_dx -= 50;
        }
        break;
    case 'W' :
    case 'w' :
        {
            m_dz += 50;
        }
        break;
    case 'S' :
    case 's' :
        {
            m_dz -= 50;
        }
        break;
    default :
        break;
    }
}

//响应鼠标输入
void camera::mousefunc(int button, int state, int x, int y)
{
    switch (button)
    {
    case 0 :
        m_leftkey = !state;
        break;
    case 1 :
        break;
    case 2 :
        m_rigtkey = !state;
        break;
    default :
        break;
    }

    m_px = x;
    m_py = y;
}

void camera::motion(int x, int y)
{
    if (m_leftkey)
    {
        m_dx += x - m_px;
        m_dy += m_py - y;
    }

    if (m_rigtkey)
    {
        m_ry += (m_px - x) / 5;
        m_rx += (y - m_py) / 5; 
    }

    m_px = x;
    m_py = y;
}

void camera::update()
{
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(0,0,4000, 0,0,0, 0,1,0);
    glTranslatef(m_dx, m_dy, m_dz);
    glRotatef(m_rx, 1, 0 ,0);
    glRotatef(m_ry, 0, 1, 0);

}

planet类实现星球运行

/*planet.h*/

#pragma once

// 星球类
#include "windows.h"
#include <gl/GL.h>
#include "vector"
#include "math.h"
using namespace std;

// 位置结构
struct point
{
    float x;  
    float y;
    float z;

    //构造函数
    point(float _x = 0, float _y = 0, float _z = 0)
        : x(_x), y(_y), z(_z)
    {
    }

    // 单位化,即变为该方向的单位向量)
    void normalize()
    {
        float len = sqrtf(x * x + y * y + z * z);   //计算距离

        //归一化,即用分量除长度
        x /= len;
        y /= len;
        z /= len;
    }
};

// 星体
class planet
{
public :
    planet(point _pos, point _axes_rev, float _size, float _rev_speed, float _rota_speed, bool _sun, const char texname[]);
    virtual ~planet();

    // 公转,自转角度更新
    void update(float timepass);
    // 绘制
    void draw();
    // 加入附属星体,比如8/9大行星都是太阳的附属星体,月亮是地球的附属星体
    void add_secondary(planet* p);
private :
    // 附属星体列表
    vector<planet*> m_secondary;
    // 位置
    point m_pos;
    // 大小
    float m_size;

    // 是否是太阳
    bool m_sun;

    // 公转速度
    float m_rev_speed;
    // 自转速度
    float m_rota_speed;
    // 公转角度
    float m_revolution;
    // 自转角度
    float m_rotation;
    // 自转轴
    point m_axes;
    // 公转轴
    point m_axes_rev;

    // 和太阳的距离
    float m_distance2sun;

    // 纹理
    GLuint m_tex;

};
/*planet.cpp*/
#include "planet.h"
#include "glut.h"
#include <string.h>
#include <stdio.h>
#include "io.h"
#include <gl\GLAux.h>
#include "math.h"
#pragma warning(disable : 4996)


planet::planet(point _pos, point _axes_rev, float _size, float _rev_speed, float _rota_speed, bool _sun, const char texname[])
    : m_pos(_pos), m_axes_rev(_axes_rev), m_size(_size), m_sun(_sun), m_tex(0),
      m_rev_speed(_rev_speed), m_rota_speed(_rota_speed),
     m_revolution(0),m_rotation(0), m_distance2sun(_pos.x),
      m_axes((float)rand() / (float)RAND_MAX, (float)rand() / (float)RAND_MAX, (float)rand() / (float)RAND_MAX)
{
    m_axes.normalize();

    if (access(texname, 0) == -1)
        return;

    // 加载贴图

    AUX_RGBImageRec* irec = auxDIBImageLoad(texname);

    glGenTextures(1, &m_tex);
    glBindTexture(GL_TEXTURE_2D, m_tex);
    glTexImage2D(GL_TEXTURE_2D, 0, 3, irec->sizeX, irec->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, irec->data);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
    glBindTexture(GL_TEXTURE_2D, 0);

    if (irec)
    {
        if (irec->data)
            free(irec->data);
        free(irec);
    }
}

planet::~planet()
{
    for (size_t i = 0; i < m_secondary.size(); ++i)
        delete[] m_secondary[i];
}

// 绘制球体函数
void draw_sphere()
{
    static GLuint uList = 0;
    int x=0;
    int i=0;
    if (uList == 0)
    {

        // 构建球体网格
        point** vs = new point*[37];
        for (int i = 0; i <= 36; ++i)
            vs[i] = new point[37];

        for (x = 0; x <= 36; ++x)
        {
            float ax = 3.141592654f * x * 10 / 180.f;
            point s = point(0, -sinf(ax), cosf(ax) );

            for (int y = 0; y <= 36; ++y)
            {
                point& v = vs[x][y];
                float ay = 3.141592654f * y * 10 / 180.f;
                v.x = s.x * cosf(ay) + s.z * sinf(ay);
                v.y = s.y;
                v.z = s.x * -sinf(ay) + s.z * cosf(ay);
            }
        }

        // 创建显示列表
        uList = glGenLists(1);
        glNewList(uList, GL_COMPILE);
        glBegin(GL_QUADS);
        glColor3f(1, 1, 1);
        for (x = 0; x < 36; ++x)
        {
            for (int y = 0; y < 36; ++y)
            {
                point& a = vs[x][y];
                point& b = vs[x][y + 1];
                point& c = vs[x + 1][y + 1];
                point& d = vs[x + 1][y];

                point na = a;
                point nb = b;
                point nc = c;
                point nd = d;

                na.normalize();
                nb.normalize();
                nc.normalize();
                nd.normalize();

                const float scal = 0.8f;

                glTexCoord2f((a.x * scal + 1) / 2, (a.y * scal + 1) / 2);
                glNormal3f(na.x, na.y, na.z);
                glVertex3f(a.x, a.y, a.z);

                glTexCoord2f((b.x * scal + 1) / 2, (b.y * scal + 1) / 2);
                glNormal3f(nb.x, nb.y, nb.z);
                glVertex3f(b.x, b.y, b.z);

                glTexCoord2f((c.x * scal + 1) / 2, (c.y * scal + 1) / 2);
                glNormal3f(nc.x, nc.y, nc.z);
                glVertex3f(c.x, c.y, c.z);

                glTexCoord2f((d.x * scal + 1) / 2, (d.y * scal + 1) / 2);
                glNormal3f(nd.x, nd.y, nd.z);
                glVertex3f(d.x, d.y, d.z);
            }
        }
        glEnd();
        glEndList();

        for (i = 0; i <= 36; ++i)
            delete[] vs[i];
        delete vs;

    }

    glCallList(uList);

}

void draw_circle()
{
    static GLuint uList = 0;

    if (uList == 0)
    {
        // 创建显示列表

        uList = glGenLists(1);
        glNewList(uList, GL_COMPILE);
        glBegin(GL_LINE_STRIP);
        glColor3f(0.5, 0.5, 0.5);
        for (int x = 0; x <= 36; ++x)
        {
            float ay = 3.141592654f * x * 10 / 180.f;
            point v;
            v.x = sinf(ay);
            v.y = 0;
            v.z = cosf(ay);

            glVertex3f(v.x, v.y, v.z);
        }
        glEnd();
        glEndList();
    }

    glCallList(uList);
}

//更新自传角度和公转角度
void planet::update(float timepass)
{
   m_revolution += timepass * m_rev_speed;
   m_rotation += timepass * m_rota_speed;

    for (size_t i = 0; i < m_secondary.size(); ++i)
        m_secondary[i]->update(timepass);
}

void planet::draw()
{
    if (m_sun)
    {
        // 绘制各个附属太阳的行星的轨道
        glDisable(GL_LIGHTING);
        glDisable(GL_TEXTURE_2D);
        for (size_t i = 0; i < m_secondary.size(); ++i)
        {
            glPushMatrix();
            glScalef(m_secondary[i]->m_distance2sun, m_secondary[i]->m_distance2sun, m_secondary[i]->m_distance2sun);
            draw_circle();
            glPopMatrix();
        }

        glEnable(GL_TEXTURE_2D);

    }
    else
        glEnable(GL_LIGHTING);

    // 绘制星体
    glPushMatrix();
    glRotatef(m_revolution, m_axes_rev.x, m_axes_rev.y, m_axes_rev.z);
    glTranslatef(m_pos.x, m_pos.y, m_pos.z);
    glPushMatrix();
    glRotatef(m_rotation, m_axes.x, m_axes.y, m_axes.z);
    glScalef(m_size, m_size, m_size);
    glBindTexture(GL_TEXTURE_2D, m_tex);
    draw_sphere();
    glBindTexture(GL_TEXTURE_2D, 0);
    glPopMatrix();

    // 绘制附属星体
    for (size_t i = 0; i < m_secondary.size(); ++i)
        m_secondary[i]->draw();

    glPopMatrix();

    glDisable(GL_LIGHTING);

}

void planet::add_secondary(planet* p)
{
    m_secondary.push_back(p);
}

主函数

#include <stdio.h>
#include <gl\GLAux.h>
#include "glut.h"
#include "math.h"
#include "camera.h"
#include "planet.h"
#include "background.h"

#pragma comment(lib, "glaux.lib")

// 窗口大小
#define VIEWWEIGHT 600
#define VIEWHIGHT  500 

// 相机
camera cameraobj;
// 宇宙背景
background bk;

// 太阳
planet* solar = 0;

void Display(void)
{
    static DWORD ptime = GetTickCount();
    DWORD ntime = GetTickCount();

    glClear(GL_DEPTH_BUFFER_BIT);
    // 更新相机
    cameraobj.update();
    // 绘制背景
    bk.draw();

    // 绘制太阳及其附属行星
    if (solar)
    {
        solar->update((float)(ntime - ptime) / 1000.f);
        glEnable(GL_TEXTURE_2D);
        solar->draw();
        glDisable(GL_TEXTURE_2D);
    }

    ptime = ntime;

    glutSwapBuffers();

}

void Run()
{   
    Display();
}

void KeyboardFunc(unsigned char key,int x, int y)
{
    cameraobj.keyfunc(key);
}

void Init()
{
    glShadeModel(GL_SMOOTH);
    glEnable(GL_CULL_FACE);
    glFrontFace(GL_CCW);
    glCullFace(GL_BACK);
    glEnable(GL_DEPTH_TEST);

    // 初始化光照
    glEnable(GL_NORMALIZE);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    float amb[4]={0.2,0.2,0.2,1};    //
    float dif[4]={1.0,1.0,1.0,1};    //方向向量
    float pos[4]={0,0,0,1};          //原点


    glLightfv(GL_LIGHT0,GL_AMBIENT,amb);
    glLightfv(GL_LIGHT0,GL_DIFFUSE,dif);
    glLightfv(GL_LIGHT0,GL_SPECULAR,dif);
    glLightfv(GL_LIGHT0,GL_POSITION,pos);
    glLightModelfv(GL_LIGHT_MODEL_AMBIENT, amb);
    glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, TRUE);

    glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, dif);
    glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, dif);
    glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, dif);
    glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 128);

    // 初始化背景
    bk.Init();

    // 初始化太阳系
    solar = new planet(point(0, 0, 0), point(0, 1, 0), 300, 0, 10, true, "tex\\sun.bmp");
    solar->add_secondary(new planet(point(400, 0, 0), point(0, 1, 0), 40, 10, 20, false, "tex\\p1.bmp"));
    solar->add_secondary(new planet(point(580, 0, 0), point(0, 1, 0), 60, 20, 30, false, "tex\\p2.bmp"));
    planet* ear = new planet(point(750, 0, 0), point(0, 1, 0), 55, 30, 40, false, "tex\\ear.bmp");
    ear->add_secondary(new planet(point(100, 0, 0), point(1, 1, 0), 10, 200, 40, false, "tex\\moon.bmp"));
    solar->add_secondary(ear);
    solar->add_secondary(new planet(point(890, 0, 0), point(0, 1, 0), 50, 35, 25, false, "tex\\p4.bmp"));
    solar->add_secondary(new planet(point(1200, 0, 0), point(0, 1, 0), 120, 15, 50, false, "tex\\p5.bmp"));
    solar->add_secondary(new planet(point(1500, 0, 0), point(0, 1, 0), 100, 50, 30, false, "tex\\p6.bmp"));
    solar->add_secondary(new planet(point(1800, 0, 0), point(0, 1, 0), 90, 20, 35, false, "tex\\p7.bmp"));
    solar->add_secondary(new planet(point(2050, 0, 0), point(0, 1, 0), 90, 40, 20, false, "tex\\p8.bmp"));

#if 0
    printf("太阳系模拟程序\n\n");
    printf("键盘 A   : 左移\n");
    printf("键盘 D   : 右移\n");
    printf("键盘 W   : 前移\n");
    printf("键盘 S   : 后移\n");
    printf("鼠标左键 : 平移\n");
    printf("鼠标右键 : 旋转\n");
#endif
}

void UnInit()
{
    if (solar)
        delete solar;
}

void Reshape(int w,int h)
{
    glViewport(0,0,w,h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(45,GLfloat(w)/h,1,50000);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    glClearDepth(1.0f);
    glEnable(GL_DEPTH_TEST);
}

void MouseFunc(int button, int state, int x, int y)
{
    cameraobj.mousefunc(button, state, x, y);
}

void MotionFunc(int x, int y)
{
    cameraobj.motion(x, y);
}

int main(int argc, char *argv[])
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
    glutInitWindowPosition(100, 100);
    glutInitWindowSize(VIEWWEIGHT, VIEWHIGHT);
    glutCreateWindow("太阳系");
    glutDisplayFunc(&Display);
    glutIdleFunc(&Run);
    glutReshapeFunc(&Reshape);
    glutKeyboardFunc(&KeyboardFunc);
    glutMouseFunc(&MouseFunc);           //注册鼠标响应函数
    glutMotionFunc(&MotionFunc);

    Init();
    glutMainLoop();    //主消息循环
    UnInit();

    return 0;
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值