OpenGL + Win32 SDK 开发框架的搭建(C语言版)
生活随笔
收集整理的這篇文章主要介紹了
OpenGL + Win32 SDK 开发框架的搭建(C语言版)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
項目介紹:
近來公司需要建立一個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语言版)的全部內容,希望文章能夠幫你解決所遇到的問題。