爆炸特效

18 篇文章 0 订阅
11 篇文章 0 订阅


//新建一个win32应用程序项目,选择空项目,然后在项目资源中的source添加一个爆炸.cpp
//========================================
            爆炸.cpp
#include <iostream>
#define GLUT_DISABLE_ATEXIT_HACK
#include<Windows.h>
#include<stdio.h>
#include<GL/GLUT.H>
#include<GLAUX.H>
#include<math.h>
#include<tchar.h>
#pragma comment(lib,"opengl32.lib")
#pragma comment(lib,"glu32.lib")
#pragma comment(lib,"glaux.lib")
HDC hDC = NULL;//设备上下文
HGLRC hRC = NULL;//着色描述表
HWND hWnd = NULL;//窗口句柄
HINSTANCE hInstance;//程序实例句柄

bool keys[256];//按键状态
bool active = TRUE;//窗口激活状态
bool fullscreen = TRUE;//全屏模式标记

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);//整口过程,opengl程序内所有消息都在这里响应
//以上是我们实现了一个OpenGL窗口,
//以下是我们在这个窗口中做点儿事情。
//做出爆炸的效果。
#define MAX_PARTICLES 1500                       //粒子数
bool rainbow = true, sp, rp;
float slowdown = 2.0f, xspeed, yspeed, zoom = -40.0f;
GLuint k, col, delay, texture[1];
typedef struct                                     //定义结构体类型,对粒子特性进行详细描述。
{
 bool active;
 float life;
 float fade;
 float r;
 float g;
 float b;
 float x;
 float y;
 float z;
 float xi;
 float yi;
 float zi;
 float xg;
 float yg;
 float zg;
}particles;                   //结构体变量名
particles particle[MAX_PARTICLES];             //结构数组,装载粒子
static GLfloat colors[12][3]=
{
 { 1.0f, 0.5f, 0.5f }, { 1.0f, 0.75f, 0.5f }, { 1.0f, 1.0f, 0.5f }, { 0.75f, 1.0f, 0.5f },
 { 0.5f, 1.0f, 0.5f }, { 0.5f, 1.0f, 0.75f }, { 0.5f, 1.0f, 1.0f }, { 0.5f, 0.75f, 1.0f },
 { 0.5f, 0.5f, 1.0f }, { 0.75f, 0.5f, 1.0f }, { 1.0f, 0.5f, 1.0f }, { 1.0f, 0.5f, 0.75f }
};
//以下格式非常重要
AUX_RGBImageRec *LoadBMP(WCHAR *Filename)    // 载入位图资源,读取纹理图像函数。

{
 HANDLE  File;       //文件句柄
 if (!Filename)          // 检查文件名是否正确
 {
  return NULL;         //不存在的话返回失败
 }
 WCHAR *strFilePathTemp;//存储文件路径
 int FILEPATHSIZE=2048;//文件路径长度
 strFilePathTemp=(WCHAR *)calloc(FILEPATHSIZE,sizeof(WCHAR));//初始化文件路径
 File=CreateFile(strFilePathTemp, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);//打开位图文件,读取位图信息
 if (File)           //检查文件是否存在
 {
  CloseHandle(File);       // 信息已经获取,关闭文件设备句柄
  return auxDIBImageLoadW(Filename);    // 成功返回文件信息
 }
 return NULL;          // 紧接着上面的判断,失败的话返回NULL
}


int LoadGLTexture()                                //读取图像
{
 int Status = FALSE;                            //读取状态标记
 AUX_RGBImageRec *TextureImage[1];              //创建一个纹理空间存储纹理信息
 memset(TextureImage, 0, sizeof(void *)* 1);    //首先清空存储空间
 if (TextureImage[0] = LoadBMP(L"Image/par.bmp")) //载入图片纹理,图片放在可执行文件的同一目录下,调试状态下放在debug同一目录
 {
  Status = TRUE;                               //  如果载入成功设置状态位为真
  glGenTextures(1, &texture[0]);               //创建纹理
  glBindTexture(GL_TEXTURE_2D, texture[0]);    //使用位图资源生成纹理
  //生成纹理
  glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);
 
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);//线性滤波方式
 }
 
 //纹理生成成功后要释放资源,这个非常重要。
 if (TextureImage[0])
 {
  if (TextureImage[0]->data)
  {
   free(TextureImage[0]->data);
  }
  free(TextureImage[0]);
 }
 return Status;
}
GLvoid ReSizeGLScreen(GLsizei width, GLsizei height) //当窗口大小改变时进行窗口窗调
{
 //glRotatef(60, 0.0f, 1.0f, 0.0f);               //“粒子”旋转。
 if (height == 0)
 {
  height = 1;                                  //防止被零除,因为在调整窗口大小时,为不改变窗口内容的显示效果
                                               //(原来在左上角的东东调整后还在左上角。。。),
                                               //利用的是窗口宽度与高度的比例进行调整的(width/height)
 }

 glViewport(0, 0, width, height);                 //重新调整当前视口

 glMatrixMode(GL_PROJECTION);                     //选择投影矩阵
 glLoadIdentity();                                //重置投影矩阵
 gluPerspective(45.0f, (GLfloat)width / (GLfloat)height, 0.1f, 100.0f);//选择模型观察矩阵
 glMatrixMode(GL_MODELVIEW);// 选择模型观察矩阵
 glLoadIdentity();//重置模型观察矩阵
}

int InitGL(GLvoid)
{
 if (!LoadGLTexture())
 {
  return FALSE;
 }
 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
 glEnable(GL_BLEND);                                       
 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
 //如果把以上两句改成注释,那么程序运行后会出现球状“粒子”向四处飞去的情形。

 glEnable(GL_TEXTURE_2D);                        //启用纹理映射
 for (k = 0; k < MAX_PARTICLES; k++)
 {
  particle[k].life = 1.0f;
  particle[k].fade = float(rand() % 100) / 1000.0f + 0.003f;
  particle[k].r = colors[k*(12 / MAX_PARTICLES)][0];
  particle[k].g = colors[k*(12 / MAX_PARTICLES)][0];
  particle[k].b = colors[k*(12 / MAX_PARTICLES)][0];
  particle[k].xi = float((rand() % 50) - 26.0f)*10.0f;
  particle[k].yi = float((rand() % 50) - 25.0f)*10.0f;
  particle[k].zi = float((rand() % 50) - 25.0f)*10.0f;
  particle[k].xg = 0.0f;
  particle[k].yg = -0.8f;
  particle[k].zg = 0.0f;
 }
 glShadeModel(GL_SMOOTH);//启用阴影平滑
 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);//设置清屏颜色(类似于win32c程序的背景色)
 glClearDepth(1.0f);//设置深度缓存
 glEnable(GL_DEPTH_TEST);//启用深度测试
 glDepthFunc(GL_LEQUAL);//选择深度测试类型
 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);//修正透视(如果有必要的话)
 return TRUE;
}
int DrawGLScene(GLvoid)
{
 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);     //清除颜色缓存和深度缓存,防止交叉重复。
 glLoadIdentity();                                       // 重置模型观察矩阵,使屏幕中心点位于三维坐标原点(0, 0,0)
 for (k = 0; k < MAX_PARTICLES; k++)
 {
  float x = particle[k].x;
  float y = particle[k].y;
  float z = particle[k].z + zoom;

  glRotatef(90.0, 0.0f, 0.0f, 1.0f);
  glRotatef(10, 0.0f, 1.0f, 0.0f);
  //以上两句旋转函数,控制会出的图元旋转,以实现有趣的效果。


  glColor4f(particle[k].r, particle[k].g, particle[k].b, particle[k].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();
  particle[k].x += particle[k].xi / (slowdown * 1000);
  particle[k].y += particle[k].yi / (slowdown * 1000);
  particle[k].z += particle[k].zi / (slowdown * 1000);
  particle[k].xi += particle[k].xg;
  particle[k].yi += particle[k].yg;
  particle[k].zi += particle[k].zg;
  //particle[k].life -= particle[k].fade;
  /*把语句particle[k].life-=particle[k].fade修改为particle[k].life-=0.2*particle[k].fade;
  那么粒子的存活时间增加,爆炸残片停留时间变长,爆炸片较多,像烟花。*/
  particle[k].life -= 0.2*particle[k].fade;
  //如果把上一句该为注释,那么所有的粒子都在飞行,直到远离。
 }
 return TRUE;
}
//下面的函数处理窗口销毁,释放一些资源,如果不处理,就会泄露,导致CPU工作异常
GLvoid KillGLWindow(GLvoid)
{
 if (fullscreen)
 {
  ChangeDisplaySettings(NULL, 0);//Nehe教程是这样解释的:
  /*我们使用ChangeDisplaySettings(NULL,0)回到原始桌面。将NULL作为第一个参数,
  0作为第二个参数传递强制Windows使用当前存放在注册表中的值(缺省的分辨率、色彩深度、刷新频率,等等)
  来有效的恢复我们的原始桌面。切换回桌面后,我们还要使得鼠标指针重新可见。*/
  ShowCursor(TRUE);//显示光标
 }

 /*判断是否拥有渲染描述表,这里解释下什么是DC,RC,我们知道,opengl工作强烈依赖于计算机的显卡(显示器),
 显卡是一种设备,外部程序访问设备,然后让CPU去处理,就必须找到设备的接口,
 这里的DC(着色描述表)和RC(渲染描述表)其实是与显示器相关的一个内存字段,
 我们就是通过他们来访问显卡设备,然后对其进行操作的(个人的见解,可能有错误)*/
 if (hRC)
 {
  if (!wglMakeCurrent(NULL, NULL))
  {
   MessageBox(NULL, TEXT("Release Of DC And RC Failed."), TEXT("SHUTDOWN ERROR"), MB_OK | MB_ICONINFORMATION);
  }
  if (!wglDeleteContext(hRC))
  {
   MessageBox(NULL, TEXT("Release Rendering Context Failed."), TEXT("SHUTDOWN ERROR"), MB_OK | MB_ICONINFORMATION);
  }
  hRC = NULL;
 }
 if (hDC&&!ReleaseDC(hWnd, hDC))
 {
  MessageBox(NULL, TEXT("Release Device Context Failed."), TEXT("SHUTDOWN ERROR"), MB_OK | MB_ICONINFORMATION);
  hDC = NULL;
 }
 if (hWnd&&!DestroyWindow(hWnd))
 {
  MessageBox(NULL, TEXT("Could Not Release hWnd."), TEXT("SHUTDOWN ERROR"), MB_OK | MB_ICONINFORMATION);
  hWnd = NULL;
 }
 if (!UnregisterClass(TEXT("OpenGL"), hInstance))
 {
  MessageBox(NULL, TEXT("Could Not Unregister Class."), TEXT("SHUTDOWN ERROR"), MB_OK | MB_ICONINFORMATION);
  hInstance = NULL;
 }
}
BOOL CreateGLWindow(TCHAR * title, int width, int height, int bits, bool fullscreenflag)
{
 GLuint PixelFormat;                //像素模式
 WNDCLASS wc;                       //窗口类
 DWORD dwExStyle;                   //扩展的窗口模式
 DWORD dwStyle;                     //窗口模式
 RECT WindowRect;                   //窗口大小
 WindowRect.left = (long)0;
 WindowRect.right = (long)width;
 WindowRect.top = (long)0;
 WindowRect.bottom = (long)height;
 fullscreen = fullscreenflag;       //显示模式标志
 hInstance = GetModuleHandle(NULL); //获取主调进程的实例句柄
 wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;   //设置窗口类型
 wc.lpfnWndProc = (WNDPROC)WndProc;               //关联窗口过程
 wc.cbClsExtra = 0;
 wc.cbWndExtra = 0;
 wc.hInstance = hInstance;
 wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);          //设置图标
 wc.hCursor = LoadCursor(NULL, IDC_ARROW);        //设置光标
 wc.hbrBackground = NULL;                         //没有背景,因为上面已经设置了窗口背
 wc.lpszMenuName = NULL;                          //没有菜单,当然你也可以设置菜单
 wc.lpszClassName = TEXT("OpenGL");               //窗口类名,此时为OpenGL
 if (!RegisterClass(&wc))
 {
  MessageBox(NULL, TEXT("Failed To Register The Window Class."), TEXT("ERROR"), MB_OK | MB_ICONEXCLAMATION);
  return FALSE;
 }
 if (fullscreen)                         //判断是否处于全屏模式,是的话,进行一下处理
 {
  DEVMODE dmScreenSettings;           //设备模式
  //清零,当用户多次选择全屏时,都会执行这里的代码,但我们并不知道我们所申请的内存是否可用,所以每次进来都要清零
  memset(&dmScreenSettings, 0, sizeof(dmScreenSettings));
  //初始化
  dmScreenSettings.dmSize = sizeof(dmScreenSettings);          //dmScreenSettings结构大小
  dmScreenSettings.dmPaperWidth = width;                       //屏幕宽度
  dmScreenSettings.dmPelsHeight = height;                      //屏幕高度
  dmScreenSettings.dmBitsPerPel = bits;                        //每位像素的色彩深度
  dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;//设置设备相关量,包括宽度,色彩深度,高度。
  //尝试设置显示模式并返回结果。注: CDS_FULLSCREEN 移去了状态条。
  if (ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)

  {
   //如果失败,让用户区处理选择
   if (MessageBox(NULL, TEXT("您当前PC不支持全屏模式,确定是否使用窗口模式!"), TEXT("提示"), MB_YESNO | MB_ICONEXCLAMATION) == IDYES)
   {
    fullscreen = FALSE;
   }
   else
   {
    MessageBox(NULL, TEXT("应用程序即将推出"), TEXT("失败"), MB_OK | MB_ICONSTOP);

    return FALSE;

   }
  }
 }
 //这里是紧接着上面的设置显示模式,如果成功的话(fullscreen为真),设置窗口显示模式
 if (fullscreen)
 {
  dwExStyle = WS_EX_APPWINDOW;
  dwStyle = WS_POPUP;

  ShowCursor(FALSE);
 }
 //如果失败的话,也要进行相应的处理
 else
 {
  dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
  dwStyle = WS_OVERLAPPEDWINDOW;
 }
 //用户已经改变了窗口(大小或方位),要进行调整
 AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle);

 //创建窗口,如果失败,销毁它(包括一切相关资源)
 if (!(hWnd = CreateWindowEx(dwExStyle, TEXT("OpenGL"), (LPCWSTR)title, dwStyle | WS_CLIPCHILDREN, 0, 0, WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top, NULL, NULL, hInstance, NULL)))
 {
  KillGLWindow();
  MessageBox(NULL, TEXT("Window Creation Error."), TEXT("ERROR"), MB_OK | MB_ICONEXCLAMATION);
  return FALSE;
 }
 //下面利用一个结构体来设置像素模式
 static PIXELFORMATDESCRIPTOR pfd =
 {
  sizeof(PIXELFORMATDESCRIPTOR),//上述格式描述符的大小
  1,                            // 版本号
  PFD_DRAW_TO_WINDOW |          //格式支持窗口
  PFD_SUPPORT_OPENGL |          //格式支持opengl
  PFD_DOUBLEBUFFER,             //支持双缓冲
  PFD_TYPE_RGBA,                //支持RGBA(Red,Green,Blue,Alpha,即三原色和透明度,任何色彩都有这组成)
  bits,                         //色彩深度
  0, 0, 0, 0, 0, 0,             //忽略的某些色彩位
  0,                            //没有ALPHA缓冲
  0,                            //忽略Shift Bit
  0,                            //无累加缓存
  0, 0, 0, 0,                   // 忽略聚集位
  16,                           // 16位 Z-缓存 (深度缓存)
  0,                            //无模板缓存
  0,                            //无辅助缓存
  PFD_MAIN_PLANE,               //主会绘图层
  0,                            //保留位
  0, 0, 0                       //忽略层遮罩
 };

 //尝试获取设备上下文
 if (!(hDC = GetDC(hWnd)))
 {
  KillGLWindow();
  MessageBox(NULL, TEXT("Can't Create A GL Device Context."), TEXT("ERROR"), MB_OK | MB_ICONEXCLAMATION);
  return FALSE;
 }
 if (!(PixelFormat = ChoosePixelFormat(hDC, &pfd)))
 {
  KillGLWindow();
  MessageBox(NULL, TEXT("Can't Find A Suitable PixelFormat."), TEXT("ERROR"), MB_OK | MB_ICONEXCLAMATION);
  return FALSE;
 }
 //找到后设置它
 if (!SetPixelFormat(hDC, PixelFormat, &pfd))
 {
  KillGLWindow();
  MessageBox(NULL, L"设置像素模式失败.", L"失败", MB_OK | MB_ICONEXCLAMATION);
  return FALSE;
 }
 //创建渲染上下文
 if (!(hRC = wglCreateContext(hDC)))
 {
  KillGLWindow();
  MessageBox(NULL, TEXT("Can't Create A GL Rendering Context."), TEXT("ERROR"), MB_OK | MB_ICONEXCLAMATION);
  return FALSE;
 }
 //激活渲染上下文
 if (!wglMakeCurrent(hDC, hRC))
 {
  KillGLWindow();
  MessageBox(NULL, TEXT("Can't Activate The GL Rendering Context"), TEXT("ERROR"), MB_OK | MB_ICONEXCLAMATION);
  return FALSE;
 }
 ShowWindow(hWnd, SW_SHOW);                  //如果一切顺利就显示窗口
 SetForegroundWindow(hWnd);                  //将窗口暂时挂在Z轴最前端
 SetFocus(hWnd);                             //将焦点调整到窗口
 ReSizeGLScreen(width, height);              //重新设置窗口大小

 //初始化OpenGL环境
 if (!InitGL())
 {
  KillGLWindow();
  MessageBox(NULL, TEXT("Initialization Failed."), TEXT("ERROR"), MB_OK | MB_ICONEXCLAMATION);
  return FALSE;
 }
 return TRUE;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
 switch (uMsg)
 {
 case WM_ACTIVATE:                              //监视窗口激活消息
 {
      if (!HIWORD(wParam))
      {
       active = TRUE;
      }
      else
      {
       active = FALSE;
      }
      return 0;
 }
 case WM_SYSCOMMAND:                           //监视系统中断,阻止一切中断
 {
        switch (wParam)
        {
        case SC_SCREENSAVE:     //屏保中断
        case SC_MONITORPOWER:   //显示器节电中断
         return 0;
        }
        break;
 }
 case WM_CLOSE:                                //退出
 {
      PostQuitMessage(0);
      return 0;
 }
 case WM_KEYDOWN:                              //按键
 {
        keys[wParam] = TRUE;
        return 0;
 }
 case WM_KEYUP:                                //释放按键
 {
      keys[wParam] = FALSE;
      return 0;
 }
 case WM_SIZE:                                 //窗口大小改变
 {
     ReSizeGLScreen(LOWORD(lParam), HIWORD(lParam));
     return 0;
 }
 }
 return DefWindowProc(hWnd, uMsg, wParam, lParam); //缺省处理
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
 MSG msg;
 BOOL done = FALSE;
 if (!CreateGLWindow(TEXT("Waving Picture"), 640, 480, 16, fullscreen))
 {
  return 0;
 }
 while (!done)
 {
  if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  {
   if (msg.message == WM_QUIT)
   {
    done = TRUE;
   }
   else
   {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
   }
  }
  else
  {
   if ((active&&!DrawGLScene()) || keys[VK_ESCAPE])
   {
    done = TRUE;
   }
   else
   {
    SwapBuffers(hDC);
   }
   if (keys[VK_F1])
   {
    keys[VK_F1] = FALSE;
    KillGLWindow();
    fullscreen = !fullscreen;
    if (!CreateGLWindow(TEXT("Waving Picture"), 640, 480, 16, fullscreen))
    {
     return 0;
    }
   }
  }
 }
 KillGLWindow();
 return (msg.wParam);
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值