用mfc框架基于OpenGL实现雪花飞舞场景的源代码
时间: 2024-05-09 18:15:28 浏览: 16
以下基于MFC框架和OpenGL实现雪花飞舞场景的源代码:
首先是头文件和全局变量的声明:
```c++
#include <afxwin.h>
#include <gl\gl.h>
#include <gl\glu.h>
#define MAX_SNOWFLAKES 2000
struct Snowflake {
float x, y, z;
float speed;
float angle;
};
Snowflake snowflakes[MAX_SNOWFLAKES];
float snowflakeSize = 0.02f;
float windSpeed = 0.01f;
float gravity = 0.0001f;
GLuint snowTexture;
BOOL SetupPixelFormat(HDC hDC);
void InitializeSnowflakes();
void DrawSnowflakes();
void UpdateSnowflakes();
void LoadSnowTexture();
void FreeSnowTexture();
class COpenGLWnd : public CFrameWnd {
public:
COpenGLWnd();
virtual ~COpenGLWnd();
protected:
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnPaint();
afx_msg void OnSize(UINT nType, int cx, int cy);
afx_msg void OnTimer(UINT_PTR nIDEvent);
afx_msg void OnDestroy();
DECLARE_MESSAGE_MAP()
private:
HDC m_hDC;
HGLRC m_hGLContext;
int m_width, m_height;
};
COpenGLWnd::COpenGLWnd() {
m_hDC = NULL;
m_hGLContext = NULL;
}
COpenGLWnd::~COpenGLWnd() {
if (m_hGLContext) {
wglMakeCurrent(NULL, NULL);
wglDeleteContext(m_hGLContext);
}
}
BEGIN_MESSAGE_MAP(COpenGLWnd, CFrameWnd)
ON_WM_CREATE()
ON_WM_PAINT()
ON_WM_SIZE()
ON_WM_TIMER()
ON_WM_DESTROY()
END_MESSAGE_MAP()
int COpenGLWnd::OnCreate(LPCREATESTRUCT lpCreateStruct) {
if (CFrameWnd::OnCreate(lpCreateStruct) == -1) {
return -1;
}
m_hDC = GetDC()->m_hDC;
PIXELFORMATDESCRIPTOR pfd = {
sizeof(PIXELFORMATDESCRIPTOR),
1,
PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
PFD_TYPE_RGBA,
16,
0, 0, 0, 0, 0, 0,
0,
0,
0,
0, 0, 0, 0,
16,
0,
0,
PFD_MAIN_PLANE,
0,
0, 0, 0
};
int pixelFormat = ChoosePixelFormat(m_hDC, &pfd);
if (!SetupPixelFormat(m_hDC)) {
MessageBox(_T("Could not setup pixel format."));
return -1;
}
m_hGLContext = wglCreateContext(m_hDC);
if (!wglMakeCurrent(m_hDC, m_hGLContext)) {
MessageBox(_T("Could not make rendering context current."));
return -1;
}
glEnable(GL_TEXTURE_2D);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClearDepth(1.0f);
glDepthFunc(GL_LEQUAL);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
LoadSnowTexture();
InitializeSnowflakes();
SetTimer(1, 30, NULL);
return 0;
}
void COpenGLWnd::OnPaint() {
CPaintDC dc(this);
SwapBuffers(m_hDC);
}
void COpenGLWnd::OnSize(UINT nType, int cx, int cy) {
m_width = cx;
m_height = cy;
glViewport(0, 0, cx, cy);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, (GLfloat)cx / (GLfloat)cy, 0.1f, 100.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void COpenGLWnd::OnTimer(UINT_PTR nIDEvent) {
UpdateSnowflakes();
Invalidate(FALSE);
}
void COpenGLWnd::OnDestroy() {
if (snowTexture) {
FreeSnowTexture();
}
CFrameWnd::OnDestroy();
}
BOOL SetupPixelFormat(HDC hDC) {
PIXELFORMATDESCRIPTOR pfd = {
sizeof(PIXELFORMATDESCRIPTOR),
1,
PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
PFD_TYPE_RGBA,
16,
0, 0, 0, 0, 0, 0,
0,
0,
0,
0, 0, 0, 0,
16,
0,
0,
PFD_MAIN_PLANE,
0,
0, 0, 0
};
int pixelFormat = ChoosePixelFormat(hDC, &pfd);
if (pixelFormat == 0) {
return FALSE;
}
if (!SetPixelFormat(hDC, pixelFormat, &pfd)) {
return FALSE;
}
return TRUE;
}
void InitializeSnowflakes() {
for (int i = 0; i < MAX_SNOWFLAKES; i++) {
Snowflake& s = snowflakes[i];
s.x = (float)(rand() % 1000) / 1000.0f - 0.5f;
s.y = (float)(rand() % 1000) / 1000.0f - 0.5f;
s.z = (float)(rand() % 1000) / 1000.0f * 5.0f;
s.speed = (float)(rand() % 1000) / 10000.0f + 0.001f;
s.angle = (float)(rand() % 360);
}
}
void DrawSnowflakes() {
glBindTexture(GL_TEXTURE_2D, snowTexture);
glBegin(GL_QUADS);
for (int i = 0; i < MAX_SNOWFLAKES; i++) {
Snowflake& s = snowflakes[i];
float x = s.x;
float y = s.y;
float z = s.z;
float size = snowflakeSize * (1.0f - (z / 5.0f));
glTexCoord2f(0.0f, 0.0f);
glVertex3f(x - size, y - size, z);
glTexCoord2f(1.0f, 0.0f);
glVertex3f(x + size, y - size, z);
glTexCoord2f(1.0f, 1.0f);
glVertex3f(x + size, y + size, z);
glTexCoord2f(0.0f, 1.0f);
glVertex3f(x - size, y + size, z);
}
glEnd();
}
void UpdateSnowflakes() {
for (int i = 0; i < MAX_SNOWFLAKES; i++) {
Snowflake& s = snowflakes[i];
s.x += windSpeed;
s.y -= s.speed;
s.z -= gravity;
if (s.z < 0.0f) {
s.z = 5.0f;
s.speed = (float)(rand() % 1000) / 10000.0f + 0.001f;
s.angle = (float)(rand() % 360);
}
}
}
void LoadSnowTexture() {
CImage image;
image.Load(_T("snow.bmp"));
glGenTextures(1, &snowTexture);
glBindTexture(GL_TEXTURE_2D, snowTexture);
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, GL_RGB, image.GetWidth(), image.GetHeight(),
0, GL_BGR_EXT, GL_UNSIGNED_BYTE, image.GetBits());
}
void FreeSnowTexture() {
glDeleteTextures(1, &snowTexture);
}
class COpenGLApp : public CWinApp {
public:
COpenGLApp();
virtual ~COpenGLApp();
virtual BOOL InitInstance();
private:
COpenGLWnd m_mainWnd;
};
COpenGLApp::COpenGLApp() {
}
COpenGLApp::~COpenGLApp() {
}
BOOL COpenGLApp::InitInstance() {
m_mainWnd.Create(NULL, _T("OpenGL Snow Scene"), WS_OVERLAPPEDWINDOW, CRect(0, 0, 640, 480));
m_pMainWnd = &m_mainWnd;
m_mainWnd.ShowWindow(SW_SHOW);
m_mainWnd.UpdateWindow();
return TRUE;
}
COpenGLApp theApp;
```
在头文件中,我们声明了 `Snowflake` 结构体,它包含雪花的位置、速度和角度。我们同时声明了一些全局变量,如雪花的大小、风向和重力。
`SetupPixelFormat` 函数设置了像素格式,创建了一个 OpenGL 上下文。`InitializeSnowflakes` 函数初始化了雪花的位置、速度和角度。`DrawSnowflakes` 函数绘制了所有的雪花。`UpdateSnowflakes` 函数更新雪花的位置。
`LoadSnowTexture` 函数加载了雪花纹理,`FreeSnowTexture` 函数释放了纹理。
`COpenGLWnd` 类继承自 `CFrameWnd`,它实现了 `OnCreate`、`OnPaint`、`OnSize`、`OnTimer` 和 `OnDestroy` 函数。在 `OnCreate` 函数中,我们创建了 OpenGL 上下文,并初始化了雪花和纹理。在 `OnPaint` 函数中,我们调用了 `SwapBuffers` 函数切换缓冲区。在 `OnSize` 函数中,我们设置了视口,并将投影矩阵设置为透视投影。在 `OnTimer` 函数中,我们更新雪花位置,并调用 `Invalidate` 函数更新窗口。在 `OnDestroy` 函数中,我们释放了纹理。
最后,在 `COpenGLApp` 类中,我们创建了 `COpenGLWnd` 对象,并将其显示出来。
注意:以上代码是在 Visual Studio 2019 中编写的,使用 MFC 应用程序模板创建,使用的是 OpenGL 版本是 1.1。如果需要使用更高版本的 OpenGL,需要修改代码。