zoukankan      html  css  js  c++  java
  • 烟花OpenGL初步实现demo

    在NeHe程序框架基础上初步实现了这个烟花的demo。

    烟花的弹片生存期由life和fade两个值决定。

    烟花的弹片速度由speed和a两个值决定。

    生命值和速度值变换在每次循环中加减运算实现,所以有必要添加一个参数来根据每台电脑的运算速度加以调整优化。

    实现代码如下。所需BMP图片在这里

    //vs2008 & windows7
    #include<windows.h>
    #include<tchar.h>
    #include <gl\gl.h>
    #include <gl\glu.h>
    #pragma comment(lib,"opengl32.lib")
    #pragma comment(lib,"glu32.lib")

    #define MAX_NUM_PARTICLES 20 //粒子数
    #define MAX_NUM_SHELLS 40 //弹片数

    HGLRC hRC=NULL; //OpenGL图形操作描述表
    HDC hDC=NULL; //设备描述表
    HWND hWnd=NULL; //窗口句柄
    HINSTANCE hInstance; //应用程序实例

    bool keys[256]; //键盘按键参数阵列
    bool active=TRUE; //窗口是否活动
    bool fullscreen=TRUE; //是否全屏

    bool rainbow=false; //彩虹模式,改变颜色
    bool sp; //空格键击键标志
    bool rp; //回车键击键标志

    float slowdown=1.0f; //粒子减速控制
    float zoom=-55.0f; //视野变焦

    GLuint loop,loop2,color,delay; //循环参数、当前颜色、延迟
    GLuint texture[1]; //粒子贴图

    float shell_life=5.0f; //弹片高度
    float shell_fade=0.05f;
    float shell_life1=4.0f; //弹片高度
    float shell_fade1=0.05f;
    float sxspeed=0.0f; //弹片速度
    float szspeed=0.0f;
    float syspeed=850.0f;
    float shell_yg=-4.8f;

    float particle_life=2.0f; //粒子高度
    float particle_fade;
    float xspeed; //粒子速度
    float yspeed;
    float zspeed;
    float particle_yg=-2.8f;

    float par_times=2.0f; //速度倍数
    float par_times1=10.0f;

    float x,y,z;
    float x1,y1,z1;

    typedef struct
    {
    bool active; //状态,生存or湮灭
    float life; //粒子生命
    float fade; //衰减速度
    float r,g,b; //颜色
    float x,y,z; //当前位置
    float xd,yd,zd; //速度
    float xg,yg,zg; //加速度 a=1-p[空气]/p[物质]
    }particle; //粒子结构

    typedef struct
    {
    bool active; //状态,生存or湮灭
    float life; //粒子生命
    float fade; //衰减速度
    unsigned int status; //阶段
    float x,y,z; //当前位置
    float xd,yd,zd; //速度
    float xg,yg,zg; //加速度 a=1-p[空气]/p[物质]
    particle particles[MAX_NUM_PARTICLES]; //颗粒
    }shell; //弹片

    shell shells[MAX_NUM_SHELLS]; //弹体

    static GLfloat colors[4][3]= // 颜色值
    {
    {1.0f,1.0f,1.0f},{1.0f,0.0f,0.0f},{1.0f,1.0f,0.0f},{1.0f,0.0f,1.0f}
    };
    //
    LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //消息处理函数
    bool NeHeLoadBitmap(LPTSTR szFileName, GLuint *texid); //贴图图像载入
    GLvoid ReSizeGLScene(GLsizei width, GLsizei height); //重新绘制窗口
    int InitGL(GLvoid); //初始化OpenGL
    int DrawGLScene(GLvoid); //画图
    GLvoid KillGLWindow(GLvoid) ; //关闭窗口
    //
    bool NeHeLoadBitmap(LPTSTR szFileName, GLuint *texid) //从一个bmp文件创建贴图
    {
    HBITMAP hBMP; //bmp文件句柄
    BITMAP BMP; // Bitmap数据结构
    glGenTextures(1, texid); // 创建贴图
    hBMP=(HBITMAP)LoadImage(GetModuleHandle(NULL), szFileName, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_LOADFROMFILE );
    if (!hBMP)
    return FALSE;
    GetObject(hBMP, sizeof(BMP), &BMP); //获得目标
    glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // Pixel Storage Mode (Word Alignment / 4 Bytes)
    //创建贴图
    glBindTexture(GL_TEXTURE_2D, *texid);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexImage2D(GL_TEXTURE_2D, 0, 3, BMP.bmWidth, BMP.bmHeight, 0, GL_BGR_EXT, GL_UNSIGNED_BYTE, BMP.bmBits);
    DeleteObject(hBMP);
    return TRUE;
    }//end of NeHeLoadBitmap

    GLvoid ReSizeGLScene(GLsizei width, GLsizei height) //重画窗口
    {
    if (height==0) height=1;
    glViewport(0, 0, width, height); //重置当前窗口
    glMatrixMode(GL_PROJECTION); // Select The Projection Matrix
    glLoadIdentity(); // Reset The Projection Matrix
    gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,200.0f); //视图
    glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix
    glLoadIdentity(); // Reset The Modelview Matrix
    }//end of ReSizeGLScene

    int InitGL(GLvoid) //初始化gl
    {
    if (!NeHeLoadBitmap(_T("Data\\Particle.bmp"), &texture[0])) {return FALSE; }//载入贴图
    glShadeModel(GL_SMOOTH); // Enables Smooth Shading
    glClearColor(0.0f,0.0f,0.0f,0.0f); // Black Background
    glClearDepth(1.0f); // Depth Buffer Setup
    glDisable(GL_DEPTH_TEST); // Disables Depth Testing
    glEnable(GL_BLEND); // Enable Blending
    glBlendFunc(GL_SRC_ALPHA,GL_ONE); // Type Of Blending To Perform
    glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST); // Really Nice Perspective Calculations
    glHint(GL_POINT_SMOOTH_HINT,GL_NICEST); // Really Nice Point Smoothing
    glEnable(GL_TEXTURE_2D); // Enable Texture Mapping
    glBindTexture(GL_TEXTURE_2D,texture[0]); // Select Our Texture

    for(loop2=0;loop2<MAX_NUM_SHELLS;loop2++)
    {
    shells[loop2].active=true;
    shells[loop2].status=0; //0-上升阶段
    shells[loop2].life=shell_life1;
    // shells[loop2].fade=float(rand()%100)/1000.0f+0.003f;
    shells[loop2].fade=shell_fade1;
    shells[loop2].xd=float((rand()%50)-25.0f)*par_times1;
    shells[loop2].yd=float((rand()%50)-25.0f)*par_times1;
    shells[loop2].zd=float((rand()%50)-25.0f)*par_times1;
    shells[loop2].xg=0.0f;
    shells[loop2].yg=shell_yg;
    shells[loop2].zg=0.0f;
    for (loop=0;loop<MAX_NUM_PARTICLES;loop++) // 初始化所有贴图
    {
    shells[loop2].particles[loop].active=true; // 使所有粒子为活动
    shells[loop2].particles[loop].life=particle_life; // 所有粒子生命值
    shells[loop2].particles[loop].fade=float(rand()%100)/100.0f+0.03f; // 随机生命递减速度
    shells[loop2].particles[loop].r=colors[color][0]; //颜色
    shells[loop2].particles[loop].g=colors[color][1];
    shells[loop2].particles[loop].b=colors[color][2];
    shells[loop2].particles[loop].xd=float((rand()%50)-25.0f)*par_times; //随机速度
    shells[loop2].particles[loop].yd=float((rand()%50)-25.0f)*par_times;
    shells[loop2].particles[loop].zd=float((rand()%50)-25.0f)*par_times;
    shells[loop2].particles[loop].xg=0.0f; //加速度
    shells[loop2].particles[loop].yg=particle_yg;
    shells[loop2].particles[loop].zg=0.0f;
    }
    }
    shells[0].life=shell_life;
    shells[0].fade=shell_fade;
    return TRUE;
    }//end of InitGL

    int DrawGLScene(GLvoid) //画图
    {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer
    glLoadIdentity(); // Reset The Current Modelview Matrix

    switch(shells[0].status)
    {
    case 0: //上升阶段
    {
    if(shells[0].life==shell_life)
    {
    shells[0].x=0.0f;
    shells[0].y=-30.0f;
    shells[0].z=zoom;
    shells[0].xd=sxspeed; //获得初始速度
    shells[0].yd=syspeed;
    shells[0].zd=szspeed;
    //
    for(loop=0;loop<MAX_NUM_PARTICLES;loop++)
    {
    shells[0].particles[loop].x=shells[0].x;
    shells[0].particles[loop].y=shells[0].y;
    shells[0].particles[loop].z=shells[0].z;
    }
    }//if life
    shells[0].x+=shells[0].xd/(slowdown*1000); //新位置
    shells[0].y+=shells[0].yd/(slowdown*1000);
    shells[0].z+=shells[0].zd/(slowdown*1000);
    shells[0].xd+=shells[0].xg; //速度增量
    shells[0].yd+=shells[0].yg;
    shells[0].zd+=shells[0].zg;
    shells[0].life-=shells[0].fade; //生命递减
    if(shells[0].life<0.0f)
    {
    shells[0].status=1; //转到下一个阶段
    shells[0].active=false;
    x1=shells[0].x;
    y1=shells[0].y;
    z1=shells[0].z;
    break;
    }

    for(loop=0;loop<MAX_NUM_PARTICLES;loop++)
    {
    if(shells[0].particles[loop].active)
    {
    shells[0].particles[loop].x+=shells[0].particles[loop].xd/(slowdown*1000); //位置改变
    shells[0].particles[loop].y+=shells[0].particles[loop].yd/(slowdown*1000);
    shells[0].particles[loop].z+=shells[0].particles[loop].zd/(slowdown*1000);
    shells[0].particles[loop].xd+=shells[0].particles[loop].xg; //速度增量
    shells[0].particles[loop].yd+=shells[0].particles[loop].yg;
    shells[0].particles[loop].zd+=shells[0].particles[loop].zg;
    shells[0].particles[loop].life-=shells[0].particles[loop].fade; //生命减少

    x=shells[0].particles[loop].x; //获得位置坐标
    y=shells[0].particles[loop].y;
    z=shells[0].particles[loop].z+zoom;
    glColor4f(shells[0].particles[loop].r,shells[0].particles[loop].g,shells[0].particles[loop].b,shells[0].particles[loop].life); //颜色
    glBegin(GL_TRIANGLE_STRIP); //两个三角画一个矩形
    glTexCoord2d(1,1);glVertex3f(x+0.5f,y+0.5f,z);
    glTexCoord2d(0,1);glVertex3f(x-0.5f,y+0.5f,z);
    glTexCoord2d(1,0); glVertex3f(x+0.5f,y-0.5f,z);
    glTexCoord2d(0,0); glVertex3f(x-0.5f,y-0.5f,z);
    glEnd();

    if(shells[0].particles[loop].life<0.0f) //湮灭
    {
    shells[0].particles[loop].life=particle_life; //获得新生
    shells[0].particles[loop].fade=float(rand()%100)/100.0f+0.03f; //生命递减速度
    shells[0].particles[loop].x=shells[0].x; //新生粒子位置与弹片位置相同
    shells[0].particles[loop].y=shells[0].y;
    shells[0].particles[loop].z=shells[0].z;
    shells[0].particles[loop].xd=xspeed+float((rand()%50)-25.0f)*par_times; //初始速度
    shells[0].particles[loop].yd=yspeed+float((rand()%50)-25.0f)*par_times;
    shells[0].particles[loop].zd=zspeed+float((rand()%50)-25.0f)*par_times;
    shells[0].particles[loop].r=colors[color][0]; //粒子颜色,用参数color改变
    shells[0].particles[loop].g=colors[color][1];
    shells[0].particles[loop].b=colors[color][2];
    }//end of if life

    }//end of if active
    }//end of for loop
    break;
    }//end of case 0:
    case 1:
    {
    if(shells[0].active==false)
    {
    shells[0].active=true;
    for(loop2=1;loop2<MAX_NUM_SHELLS;loop2++)
    {
    shells[loop2].x=x1;
    shells[loop2].y=y1;
    shells[loop2].z=z1;
    }
    }//if !
    for(loop2=1;loop2<MAX_NUM_SHELLS;loop2++)
    {
    // if(shells[loop2].life>0.0f)
    // {
    for(loop=0;loop<MAX_NUM_PARTICLES;loop++)
    {
    if(shells[loop2].life==shell_life1)
    {
    shells[loop2].particles[loop].x=shells[loop2].x;
    shells[loop2].particles[loop].y=shells[loop2].y;
    shells[loop2].particles[loop].z=shells[loop2].z;
    }
    shells[loop2].particles[loop].x+=shells[loop2].particles[loop].xd/(slowdown*1000); //位置改变
    shells[loop2].particles[loop].y+=shells[loop2].particles[loop].yd/(slowdown*1000);
    shells[loop2].particles[loop].z+=shells[loop2].particles[loop].zd/(slowdown*1000);
    shells[loop2].particles[loop].xd+=shells[loop2].particles[loop].xg; //速度增量
    shells[loop2].particles[loop].yd+=shells[loop2].particles[loop].yg;
    shells[loop2].particles[loop].zd+=shells[loop2].particles[loop].zg;
    shells[loop2].particles[loop].life-=shells[loop2].particles[loop].fade; //生命减少

    x=shells[loop2].particles[loop].x; //获得位置坐标
    y=shells[loop2].particles[loop].y;
    z=shells[loop2].particles[loop].z+zoom;
    glColor4f(shells[loop2].particles[loop].r,shells[loop2].particles[loop].g,shells[loop2].particles[loop].b,shells[loop2].particles[loop].life); //颜色
    glBegin(GL_TRIANGLE_STRIP); //两个三角画一个矩形
    glTexCoord2d(1,1);glVertex3f(x+0.5f,y+0.5f,z);
    glTexCoord2d(0,1);glVertex3f(x-0.5f,y+0.5f,z);
    glTexCoord2d(1,0); glVertex3f(x+0.5f,y-0.5f,z);
    glTexCoord2d(0,0); glVertex3f(x-0.5f,y-0.5f,z);
    glEnd();

    if(shells[loop2].particles[loop].life<0.0f) //湮灭
    {
    shells[loop2].particles[loop].life=particle_life; //获得新生
    shells[loop2].particles[loop].fade=float(rand()%100)/100.0f+0.03f; //生命递减速度
    shells[loop2].particles[loop].x=shells[loop2].x;
    shells[loop2].particles[loop].y=shells[loop2].y;
    shells[loop2].particles[loop].z=shells[loop2].z;
    shells[loop2].particles[loop].xd=xspeed+float((rand()%50)-25.0f)*par_times; //初始速度
    shells[loop2].particles[loop].yd=yspeed+float((rand()%50)-25.0f)*par_times;
    shells[loop2].particles[loop].zd=zspeed+float((rand()%50)-25.0f)*par_times;
    shells[loop2].particles[loop].r=colors[color][0]; //粒子颜色,用参数color改变
    shells[loop2].particles[loop].g=colors[color][1];
    shells[loop2].particles[loop].b=colors[color][2];
    }
    }//for loop
    // }//if life
    shells[loop2].x+=shells[loop2].xd/(slowdown*1000); //新位置
    shells[loop2].y+=shells[loop2].yd/(slowdown*1000);
    shells[loop2].z+=shells[loop2].zd/(slowdown*1000);
    shells[loop2].xd+=shells[loop2].xg; //速度增量
    shells[loop2].yd+=shells[loop2].yg;
    shells[loop2].zd+=shells[loop2].zg;
    shells[loop2].life-=shells[loop2].fade; //生命递减
    if(shells[1].life<0.0f){shells[1].status=1;}
    }//for loop2
    break;
    }//end of case 1:
    default:
    break;
    }//end of switch

    if (keys[VK_TAB]||shells[1].status==1) //TAB发射一颗新烟花弹
    {
    shells[0].life=shell_life;
    shells[0].status=0;
    for(loop2=0;loop2<MAX_NUM_SHELLS;loop2++)
    {
    shells[loop2].active=true;
    shells[loop2].status=0; //0-上升阶段
    shells[loop2].life=shell_life1;
    // shells[loop2].fade=float(rand()%100)/1000.0f+0.003f;
    shells[loop2].fade=shell_fade1;
    shells[loop2].xd=float((rand()%50)-25.0f)*par_times1;
    shells[loop2].yd=float((rand()%50)-25.0f)*par_times1;
    shells[loop2].zd=float((rand()%50)-25.0f)*par_times1;
    shells[loop2].xg=0.0f;
    shells[loop2].yg=shell_yg;
    shells[loop2].zg=0.0f;
    for (loop=0;loop<MAX_NUM_PARTICLES;loop++) // 初始化所有贴图
    {
    shells[loop2].particles[loop].active=true; // 使所有粒子为活动
    shells[loop2].particles[loop].life=particle_life; // 所有粒子生命值
    shells[loop2].particles[loop].fade=float(rand()%100)/100.0f+0.03f; // 随机生命递减速度
    shells[loop2].particles[loop].r=colors[color][0]; //颜色
    shells[loop2].particles[loop].g=colors[color][1];
    shells[loop2].particles[loop].b=colors[color][2];
    shells[loop2].particles[loop].xd=float((rand()%50)-25.0f)*par_times; //随机速度
    shells[loop2].particles[loop].yd=float((rand()%50)-25.0f)*par_times;
    shells[loop2].particles[loop].zd=float((rand()%50)-25.0f)*par_times;
    shells[loop2].particles[loop].xg=0.0f; //加速度
    shells[loop2].particles[loop].yg=particle_yg;
    shells[loop2].particles[loop].zg=0.0f;
    }
    }
    shells[0].life=shell_life;
    shells[0].fade=shell_fade;
    }//if

    return TRUE;
    }//end of DrawGLScene

    <完>

  • 相关阅读:
    [MSDN] How to Debug a Release Build
    抽象成员 虚方法
    强制类型转换符 和 as 运算符
    一份超长的MySQL学习笔记
    Java反射基础
    c3p0config.xml
    一个JDBC封装工具类
    Spring5——IOC操作Bean管理(基于xml文件)
    Android游戏开发大全
    移除项目里的所有.svn命令
  • 原文地址:https://www.cnblogs.com/afarmer/p/1611257.html
Copyright © 2011-2022 走看看