【OpenGL】VS2005下创建基于Win32项目的OpenGL窗口

(2010-03-08)


       目前很多关于OpenGL的教材或教程都是基于VC来创建Win32下的OpenGL窗口的,而VS2005下的Win32项目的自生成代码与VC的还是略有不同。为了方便以后在VS2005下开发OpenGL程序,保留一个创建OpenGL窗口的模板是必要的。

        假设新建了一个名为glTemp的Win32项目,找到其主函数(即程序入口点)所在的文件glTemp.cpp,在其中编写创建OpenGL窗口的代码:

(1)首先不要忘了在stdafx.h中加入OpenGL必要的头文件和链接库:

#include <gl/gl.h>
#include <gl/glu.h>
#include <gl/glaux.h>
#include <gl/glut.h>
#pragma comment(lib,"opengl32.lib")
#pragma comment(lib,"glu32.lib")
#pragma comment(lib,"glaux.lib")
#pragma comment(lib,"glut32.lib")

当然,.lib库文件也可以用非编程方式,而通过设置VS2005项目属性加入。

(2)glTemp.cpp代码如下:

// glTemp.cpp : 定义应用程序的入口点。
//

#include "stdafx.h"
#include "glTemp.h"

#define MAX_LOADSTRING 100

// 全局变量:
HINSTANCE hInst;        // 当前实例
TCHAR szTitle[MAX_LOADSTRING];     // 标题栏文本
TCHAR szWindowClass[MAX_LOADSTRING];   // 主窗口类名

// 此代码模块中包含的函数的前向声明:
ATOM    MyRegisterClass(HINSTANCE hInstance);
BOOL    InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);

HWND hWnd; //窗口句柄
HDC hDC; //私有的GDI设备描述表
HGLRC hRC=NULL; //着色描述表
RECT rect;
int sw=640,sh=480; //全屏分辨率
bool fullscreen=1; //全屏标志
GLfloat aspect; //斜率
bool keys[256]; //按键是否被按下的信息
int mx,my; //获取鼠标指针坐标
//判断鼠标是否移动、是否左击、右击、双击
bool m_move,m_left,m_right,m_dclick;

//初始化OpenGL窗口
void SceneInit(int w,int h)
{
 glShadeModel(GL_SMOOTH); //允许平滑着色
 glClearColor(0.6f,0.2f,0.0f,0.5); //设置背景色
 glClearDepth(1.0f); //设置深度缓冲区
 glEnable(GL_DEPTH_TEST); //允许深度测试
 glDepthFunc(GL_LEQUAL); //深度测试的类型
 glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST); //更加精细的透视校正
}
//重置OpenGL场景尺寸
void SceneResizeViewport(GLsizei w,GLsizei h)
{
 if(h==0)
  h=1;
 aspect=(GLfloat)w/(GLfloat)h;
 glViewport(0,0,w,h); //设置当前视口
 glMatrixMode(GL_PROJECTION); //选择投影矩阵
 glLoadIdentity(); //重置投影矩阵
 gluPerspective(45.0f,aspect,0.1f,100.0f); //设置透视视景
 glMatrixMode(GL_MODELVIEW); //选择模型视图矩阵
 glLoadIdentity(); //重置模型视图矩阵
}
//所有OpenGL绘制
void SceneShow(GLvoid)
{
 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); //清屏和清除深度缓冲区
 glLoadIdentity(); //重置当前Modelview矩阵(原点回到窗口中心)
 gluLookAt(0,0,10,0,0,0,0,1,0);//设置视觉坐标系(视点位置,目标点位置,视点向上方向)
 /*添加任何绘图代码*/
}
//激活OpenGL
void EnbleOpenGL()
{
 PIXELFORMATDESCRIPTOR pfd; //像素格式描述符
 int iFormat;
 hDC=GetDC(hWnd); //获取设备描述表
 ZeroMemory(&pfd,sizeof(pfd));
 pfd.nSize=sizeof(pfd); //格式描述符大小
 pfd.nVersion=1; //版本号
 //格式必须支持窗口、OpenGL、双缓冲
 pfd.dwFlags=PFD_DRAW_TO_WINDOW|PFD_SUPPORT_OPENGL|PFD_DOUBLEBUFFER;
 pfd.iPixelType=PFD_TYPE_RGBA; //申请RGBA格式
 pfd.cColorBits=16; //色彩深度
 pfd.cDepthBits=16; //深度缓存(Z缓存)
 pfd.iLayerType=PFD_MAIN_PLANE; //主绘图层
 iFormat=ChoosePixelFormat(hDC,&pfd); //选择像素格式
 SetPixelFormat(hDC,iFormat,&pfd); //设置像素格式
 hRC=wglCreateContext(hDC); //取得着色描述表
 wglMakeCurrent(hDC,hRC); //激活着色描述表
}
//关闭OpenGL
void DisableOpenGL()
{
 wglMakeCurrent(NULL,NULL); //释放DC和RC描述表
 wglDeleteContext(hRC); //删除RC
 ReleaseDC(hWnd,hDC); //释放DC
}
//改变屏幕分辨率
bool ChangeResolution(int w,int h,int bitdepth)
{
 DEVMODE devMode; //设备模式
 int modeSwitch;
 int closeMode=0;
 EnumDisplaySettings(NULL,closeMode,&devMode);
 devMode.dmBitsPerPel=bitdepth; //每像素所选的色彩深度
 devMode.dmPelsWidth=w; //屏幕宽
 devMode.dmPelsHeight=h; //屏幕高
 devMode.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;
 //设置显示模式
 modeSwitch=ChangeDisplaySettings(&devMode,CDS_FULLSCREEN);
 if(modeSwitch==DISP_CHANGE_SUCCESSFUL)
  return true;
 else
 {
  ChangeDisplaySettings(NULL,0);
  return false;
 }
}
//主函数(程序入口)
int APIENTRY _tWinMain(HINSTANCE hInstance,
        HINSTANCE hPrevInstance,
        LPTSTR    lpCmdLine,
        int       nCmdShow)
{
 UNREFERENCED_PARAMETER(hPrevInstance);
 UNREFERENCED_PARAMETER(lpCmdLine);

 // TODO: 在此放置代码。
 MSG msg;
 HACCEL hAccelTable;
 bool bQuit=false;
    
 m_move=false;m_left=false;m_right=false;m_dclick=false;

 if(MessageBox(NULL,L"是否选择全屏显示模式?",L"全屏方式运行?",MB_YESNO|MB_ICONQUESTION)==IDNO)
  fullscreen=0;

 // 初始化全局字符串
 LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
 LoadString(hInstance, IDC_GLTEMP, szWindowClass, MAX_LOADSTRING);
 MyRegisterClass(hInstance);

 // 执行应用程序初始化:
 if (!InitInstance (hInstance, nCmdShow))
 {
  return FALSE;
 }

 hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_GLTEMP));

 // 主消息循环:
 while(!bQuit)
 {
  if(PeekMessage(&msg,NULL,0,0,PM_REMOVE))
   if(msg.message==WM_QUIT) //收到退出消息
    bQuit=true;
   else
   {
    TranslateMessage(&msg); //翻译消息
    DispatchMessage(&msg); //发送消息
   }
  else
  {
   //OpenGL动画
   SceneShow();
   SwapBuffers(hDC); //交换缓存
   /*添加响应键盘或鼠标消息的代码*/
  }
 }
    //销毁OpenGL窗口的几个后续操作
 DisableOpenGL();
 ShowWindow(hWnd,SW_HIDE);
 DestroyWindow(hWnd);
 ChangeDisplaySettings(NULL,0);

 return (int) msg.wParam;
}
//
//  函数: MyRegisterClass()
//
//  目的: 注册窗口类。
//
//  注释:
//
//    仅当希望
//    此代码与添加到 Windows 95 中的“RegisterClassEx”
//    函数之前的 Win32 系统兼容时,才需要此函数及其用法。调用此函数十分重要,
//    这样应用程序就可以获得关联的
//    “格式正确的”小图标。
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
 WNDCLASSEX wcex; //窗口类结构

 wcex.cbSize = sizeof(WNDCLASSEX);

 wcex.style   = CS_OWNDC; //为窗口取得DC
 wcex.lpfnWndProc = WndProc; //WndProc处理消息
 wcex.cbClsExtra  = 0; //无额外窗口数据
 wcex.cbWndExtra  = 0; //无额外窗口数据
 wcex.hInstance  = hInstance; //设置实例
 wcex.hIcon   = LoadIcon(NULL,IDI_APPLICATION); //装入缺省图标
 wcex.hCursor  = LoadCursor(NULL, IDC_ARROW); //装入鼠标指针
 wcex.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); //背景
 wcex.lpszMenuName = MAKEINTRESOURCE(IDC_GLTEMP); //菜单
 wcex.lpszClassName = L"Name"; //类名
 wcex.hIconSm  = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
    //注册窗口类
 return RegisterClassEx(&wcex);
}

//
//   函数: InitInstance(HINSTANCE, int)
//
//   目的: 保存实例句柄并创建主窗口
//
//   注释:
//
//        在此函数中,我们在全局变量中保存实例句柄并
//        创建和显示主程序窗口。
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
 hInst = hInstance; // 将实例句柄存储在全局变量中
 if(fullscreen)
 {
  ChangeResolution(640,480,16);
  hWnd=CreateWindow(L"Name",L"Lesson1",WS_POPUP|WS_CLIPSIBLINGS|WS_VISIBLE,0,0,GetSystemMetrics(SM_CXSCREEN),
   GetSystemMetrics(SM_CYSCREEN),NULL,NULL,hInstance,NULL);
 }
 else
 {
  hWnd=CreateWindow(L"Name",L"Lesson1",WS_TILEDWINDOW|WS_VISIBLE,
   GetSystemMetrics(SM_CXSCREEN)/2-sw/2,
   GetSystemMetrics(SM_CYSCREEN)/2-sh/2,
   sw,sh,NULL,NULL,hInstance,NULL);
  ChangeDisplaySettings(NULL,0);
 }
 //OpenGL窗口创建完毕的后续工作
 ShowWindow(hWnd,nCmdShow);
 UpdateWindow(hWnd);
 EnbleOpenGL();
 SceneInit(sw,sh);
 if(!fullscreen)
 {
  GetWindowRect(hWnd,&rect);
  sw=rect.right-rect.left;
  sh=rect.bottom-rect.top;
  if(sw>0&&sh>0)
   SceneResizeViewport(sw,sh);
 }
 else
 {
  SceneResizeViewport(GetSystemMetrics(SM_CXSCREEN),GetSystemMetrics(SM_CYSCREEN));
 }

 return TRUE;
}

//
//  函数: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  目的: 处理主窗口的消息。
//
//  WM_COMMAND - 处理应用程序菜单
//  WM_PAINT - 绘制主窗口
//  WM_DESTROY - 发送退出消息并返回
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
 int wmId, wmEvent;
 PAINTSTRUCT ps;
 HDC hdc;

 switch (message)
 {
 case WM_COMMAND:
  wmId    = LOWORD(wParam);
  wmEvent = HIWORD(wParam);
  // 分析菜单选择:
  switch (wmId)
  {
  case IDM_ABOUT:
   DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
   break;
  case IDM_EXIT:
   DestroyWindow(hWnd);
   break;
  default:
   return DefWindowProc(hWnd, message, wParam, lParam);
  }
  break;
 case WM_PAINT:
  hdc = BeginPaint(hWnd, &ps);
  // TODO: 在此添加任意绘图代码...
  EndPaint(hWnd, &ps);
  break;
 case WM_DESTROY:
  PostQuitMessage(0);
  break;
 case WM_CREATE:
  GetWindowRect(hWnd,&rect);
  sw=rect.right-rect.left;
  sh=rect.bottom-rect.top;
  SceneResizeViewport(sw,sh);
  break;
 case WM_SIZE:
  if(!fullscreen)
  {
   GetWindowRect(hWnd,&rect);
   sw=rect.right-rect.left;
   sh=rect.bottom-rect.top;
   if(sw>0&&sh>0)
    SceneResizeViewport(sw,sh);
  }
  else
  {
   SceneResizeViewport(GetSystemMetrics(SM_CXSCREEN),GetSystemMetrics(SM_CYSCREEN));
  }
  break;
 case WM_CLOSE:
  ShowWindow(hWnd,SW_HIDE);
  PostQuitMessage(0);
  break;
 case WM_KEYDOWN:
  keys[wParam]=true;
  switch(wParam)
  {
  case VK_ESCAPE:
   PostMessage(hWnd,WM_CLOSE,0,0);
   break;
  case VK_F1:
   {
    hInst=GetModuleHandle(NULL);
    break;
   }
  }
  break;
 case WM_KEYUP:
  keys[wParam]=false;
  break;
    //lParam的低4位为鼠标指针的x坐标,高4位为y坐标
 case WM_LBUTTONDOWN: // 处理鼠标左键按下消息  
  {
   mx=LOWORD(lParam);
   my=HIWORD(lParam);
   m_left=true;
   break;
  }
 case WM_LBUTTONUP: // 处理鼠标左键抬起消息   
  {
   mx=LOWORD(lParam);
   my=HIWORD(lParam);
   m_left=false;
   break;
  }
 case WM_RBUTTONDOWN: // 处理鼠标右键按下消息
  {
   mx=LOWORD(lParam);
   my=HIWORD(lParam);
   m_right=true;
   break;
  }
 case WM_RBUTTONUP: // 处理鼠标右键抬起消息
  {
   mx=LOWORD(lParam);
   my=HIWORD(lParam);
   m_right=false;
   break;
  }
 case WM_LBUTTONDBLCLK: // 处理鼠标左键双击消息
  {
   mx=LOWORD(lParam);
   my=HIWORD(lParam);
   m_dclick=true;
   break;
  }
 case WM_MOUSEMOVE: // 处理鼠标移动消息
  {
   mx=LOWORD(lParam);
   my=HIWORD(lParam);
   m_move=true;
   break;
  }
 default:
  return DefWindowProc(hWnd, message, wParam, lParam);
 }
 return 0;
}

// “关于”框的消息处理程序。
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
 UNREFERENCED_PARAMETER(lParam);
 switch (message)
 {
 case WM_INITDIALOG:
  return (INT_PTR)TRUE;

 case WM_COMMAND:
  if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
  {
   EndDialog(hDlg, LOWORD(wParam));
   return (INT_PTR)TRUE;
  }
  break;
 }
 return (INT_PTR)FALSE;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值