win32原生API实现OpenGL例子(无glew,glut等第三方依赖库)

正文:

  话不多说,直接上代码:

#include<Windows.h>
#include<GL/GL.h>
#pragma comment(lib,"opengl32.lib")
//注册win32窗口类
BOOL win32_regist_class(const char* class_name)
{
 WNDCLASSEXA cs =
 {
  sizeof(WNDCLASSEXA),
  CS_HREDRAW | CS_VREDRAW,
  [](HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)->LRESULT
   {
    switch (msg)
    {
    case WM_NCCREATE:
    {
     SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)((LPCREATESTRUCTA)lparam)->lpCreateParams);
     break;
    };
    case WM_PAINT:
    {
     PAINTSTRUCT ps;
     BeginPaint(hwnd, &ps);
     EndPaint(hwnd, &ps);
     break;
    }
    case WM_ERASEBKGND://阻止窗口重绘,不然当窗口从边界移回来时会看到背景色
    {
     return TRUE;
    }
    case WM_DESTROY:
    {
     PostQuitMessage(0);
     break;
    }
    default:
     break;
    }
    return DefWindowProcA(hwnd, msg, wparam, lparam);
   },
  0,
  0,
  (HINSTANCE)GetModuleHandleA(nullptr),
  nullptr,
  LoadCursorA(nullptr,IDC_ARROW),
  (HBRUSH)COLOR_WINDOW,
  nullptr,
  class_name,
  nullptr
 };
 return RegisterClassExA(&cs);
}
//创建win32窗口
HWND win32_create(const char*class_name,const char*window_name,int x, int y, int width, int height)
{
 return CreateWindowExA(0, class_name,window_name, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
  x, y, width, height,
  nullptr, nullptr, GetModuleHandle(nullptr), nullptr);
}
//获取可用于OpenGL绘制的DC
HDC win32_get_gl_dc(HWND hwnd)
{
 PIXELFORMATDESCRIPTOR pfd = {};
 pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
 pfd.nVersion = 1;
 pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
 auto hdc = GetDC(hwnd);
 auto pixelFormat = ChoosePixelFormat(hdc, &pfd);
 if (!pixelFormat)
 {
  ReleaseDC(hwnd, hdc);
  return nullptr;
 }
 if (!SetPixelFormat(hdc, pixelFormat, &pfd))
 {
  ReleaseDC(hwnd, hdc);
  return nullptr;
 }
 return hdc;
}
//处理win32消息
BOOL win32_peek_message(HWND hwnd)
{
 MSG msg;
 if (PeekMessageA(&msg, hwnd, 0, 0, PM_REMOVE))
 {
  if (msg.message == WM_QUIT)
   return FALSE;
  TranslateMessage(&msg);
  DispatchMessageA(&msg);
 }
 return TRUE;
}
//创建OpenGL API
HGLRC gl_create(HDC hdc)
{
 auto hglrc = wglCreateContext(hdc);
 if (!hglrc)
  return nullptr;
 if (!wglMakeCurrent(hdc, hglrc))
  return nullptr;
 //******获取高版本API(glew的最主要功能就是这是一步)
 /*
  在这个里获取会用到的opengl api,这些API名称可以去opengl官网查询
  因为需要的功能不复杂,不需要使用着色器,GL1.0版本的API足够用了。
  所以这里并没有获取所有高版本的API,只获取了一个glCreateShader作为例子。
 */
 auto glCreateShader=(GLuint(__stdcall*)(GLenum type))wglGetProcAddress("glCreateShader");
 //******获取高版本API结束
 return hglrc;
}
//渲染
void render(HWND hwnd, HDC hdc, HGLRC hglrc)
{
 RECT rc;
 GetClientRect(hwnd, &rc);
 wglMakeCurrent(hdc, hglrc);//关联gl的DC到窗口的hdc。如果是单DC,只需关联一次即可
 glViewport(0, 0, rc.right, rc.bottom);//设置视口
 glClearColor(0.4f, 0.5f, 0.4f, 0);//设置清屏时的颜色
 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//清屏。这里清掉颜色缓冲区与深度缓冲区
 //******以下内容为1.0版本绘制方法,高版本的不建议这样绘制了,尽量使用glDraw*系列函数以提高性能
 //设置点
 glBegin(GL_TRIANGLE_STRIP); //以画线方式绘制,
 glColor3f(1, 0, 0); glVertex2f(0.0f, 0.0f);//中心端点,为红色
 glColor3f(0, 1, 0); glVertex2f(0.5f, 0.5f);//到左上角中点端点,为绿色
 glColor3f(0, 0, 1); glVertex2f(0.0f, 0.5f);//到上方中点端点,为蓝色
 glEnd();
 //glDrawArrays(GL_LINES, 0, 2);//经过测试,1.0版本不需要调用此函数
}
int main(int argc, const char* argv[])
{
 win32_regist_class("test");
 auto hwnd = win32_create("test", "test", 100, 100, 500, 400);
 auto hdc = win32_get_gl_dc(hwnd);
 auto hglrc = gl_create(hdc);
 while (true)
 {
  if(win32_peek_message(nullptr)==FALSE)
   break;
  render(hwnd, hdc, hglrc);
  SwapBuffers(wglGetCurrentDC());//翻转缓冲区(因为使用了双缓冲,必须要翻转才能看到绘制结果)
 }
}

  整个代码约140行,不算多。这是上次QQ群里一个人问我之后我改了之前的代码写出来的,逻辑比之前强很多,个人感觉优势在于不再需要乱七八糟的第三方库,可以作为学习用,在自己获取高版本GL的API后也可以简单取代glut。
  主要部分是win32_get_gl_dc(HWND hwnd)这个函数。这个函数执行成功了就可以继续后续的OpenGL操作,不然的话就会出现GL上下文创建失败的情况,导致后续的OpenGL操作无效。

附:gles32 API获取文件说明

  实现我已经放到我的资源里:_gles32.h,直接点击下载就行,只有一个头文件,是从GLES32官网上扒了gles32头文件下来改了实现的。
用法:

  1. 先调用上面的gl_create函数创建gl环境,不然会像gl_create代码里的注释说的一样接下来的操作失败(glew里包含有这步,所以可以直接用);
gl_load_api(wglGetProcAddress);

至于头文件包含

#include"_gles32.h"

这个不用我多说了吧。
  上面的wglGetProcAddress这个就是win32下用来获取高版本GL API的平台函数,之所以放到这里来作为参数传入而不写在_gles32.h里就是希望让_gles32.h平台独立化,所以gles32.h里是没有任何与win32相关的API的,唯一一个相关的已经被放到参数这来了。
  实现这个主要是因为原来用的glew还需要下载一个库,研究了下glew发现也没什么特别的,就去gles官网上扒了头文件下来自己改了下就完成实现了。这样下以后就可以不用再去包含一个第三方库。
  实际上我还实现了一个_gl_wrapper.h文件来对_gles32.h做包装,里面包含了着色器的操作封装及其他东西,但我觉得这不是OpenGL的核心东西,所以没放到资源里。
  完整的调用代码如下:

#include<Windows.h>
#include<GL/GL.h>
//包含头文件
#include"_gles32.h"
#pragma comment(lib,"opengl32.lib")

int main(int argc, const char* argv[])
{
 win32_regist_class("test");
 auto hwnd = win32_create("test", "test", 100, 100, 500, 400);
 auto hdc = win32_get_gl_dc(hwnd);
 //哈哈,你没看错,这就是上面那个例子的main函数,就改了这里
 auto hglrc = wglCreateContext(hdc);
 wglMakeCurrent(hdc, hglrc);
 //加载高版本GL API(就一个函数)
 gl_load_api(wglGetProcAddress);
 //加载API结束,接下来就可以正常使用高版本的GLES API了,
 //例如glCreateShader、glCreateProgram之类的。
 
 while (true)
 {
  if(win32_peek_message(nullptr)==FALSE)
   break;
  render(hwnd, hdc, hglrc);
  SwapBuffers(wglGetCurrentDC());//翻转缓冲区(因为使用了双缓冲,必须要翻转才能看到绘制结果)
 }
}

  (吐槽一下,CSDN的markdown排版有点难用啊,我用typora编辑的时候没这么蛋疼,而且typora和CSDN用的数学公式渲染器不是同一个,导致我在typora上编辑好的公式没法直接复制过来用)

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值