项目介绍:

近来公司需要建立一个OpenGL的开发环境,我需要设计一个框架,以便不熟悉Win32 API的用户能够直接”书写 glXXX代码”。

卖点:

1. 只使用C语言。

2. 只使用Win32 API和操作系统自带的动态库,决不使用第三方的库。

3. 支持多窗口管理。

开始摆 了~~~~~~~

=====================================================================================

设计思路:

GLWinApp.h 框架的头文件。

GLWinApp.c  实现了框架。

Example.c 一个测试例子。

先来按照“测试驱动开发模式”来说明我的Example.c如何使用我这个库。

#include "GLWinApp.h"GLMY_WINDOW *gpWnd1, *gpWnd2, *gpWnd3;/** 应用程序启动后的钩子 */
void myPreHook()
{RECT rect;GetClientRect(GetDesktopWindow(), &rect);gpWnd1 = glmyCreateWindow(TEXT("test0"), TRUE, rect, 32);rect.top  = 0;rect.left = 0;rect.right = 300;rect.bottom = 300;gpWnd2 = glmyCreateWindow(TEXT("test1"), FALSE, rect, 32);rect.left = 350;rect.top = 0;rect.right = 650;rect.bottom = 300;gpWnd3 = glmyCreateWindow(TEXT("test2"), FALSE, rect, 32);glmyTimer(gpWnd1, 0, 10, TRUE);        /**< 设定定时器0 */glmyTimer(gpWnd2, 0, 10, TRUE);        /**< 设定定时器0 */glmyRefreshRate(1);                    /**< 设置刷新频率 */return;
}/** 应用程序结束前的钩子 */
void myPostHook()
{
}/** 窗口尺寸改变后的钩子 */
void myResizeHook(GLMY_WINDOW * pWnd)
{glViewport(0, 0, pWnd->nWidth, pWnd->nHeight);       /**< 设置视口 */glMatrixMode(GL_PROJECTION);         /**< 重置投影矩阵 */glLoadIdentity();//gluPerspective(45.0f, (float)pWnd->nWidth / (float)pWnd->nHeight, 0, 1000.0f);    /**< 使用对称透视视景体 */gluOrtho2D(0, pWnd->nWidth, pWnd->nHeight, 0);        /**< 使用平面坐标 */glMatrixMode(GL_MODELVIEW);                /**< 重置模型视点矩阵 */glLoadIdentity();
}/** 绘制的钩子 */
void myDrawHook(GLMY_WINDOW * pWnd)
{glClearColor(0.0f, 0.0f, 0.0f, 0.0f);glClear(GL_COLOR_BUFFER_BIT);glColor3f(1, 0, 0);glRecti(0, 0, 100, 100);if (pWnd == gpWnd1){//Draw wind1}if (pWnd == gpWnd2){//Draw wind2}
}/** 定时器的钩子 */
void myTimerHook(GLMY_WINDOW * pWnd, unsigned char nIndex)
{if (pWnd == gpWnd1 && nIndex == 0){//Do something}if (pWnd == gpWnd2 && nIndex == 0){//Do something}
}
/** 键盘触发 */
void myKeyboardHook(GLMY_WINDOW * pWnd, GLMY_KEYBOARD_KEY key)
{
}/** 鼠标触发 */
void myMouseHook(GLMY_WINDOW * pWnd, GLMY_MOUSE_BUTTON button, GLMY_MOUSE_ACTION action)
{
}/** GLMY程序入口,给用户设置Hook的机会(必须由客户端实现) */
void    GLMYENTRY glmyEntry()
{glmySetPreHook(myPreHook);glmySetPostHook(myPostHook);glmySetResizeHook(myResizeHook);glmySetDrawHook(myDrawHook);glmySetTimerHook(myTimerHook);glmySetKeyboardHook(myKeyboardHook);glmySetMouseHook(myMouseHook);
}

=====================================================================================

框架介绍:

直接上代码吧:

先来头文件GLWinApp.h

/************************************************************************/
/* 建立OpenGL Windows应用程序的通用框架(C语言版)特点:1. 仅使用Windows系统自带的SDK。2. 使用C语言,不使用C++语言。3. 使用glmy前缀,表示自定义的库设计说明:1. 配置文件使用说明:修改GLWinAppConfig.h文件,使用自定义的配置信息。//可配置项说明GLMY_PRE_HOOK      glmyPreHookGLMY_POST_HOOK       glmyPostHookGLMY_KEYBOARD_HOOK  glmyKeyboardHookGLMY_MOUSE_HOOK     glmyMouseHookGLMY_DRAW_HOOK     glmyDrawHookGLMY_TIMER_HOOK     glmyTimerHook2. 接口说明:新建一个或多个*.c的文件,写相应的函数。//HOOK函数说明glmyPreHook           程序启动时的Hook,可以创建窗口glmyPostHook        程序结束时的Hook,可以销毁窗口glmyKeyboardHook    键盘响应HookglmyMouseHook       鼠标响应HookglmyDrawHook        绘图需求HookglmyTimerHook       定时器响应Hook//可调用函数说明glmyCreateWindow      创建一个GL窗口glmyDestroyWindow       销毁一个GL窗口*/
/************************************************************************/#ifndef   _GLWINAPP_H_
#define _GLWINAPP_H_#ifdef __cplusplusextern "C" {
#endif/************************************************************************/
/* 宏定义,预处理定义,头文件 声明                                      */
/************************************************************************/#define   GLMYAPI     __declspec(dllexport)   /* 是否导出?         */
#define GLMYENTRY   __stdcall               /* 约定程序调用方式     */#pragma comment (lib, "opengl32.lib")   /* link Microsoft OpenGL lib    */
#pragma comment (lib, "glu32.lib")        /* link OpenGL Utility lib      */#define _CRT_SECURE_NO_WARNINGS       /**< c4996 warning, _stprintf() */
#define _CRT_NON_CONFORMING_SWPRINTFS#include <windows.h>
#include <tchar.h>
#include <assert.h>
#include <gl/gl.h>
#include <gl/glu.h>
#include "GLWinAppConfig.h"       /**< 编译配置文件 *//************************************************************************/
/* 数据结构定义                                                         */
/************************************************************************//** 鼠标按键 */
typedef enum
{GLMY_MOUSE_LEFT_BUTTON     = 0x0001,GLMY_MOUSE_RIGHT_BUTTON       = 0x0002,GLMY_MOUSE_MIDDLE_BUTTON  = 0x0004
} GLMY_MOUSE_BUTTON;/** 鼠标动作 */
typedef enum
{GLMY_MOUSE_DOWN        = 0x0001,GLMY_MOUSE_UP     = 0x0002,GLMY_MOUSE_MOVE       = 0x0004
} GLMY_MOUSE_ACTION;/** 键盘按键 */
typedef enum
{GLMY_KEY_ESC,GLMY_KEY_F1,GLMY_KEY_F2,GLMY_KEY_F3,GLMY_KEY_LEFT,GLMY_KEY_RIGHT,GLMY_KEY_UP,GLMY_KEY_DOWN,GLMY_KEY_SPACE
} GLMY_KEYBOARD_KEY;/** 结构 GLMY程序 */
typedef struct _GLMY_WINDOW
{HWND   hWnd;HDC        hDC;HGLRC   hRC;BOOL    bFullScreen;unsigned int    nWidth;unsigned int nHeight;unsigned int    nBitsPerPixel;struct _GLMY_WINDOW   *pNext;
} GLMY_WINDOW;/************************************************************************/
/* 接口声明                                                             */
/************************************************************************//**** 窗口管理函数 ****//** 建立窗口 */
GLMY_WINDOW *   GLMYENTRY glmyCreateWindow(TCHAR * title, BOOL bFullscreen, RECT rect, int nBitsPerPixel);
/** 销毁窗口 */
void    GLMYENTRY glmyDestroyWindow(GLMY_WINDOW * pWnd);
/** 设置全屏 */
void    GLMYENTRY glmyFullscreen(BOOL bEnable);
/** 设置刷新帧率 */
void    GLMYENTRY glmyRefreshRate(unsigned int nMs);
/** 更改窗口大小 */
void    GLMYENTRY glmyResize(GLMY_WINDOW * pWnd, int nWidth, int nHeight);/** 设置定时器 */
void    GLMYENTRY glmyTimer(GLMY_WINDOW * pWnd, unsigned char nIndex, unsigned int nMs, BOOL bEnable);/**** 注册回调函数 ****//** GLMY程序入口,给用户设置Hook的机会(必须由客户端实现) */
void    GLMYENTRY glmyEntry();/** 设置 程序启动后的Hook */
void    GLMYENTRY glmySetPreHook( void (*pFunc)());
/** 设置 程序结束前的Hook */
void    GLMYENTRY glmySetPostHook(void (*pFunc)());
/** 设置 窗口尺寸改变后的Hook */
void    GLMYENTRY glmySetResizeHook(void (*pFunc)(GLMY_WINDOW * pWnd));
/** 设置 绘制的Hook */
void    GLMYENTRY glmySetDrawHook(void (*pFunc)());
/** 设置 定时器触发的Hook */
void    GLMYENTRY glmySetTimerHook(void (*pFunc)(GLMY_WINDOW * pWnd, unsigned char nIndex));
/** 设置 键盘触发的Hook */
void    GLMYENTRY glmySetKeyboardHook(void (*pFunc)(GLMY_WINDOW * pWnd, GLMY_KEYBOARD_KEY key));
/** 设置 鼠标触发的Hook */
void    GLMYENTRY glmySetMouseHook(void (*pFunc)(GLMY_WINDOW * pWnd, GLMY_MOUSE_BUTTON button, GLMY_MOUSE_ACTION action));#ifdef    __cplusplus}
#endif/*** END OF FILE ***/
#endif  /* _GLWINAPP_H_ */

下面介绍GLWinApp.c的主要内容

#include "GLWinApp.h"/************************************************************************/
/* 私有成员                                                             */
/************************************************************************//** 常量 */
#define GLMY_WINDOW_MAX     99                          /**< 最大的窗口数量 *//** 字段 */
static HINSTANCE        m_hInstance = NULL;                /**< 程序实例        */
static TCHAR const *    m_sAppName = TEXT("GLMYApplication");    /**< 窗口类的名称 */
static GLMY_WINDOW *    m_pWndListHead = NULL;                     /**< GL窗口对象链表    */
static unsigned int     m_nWndListCount = 0;           /**< GL窗口对象链表的当前长度 */
static unsigned int     m_nRefreshRate = 35;           /**< 刷新帧率(ms)      *//** Hook函数指针 */
static void ( * m_PreHook )( void ) = 0;                   /**< 程序启动后的Hook  */static void ( * m_PostHook )( void ) = 0;                    /**< 程序退出前的Hook  */static void ( * m_ResizeHook)( GLMY_WINDOW * pWnd ) = 0; /**< 窗口尺寸改变后的Hook */static void ( * m_DrawHook )( GLMY_WINDOW * pWnd ) = 0;         /**< 绘制的Hook */static void ( * m_TimerHook )( GLMY_WINDOW * pWnd, unsigned char nIndex ) = 0;       /**< 定时器触发的Hook */static void ( * m_KeyboardHook )( GLMY_WINDOW * pWnd, GLMY_KEYBOARD_KEY key ) = 0;        /**< 键盘触发的Hook */static void ( * m_MouseHook )( GLMY_WINDOW * pWnd, GLMY_MOUSE_BUTTON button, GLMY_MOUSE_ACTION action ) = 0;   /**< 鼠标触发的Hook *//************************************************************************/
/* 内部函数声明                                                               */
/************************************************************************//** 注册窗口类 */
static BOOL glmy_RegWndClass(HINSTANCE hInstance, WNDPROC wndProc);
/** 消息处理函数 */
static LRESULT CALLBACK glmy_WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
/** 设置屏幕模式 */
static BOOL glmyChangeScreenMode(BOOL bFullscreen, int nWidth, int nHeight, int nBitsPerPixel);
/** 启动OpenGL渲染环境 */
static void glmyEnableGL(GLMY_WINDOW * pApp);
/** 停止OpenGL渲染环境 */
static void glmyDisableGL(GLMY_WINDOW *pApp);/** 窗口链表 - 增加 */
static BOOL glmy_WndList_Add(GLMY_WINDOW * pWnd);
/** 窗口链表 - 删除 */
static BOOL glmy_WndList_Delete(GLMY_WINDOW * pWnd);
/** 窗口链表 - 查找 */
static GLMY_WINDOW * glmy_WndList_Search(HWND hWnd);
/** 窗口链表 - 反向销毁所有的窗口对象 */
static void glmy_WndList_ReverseFreeAll();/************************************************************************/
/* 内部函数实现                                                           */
/************************************************************************//** Windows程序入口 */
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{MSG    msg;                /**< 定义一个消息      */BOOL bQuit = FALSE;      /**< 是否退出消息循环    */m_hInstance = hInstance; /**< 记录程序实例 */if (!glmy_RegWndClass(hInstance, glmy_WndProc))        /**< 注册一个窗口类 */{return -1;}glmyChangeScreenMode(FALSE, 0, 0, 0);     /**< 强行切换一次显示模式,在以下的创建过程中,如果是全屏,才会修改一次显示模式 */#if GLMY_HOOKglmyEntry();
#endif#if   GLMY_PRE_HOOKif (m_PreHook != NULL)    /**< 启动Hook */{m_PreHook();}
#endif/** 传统的消息循环 *//*while (GetMessage (&msg, NULL, 0, 0)){TranslateMessage (&msg) ;DispatchMessage (&msg) ;}return msg.wParam ;*//** 不使用定时器的消息循环 */while (!bQuit) /**< 消息循环 */{        if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))   /**< 检查消息  */{if (msg.message == WM_QUIT)          /**< 检查退出消息 */{bQuit = TRUE;}else{TranslateMessage(&msg);       /**< 翻译消息 */DispatchMessage(&msg);       /**< 分发消息 */}}else{GLMY_WINDOW * pNextWnd = m_pWndListHead;int nWndCnt = m_nWndListCount > 0 ? m_nWndListCount : 1;int nSleepMs = m_nRefreshRate / nWndCnt;        /**< 计算休眠时间 */nSleepMs = nSleepMs < 1 ? 1 : nSleepMs;                /**< 防止为0 */while (pNextWnd != NULL){
#if GLMY_DRAW_HOOKif (m_DrawHook != NULL){wglMakeCurrent(pNextWnd->hDC, pNextWnd->hRC);m_DrawHook(pNextWnd);SwapBuffers(pNextWnd->hDC);       /**< 交换到缓冲区  */wglMakeCurrent(NULL, NULL);}
#endifSleep(nSleepMs);pNextWnd = pNextWnd->pNext;}}}#if GLMY_POST_HOOKif (m_PostHook != NULL)  /**< 结束Hook  */{m_PostHook();}
#endifglmy_WndList_ReverseFreeAll();    /**< 反向清空所有的窗体对象 */return msg.wParam;
}/** 注册窗口类 */
static BOOL glmy_RegWndClass(HINSTANCE hInstance, WNDPROC wndProc)
{WNDCLASSEX wcex;/* 注册窗口类 */wcex.cbSize = sizeof(WNDCLASSEX);wcex.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;wcex.lpfnWndProc = 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(GRAY_BRUSH);wcex.lpszMenuName = NULL;wcex.lpszClassName = m_sAppName;wcex.hIconSm = LoadIcon(NULL, IDI_APPLICATION);if(!RegisterClassEx(&wcex)){return FALSE;}return TRUE;
}/** 消息处理函数 */
static LRESULT CALLBACK glmy_WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{GLMY_WINDOW* pWnd = NULL;GLMY_KEYBOARD_KEY key = GLMY_KEY_SPACE;                 /**< 键盘按键 */pWnd = glmy_WndList_Search(hWnd);   switch(uMsg){case WM_CREATE:break;case WM_CLOSE:if (pWnd != NULL){glmy_WndList_Delete(pWnd);   /**< 关闭当前窗口,并清除相关资源 */}if (m_pWndListHead == NULL)      /**< 如果窗口列表为空,则退出程序 */{PostQuitMessage(0);}break;case WM_SIZE:if (pWnd != NULL){
#if GLMY_RESIZE_HOOKpWnd->nWidth = LOWORD(lParam);      /**< 记录宽度和高度 */pWnd->nHeight = HIWORD(lParam);pWnd->nHeight = pWnd->nHeight > 1 ? pWnd->nHeight : 1;    /**< 防止为0 */wglMakeCurrent(pWnd->hDC, pWnd->hRC);  /**< 选中DC和RC */if (m_ResizeHook != NULL){m_ResizeHook(pWnd, pWnd->nWidth, pWnd->nHeight); /**< 调用Hook */}wglMakeCurrent(NULL, NULL);   /**< 释放DC和RC */
#endif}break;case WM_KEYDOWN:switch(wParam){case VK_F1:key = GLMY_KEY_F1;break;case VK_F2:key = GLMY_KEY_F2;break;case VK_F3:key = GLMY_KEY_F3;break;case VK_ESCAPE:PostQuitMessage(0);break;}
#if GLMY_KEYBOARD_HOOKif (m_KeyboardHook != NULL){m_KeyboardHook(pWnd, key);}
#endifbreak;case WM_LBUTTONDOWN:
#if GLMY_KEYBOARD_HOOKif (m_MouseHook != NULL){m_MouseHook(pWnd, GLMY_MOUSE_LEFT_BUTTON, GLMY_MOUSE_DOWN);}
#endifbreak;case WM_LBUTTONUP:
#if GLMY_KEYBOARD_HOOKif (m_MouseHook != NULL){m_MouseHook(pWnd, GLMY_MOUSE_LEFT_BUTTON, GLMY_MOUSE_UP);}
#endifbreak;case WM_RBUTTONDOWN:
#if GLMY_KEYBOARD_HOOKif (m_MouseHook != NULL){m_MouseHook(pWnd, GLMY_MOUSE_RIGHT_BUTTON, GLMY_MOUSE_DOWN);}
#endifbreak;case WM_RBUTTONUP:
#if GLMY_KEYBOARD_HOOKif (m_MouseHook != NULL){m_MouseHook(pWnd, GLMY_MOUSE_RIGHT_BUTTON, GLMY_MOUSE_UP);}
#endifbreak;case WM_MBUTTONDOWN:
#if GLMY_KEYBOARD_HOOKif (m_MouseHook != NULL){m_MouseHook(pWnd, GLMY_MOUSE_MIDDLE_BUTTON, GLMY_MOUSE_DOWN);}
#endifbreak;case WM_MBUTTONUP:
#if GLMY_KEYBOARD_HOOKif (m_MouseHook != NULL){m_MouseHook(pWnd, GLMY_MOUSE_MIDDLE_BUTTON, GLMY_MOUSE_UP);}
#endifbreak;case WM_MOUSEMOVE:
#if GLMY_KEYBOARD_HOOKif (m_MouseHook != NULL){m_MouseHook(pWnd, GLMY_MOUSE_LEFT_BUTTON, GLMY_MOUSE_MOVE);}
#endifbreak;case WM_TIMER:
#if GLMY_TIMER_HOOKif (m_TimerHook != NULL){m_TimerHook(pWnd, (unsigned int)wParam);}
#endifbreak;default:return DefWindowProc(hWnd, uMsg, wParam, lParam);}return 0;
}/** 设置屏幕模式 */
static BOOL glmyChangeScreenMode(BOOL bFullscreen, int nWidth, int nHeight, int nBitsPerPixel)
{if (!bFullscreen){ChangeDisplaySettings(NULL, 0);          /**< 回到桌面 */}else{DEVMODE dmScreenSettings;                                  /**< 设备模式    */memset(&dmScreenSettings, 0, sizeof(dmScreenSettings));dmScreenSettings.dmSize            = sizeof(DEVMODE);         dmScreenSettings.dmPelsWidth    = nWidth;                  /**< 屏幕宽度 */dmScreenSettings.dmPelsHeight    = nHeight;                 /**< 屏幕高度 */dmScreenSettings.dmBitsPerPel    = nBitsPerPixel;           /**< 色彩深度 */dmScreenSettings.dmFields        = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;// 尝试设置显示模式并返回结果。注: CDS_FULLSCREEN 移去了状态栏if (ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL){return FALSE;}}return TRUE;
}/** 启动OpenGL渲染环境 */
static void glmyEnableGL(GLMY_WINDOW * pApp)
{PIXELFORMATDESCRIPTOR pfd =       /**< 像素格式设置 */{sizeof(PIXELFORMATDESCRIPTOR),1,                      /**< 版本号 */PFD_DRAW_TO_WINDOW        /**< 格式支持窗口 */| PFD_SUPPORT_OPENGL   /**< 格式必须支持OpenGL */| PFD_DOUBLEBUFFER       /**< 必须支持双缓冲 */| PFD_TYPE_RGBA,      /**< RGBA颜色格式 */pApp->nBitsPerPixel,  /**< 选定色彩深度 */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                    /**< 忽略层遮罩 */};int nPixelFormatIndex;        /**< 像素格式序号 */pApp->hDC = GetDC(pApp->hWnd);      /**< 获取HDC */nPixelFormatIndex = ChoosePixelFormat(pApp->hDC, &pfd); /**< 取得索引 */SetPixelFormat(pApp->hDC, nPixelFormatIndex, &pfd);       /**< 设置索引 */pApp->hRC = wglCreateContext(pApp->hDC);      /**< 创建RC */wglMakeCurrent(pApp->hDC, pApp->hRC);          /**< 测试选中,取消 */wglMakeCurrent(NULL, NULL);
}/** 停止OpenGL渲染环境 */
static void glmyDisableGL(GLMY_WINDOW *pApp)
{if (pApp->hRC){wglMakeCurrent(NULL, NULL);      /**< 释放DC和RC */wglDeleteContext(pApp->hRC);   /**< 释放RC */pApp->hRC = NULL;}if (pApp->hDC){ReleaseDC(pApp->hWnd, pApp->hDC);  /**< 释放DC */pApp->hDC = NULL;}
}/************************************************************************/
/* 接口函数实现                                                           */
/************************************************************************//** 建立GL窗口 */
GLMY_WINDOW *   GLMYENTRY glmyCreateWindow(TCHAR * title, BOOL bFullscreen, RECT rect, int nBitsPerPixel)
{GLMY_WINDOW    *pWnd;BOOL      bQuit = FALSE;DWORD        dwStyle;DWORD       dwExStyle;pWnd = calloc(1, sizeof(GLMY_WINDOW));       /**< 在堆上分配内存,一定要注意释放 */pWnd->bFullScreen = bFullscreen;pWnd->nWidth = rect.right - rect.left;pWnd->nHeight = rect.bottom - rect.top;pWnd->nBitsPerPixel = nBitsPerPixel;if (pWnd->bFullScreen)     /**< 如果是全屏,则要切换显示模式 */{glmyChangeScreenMode(bFullscreen, rect.right - rect.left, rect.bottom - rect.top, nBitsPerPixel);}/** 创建窗口 */if (bFullscreen)      {dwStyle = WS_POPUP;dwExStyle = WS_EX_APPWINDOW;//ShowCursor(FALSE);}else{dwStyle = WS_OVERLAPPEDWINDOW;dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;//ShowCursor(TRUE);}dwStyle |= WS_CLIPCHILDREN  /**< 排除子窗口 */| WS_CLIPSIBLINGS;      /**< 排除同类窗口 */pWnd->hWnd = CreateWindowEx(dwExStyle,m_sAppName,title,dwStyle,rect.left,                  /**< start x */rect.top,                 /**< start y */rect.right - rect.left,   /**< width       */rect.bottom - rect.top,   /**< height      */NULL,     /**< parent window handle */NULL,        /**< window menu handle      */m_hInstance,  /**< program instance handle */NULL);        /**< creation parameters */if (pWnd->hWnd == NULL)      /**< 如果创建失败? */{      free(pWnd);return FALSE;}if (!glmy_WndList_Add(pWnd))       /**< 增加到链表。如果失败,则可能是超出了容量或内存分配失败 */{free(pWnd);return NULL;}glmyEnableGL(pWnd);                               /**< 启用OpenGL渲染环境 */glmyResize(pWnd, pWnd->nWidth, pWnd->nHeight); /**< 手动触发Resize事件,使之能够调整GL环境 */ShowWindow(pWnd->hWnd, SW_SHOW);    /**< 显示窗口 */SetForegroundWindow(pWnd->hWnd);SetFocus(pWnd->hWnd);return pWnd;
}/** 删除GL窗口 */
void GLMYENTRY glmyDestroyWindow(GLMY_WINDOW * pWnd)
{assert(pWnd != NULL);     /**< 调试时不允许错误,限制用户必须维护数据的正确 */if (pWnd == NULL)         /**< 防止用户传入空参数 */{return;}if (pWnd->bFullScreen)      /**< 如果是全屏,则要切换回桌面 */{glmyChangeScreenMode(FALSE, 0, 0, 0);}glmyDisableGL(pWnd);      /**< 先禁止OpenGL环境 */if (pWnd->hWnd != NULL)       /**< 销毁窗口 */{DestroyWindow(pWnd->hWnd);//SendMessage(pWnd->hWnd, WM_CLOSE, 0, 0);pWnd->hWnd = NULL;}
}/** 设置全屏 */
void    GLMYENTRY glmyFullscreen(BOOL bEnable)
{}/** 设置刷新帧率 */
void    GLMYENTRY glmyRefreshRate(unsigned int nMs)
{int nRefreshRateMin = 1;      /**< 最快1ms刷新一次 */int nRefreshRateMax = 10000;   /**< 最慢10s刷新一次 */nMs = nMs < nRefreshRateMin ? nRefreshRateMin : nMs;nMs = nMs > nRefreshRateMax ? nRefreshRateMax : nMs;m_nRefreshRate = nMs;
}/** 更改窗口大小 */
void    GLMYENTRY glmyResize(GLMY_WINDOW * pWnd, int nWidth, int nHeight)
{assert(pWnd != NULL);assert(pWnd->hWnd != NULL);assert(pWnd->hDC != NULL);assert(pWnd->hRC != NULL);SendMessage(pWnd->hWnd, WM_SIZE, 0, MAKELONG(nWidth, nHeight));    /**< 发送WM_SIZE消息 */
}/** 设置定时器 */
void    GLMYENTRY glmyTimer(GLMY_WINDOW * pWnd, unsigned char nIndex, unsigned int nMs, BOOL bEnable)
{if (pWnd == NULL || pWnd->hWnd == NULL){return;}nMs = nMs < 10 ? 10 : nMs;  /**< 定时器精度最大为10ms */if (bEnable){SetTimer(pWnd->hWnd, nIndex, nMs, NULL);}else{KillTimer(pWnd->hWnd, nIndex);}
}/** 设置 程序启动后的Hook */
void    GLMYENTRY glmySetPreHook(void (*pFunc)())
{m_PreHook = pFunc;
}
/** 设置 程序结束前的Hook */
void    GLMYENTRY glmySetPostHook(void (*pFunc)())
{m_PostHook = pFunc;
}
/** 设置 窗口尺寸改变后的Hook */
void    GLMYENTRY glmySetResizeHook(void (*pFunc)(GLMY_WINDOW * pWnd))
{m_ResizeHook = pFunc;
}
/** 设置 绘制的Hook */
void    GLMYENTRY glmySetDrawHook(void (*pFunc)())
{m_DrawHook = pFunc;
}
/** 设置 定时器触发的Hook */
void    GLMYENTRY glmySetTimerHook(void (*pFunc)(GLMY_WINDOW * pWnd, unsigned char nIndex))
{m_TimerHook = pFunc;
}
/** 设置 键盘触发的Hook */
void    GLMYENTRY glmySetKeyboardHook(void (*pFunc)(GLMY_WINDOW * pWnd, GLMY_KEYBOARD_KEY key))
{m_KeyboardHook = pFunc;
}
/** 设置 鼠标触发的Hook */
void    GLMYENTRY glmySetMouseHook(void (*pFunc)(GLMY_WINDOW * pWnd, GLMY_MOUSE_BUTTON button, GLMY_MOUSE_ACTION action))
{m_MouseHook = pFunc;
}

下面补充WndList的链表操作。

/** 窗口链表 - 增加 */
static BOOL glmy_WndList_Add( GLMY_WINDOW * pWnd )
{int count = 0;GLMY_WINDOW * pPrev = m_pWndListHead, * pNode;assert(pWnd != NULL);           //传入元素必不为空if (m_pWndListHead == NULL)     //如果链表为空{m_pWndListHead = pWnd;m_nWndListCount = 1;       /**< 数量为1 */return TRUE;}pNode = pPrev;while (pNode != NULL)           //找到第一个空节点{pPrev = pNode;pNode = pNode->pNext;count++;if (count >= GLMY_WINDOW_MAX)  //超出链表容量{return FALSE;}}pPrev->pNext = pWnd;m_nWndListCount++;            /**< 数量+1 */return TRUE;
}
/** 窗口链表 - 删除 */
static BOOL glmy_WndList_Delete( GLMY_WINDOW * pWnd )
{GLMY_WINDOW * pPrev = m_pWndListHead, * pNode = NULL;assert(pPrev != NULL);     //链表必不为空assert(pWnd != NULL);      //传入元素必不为空if (pWnd == m_pWndListHead) //如果就是头结点{pNode = pWnd->pNext;  //先取得后一个元素glmyDestroyWindow(pWnd);  /**< 释放窗体资源 */free(pWnd);                    /**< 释放GL窗体节点 */m_pWndListHead = pNode;     /**< 修改表头 */m_nWndListCount = 0;        /**< 数量为0 */return TRUE;}pNode = pPrev;while(pNode != NULL){pPrev = pNode;pNode = pNode->pNext;if (pNode == pWnd)       //找到元素{pPrev->pNext = pNode->pNext;  /**< 指向下下个节点 */m_nWndListCount--;            /**< 数量-1 */glmyDestroyWindow(pWnd); /**< 释放窗体资源 */free(pWnd);                    /**< 释放GL窗体节点 */return TRUE;}}return FALSE;
}
/** 窗口链表 - 查找 */
static GLMY_WINDOW * glmy_WndList_Search(HWND hWnd)
{GLMY_WINDOW * pNode = NULL, *pHead;pHead = m_pWndListHead;while (pHead != NULL){if (pHead->hWnd == hWnd){pNode = pHead;break;}pHead = pHead->pNext;}//assert(pWnd != NULL);          /**< !此处不可避免的会失败,当CreateWindows()运行后自动发送WM_SIZE事件,但是还没有机会将新的hWND有关的GL_Wnd存储下来。return pNode;
}/** 窗口链表 - 反向销毁所有的窗口对象 */
static void glmy_WndList_ReverseFreeAll()
{GLMY_WINDOW * pPrev, * pNode;while (TRUE){pPrev = m_pWndListHead;if (pPrev == NULL)     //表头为空{return;}pNode = pPrev->pNext;if (pNode == NULL)        //只有一个元素{glmyDestroyWindow(pPrev);free(pPrev);m_pWndListHead = NULL;m_nWndListCount = 0;          /**< 数量为0 */return;}while (pNode != NULL)   //元素数量>=2。找到末尾节点。{if (pNode->pNext == NULL){break;}else{pPrev = pNode;pNode = pNode->pNext;}}glmyDestroyWindow(pPrev->pNext);free(pPrev->pNext);        //销毁刚找到的末尾节点,使之数量减1pPrev->pNext = NULL;m_nWndListCount--;        /**< 数量-1 */}assert(m_nWndListCount == 0);     /**< 数量必为0 */
}

=====================================================================================

(华丽的结束线)

后记:当然,可能还有些许错误,也还没有做任何优化,期待我的库能够运行下去。欢迎各位指正。

OpenGL + Win32 SDK 开发框架的搭建(C语言版)相关推荐

  1. 使用纯C语言开始win32 sdk编程

    使用纯C语言开始win32 sdk编程 今天开始加强用c语言进行win32 sdk编程的训练,不为别的,只为进一步加强自己对代码的感觉,加强快速写出正确代码的能力.因为c是如些地具有挑战性而灵活的语言 ...

  2. 一个使用纯Win32 SDK和C语言实现的五子棋游戏

    引言:GobangGame 这是一个使用纯Win32 SDK和C语言实现的五子棋游戏 在这个游戏中实现的功能 [x] 绘制一个15 * 15的棋盘 [x] 绘制5个着重点位置 [x] 根据鼠标左键的点 ...

  3. 使用百度云智能SDK和树莓派搭建简易的人脸识别系统 Python语言版

    硬件 树莓派4B一个 CSI摄像头一个 笔者使用的是树莓派4B和CSI摄像头,但是树莓派3和USB摄像头等相似设备均可. 百度云智能设置 Step 1 登录 百度云智能 网址https://cloud ...

  4. Eclipse下搭建C语言开发环境

    Eclipse下搭建C语言开发环境 要使用Eclipse开发C/C++语言主要有 下面几个步骤: 1. 安装 JRE 去sun官方网站 下载安装即可 由于 Eclipse 本身是用 Java 开发的, ...

  5. Win32 SDK 访问数据库

    一 ODBC + WIN32 API 访问MYSQL 数据库实现简单QQ用户注册和登录 http://blog.csdn.net/dai_jing/article/details/8231645 // ...

  6. 将GLFW窗口嵌入Win32 SDK窗口及其多线程渲染方法

    这篇文章(MFC单文档视图中嵌入GLFW窗口)提到了glfw嵌入mfc的办法,采用的查找进程PID再嵌入的方法,进程间通信采用UDP,略微繁琐. 其实不必如此麻烦,SetParent直接就可以办到. ...

  7. 第一个Win32 SDK应用程序

    #include<windows.h>int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int);LRESULT WINAPI WndProc(HW ...

  8. c语言环境窗口组成,如何搭建C语言环境

    如何搭建C语言环境 开发C程序的时候我们用的开发软件有VC++6.0.visual studio等等,但对于有些简单的程序我们更喜欢用记事本或者notepad++等方便的工具进行编辑,编辑完后再通过c ...

  9. window环境搭建go语言运行环境

    研究区块链,一直在纠结是研究比原链还是研究比特币链, 现在准备研究比原链,因为 ①比原链也是基于比特币开发的, ②我也在比原社区群里,有问题的话可以向比原技术老师请教 ③我是从事交易所工作的,最近对接 ...

最新文章

  1. EXCEL——批量生成中国各省省会经纬度JSON的一种方法
  2. desktop docker 无法卸载_docker,生信人的福音!
  3. 野火linux底板设计,野火STM32F767套件(底板+核心板)
  4. 【Python】【有趣的模块】【systimeos】
  5. Eclipse\myeclipse加载项目building workspace过久
  6. 《必玩》!学习大师们的游戏设计经验,激发你的游戏创造力!
  7. 8.企业安全建设指南(金融行业安全架构与技术实践) --- 安全考核
  8. E-prime实验设计常用技术
  9. CTF必备密码编码大全
  10. 软件工程——NS图,PAD图
  11. 使用虚拟鼠标驱动解决Surface go以及寨板win10 win11 win8平台 甚至win arm手机 在运行某些GalGame 当不插入鼠标或者连接蓝牙鼠标时候出现的错误
  12. 关于keras-yolov3-deepsort
  13. 怎么样在应用中实现自助报表功能
  14. 【计算机网络】路由器和交换机的基本配置
  15. 查看计算机内存过高,物理内存过高怎么办,小编教你电脑物理内存过高怎么办...
  16. 《商用密码-应用与安全性评估》学习1:密码基础知识
  17. uTools插件-Excalidraw轻量的在线白板绘图工具
  18. 用java语言如何编写圆面积_用java语言编写一个圆面积的求法
  19. speccpu2006整型浮点型测试
  20. 分布式FFMPEG转码集群

热门文章

  1. 《我的初恋、我的老婆》超爆笑!!
  2. MySQL数据库select语句6大子句(from、where、group by、having、order by 、limit )#经典员工、部门表案例语句练手!
  3. 糖醋鲤鱼——经典美食
  4. 基于Python3.6配置开发环境
  5. 新手学习嵌入式开发要学什么
  6. 试试看:把电脑时间调到2099年12月31号之后,会发生什么
  7. python学习-day18、文件处理、
  8. 【转载】深入了解scanf()/getchar()和gets()等函数,C++系列教程,C++实例教程,C++
  9. 坐标下载gRaphael——JavaScript 矢量图表库:两行代码实现精美图表
  10. Centos8 部署Promethus(普罗米修斯)+grafana画图