学校网站源码php地推app
在win api环境下,不借助任何界面库搭建opengl开发环境。主要是窗口设备上下文和opengl设备上下文进行关联,当进行opengl绘制时,就直接绘制到窗口上。
VS环境设置:
项目属性----链接器----附加依赖项----添加库文件OpenGL32.lib
代码如下(有详细注释方便理解代码):
- GLContext.hpp
#pragma once#include <windows.h>
#include <gl/GL.h>class GLContext {
protected:int _format;HWND _hWnd; //窗口句柄HDC _hDC; //绘制设备上下文HGLRC _hRC; //opengl设备上下文 可以理解为opengl对象
public:GLContext();~GLContext();//初始化 GL 建立openglbool setup(HWND hWnd, HDC hDC);//销毁 EGLvoid shutdown();//交换缓冲区void swapBuffer();
};
- GLContext.cpp
#include "GLContext.hpp"GLContext::GLContext() {_format = 0;_hWnd = 0;_hDC = 0;_hRC = 0;
}GLContext::~GLContext() {shutdown();
}bool GLContext::setup(HWND hWnd, HDC hDC) {_hWnd = hWnd;_hDC = hDC;unsigned PixelFormat;//声明像素格式描述符PIXELFORMATDESCRIPTOR pfd ={sizeof(PIXELFORMATDESCRIPTOR),1, //版本PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, //opengl 数据绘制到win窗口上 | 支持opengl | 双缓冲PFD_TYPE_RGBA, //像素类型32,0,0,0,0,0,0,0,0,0,0,0,0,0,24,8,0,PFD_MAIN_PLANE,0,0,0,0};_hDC = GetDC(_hWnd); //获取设备DCif(0 == _format) {PixelFormat = ChoosePixelFormat(_hDC, &pfd); //从_hDC 中查找有没有匹配 pfd像素格式的索引}else {PixelFormat = _format;}if(!SetPixelFormat(_hDC, PixelFormat, &pfd)) { //将当前_hDC 建立成pfd 这种像素格式和索引,建立后,windows内部将建立各种缓冲区 颜色缓冲区 模板缓冲区 深度缓冲区return false;}_hRC = wglCreateContext(_hDC); //wgl 是window扩展 opengl的函数 wglCreateContext意思是在给定的dc 上建立opengl的设备上下文 并返回句柄if(!wglMakeCurrent(_hDC, _hRC)) { //建立_hDC _hRC 关联 当用opengl进行绘制的时候 实际绘制到dc上 在当前的线程中建立opengl对象 该opengl对象和线程绑定 所以opengl只能在该线程下绘制 在其他线程中绘制要切换设备上下文return false;}return true;
}void GLContext::shutdown() {if(_hRC != NULL) {wglMakeCurrent(NULL, NULL);wglDeleteContext(_hRC);_hRC = NULL;}if(_hDC != NULL) {ReleaseDC(_hWnd, _hDC);_hDC = NULL;}
}//双缓冲 进行交换
void GLContext::swapBuffer() {SwapBuffers(_hDC);
}
- main.cpp
#include <windows.h>
#include <tchar.h>#include "GLContext.hpp"LRESULT CALLBACK wndProc(HWND hWnd, UINT msgId, WPARAM wParam, LPARAM lParam) {switch(msgId) {case WM_CLOSE:case WM_DESTROY:PostQuitMessage(0);break;default:return DefWindowProc(hWnd, msgId, wParam, lParam);}return 0;
}//#define CALLBACK __stdcall 标准调用int CALLBACK WinMain(HINSTANCE hInstance, //实例句柄HINSTANCE hPrevInstance, //前一个实例句柄 (这个应用程序可能由另一个应用程序启动)LPSTR lpCmdLine, //命令行int nShowCmd) {//1. 向操作系统注册窗口类WNDCLASSEX wnd;memset(&wnd, 0, sizeof(wnd));wnd.cbSize = sizeof(wnd);wnd.lpfnWndProc = wndProc; //告诉操作系统 这个窗口有事件就调用这个函数wnd.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);wnd.hCursor = LoadCursor(hInstance, IDC_ARROW); //鼠标样式 wnd.hIcon = 0; //小图标 应用程序左上角显示的wnd.hIconSm = 0; //大图标 windows 任务栏显示的wnd.hInstance = hInstance;wnd.lpszClassName = _T("lesson01"); //窗口类的名称wnd.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW | CS_OWNDC; //风格 样式 支持双击 水平滚动 横向滚动 拥有自己的DC(绘制设备上下文)RegisterClassEx(&wnd); //注册, 将上面定义的结构体 告诉操作系统//2. 创建窗口HWND hWnd = CreateWindowEx(0, //窗口的扩展风格_T("lesson01"), //该参数必须和上面wnd.lpszClassName = _T("lesson01"); 一致,否则创建错误_T("lesson01"), //窗口的标题WS_OVERLAPPEDWINDOW, //窗口风格 最大化 最小化 边框.....100, //窗口位置x100, //窗口位置y480, //窗口宽度w320, //窗口宽度h0, //父窗口句柄0, //系统菜单hInstance, //实例句柄0); //用户数据//3. 更新显示窗口 刷新重绘if(hWnd) { //窗口句柄是否为空UpdateWindow(hWnd); //更新窗口ShowWindow(hWnd, SW_SHOW); //显示窗口 }else {return 0;}GLContext context;bool succ = context.setup(hWnd, GetDC(hWnd));if(!succ) {return 0;}MSG msg ={ 0 };//4. 消息循环while(WM_QUIT != msg.message) {//if(GetMessage(&msg, 0, 0, 0)) { //当操作系统没有任何消息的时候 会阻塞在这里 // TranslateMessage(&msg); //翻译消息// DispatchMessage(&msg); //分发消息 最后由 wndProc函数处理各种不同的消息//}if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) { //到消息队列中查找有没有消息 有则获取 没有则直接返回 不会阻塞 opengl一般使用这种方式在else中实现绘制和逻辑计算TranslateMessage(&msg); //翻译消息DispatchMessage(&msg); //分发消息 最后由 wndProc函数处理各种不同的消息}else {//调用绘制函数进行绘制glClearColor(1, 0, 0, 1); //红色清屏绘制glClear(GL_COLOR_BUFFER_BIT);context.swapBuffer();}}context.shutdown();return 0;
}