计算机图形学编程练习8MFC+明暗处理的实现 下载本文

计算机图形学编程练习8:MFC+明暗处理实现

MFC与OpenGL集成

在Windows下编程,利用MFC是一个非常便捷的方法。本次练习的主要目的,是希望同学们在MFC应用程序框架下进行OpenGL编程。为此,需要对MFC生成的应用程序进行适当的初始化,关于这方面的内容详见: [1] Crain, Dennis. \April 1994. (MSDN Library, Technical Articles) [2] Rogerson, Dale. \. December 1994. (MSDN Library, Technical Articles)

[3] D. Shreiner and The Khronos OpenGL ARB Working Group. OpenGL Programming Guide: The Official Guide to Learning OpenGL, Versions 3.0 and 3.1, 7th Ed., 2009. (附录D)

从设计目标来说,OpenGL是流水线结构(streamlined)、硬件无关(hardware-independent)、跨平台的3D图形编程API。但是,在实际应用时,OpenGL的具体实现是与操作系统以及图形硬件相关的。为此,操作系统需要提供像素格式(pixel format)与绘制上下文管理函数(rendering context managnment functions)。Windows操作系统提供了通用图形设备接口(generic graphics device interface, GDI)以及设备驱动实现。为了使OpenGL命令得到正确的执行,需要调用WGL函数,具体的步骤如下:

Step 1: 添加成员变量

在CView类(利用AppWizard生成)中添加如下成员变量:

// OpenGL Windows specification HDC m_hDC;

// Device Context // Rendering Context

HGLRC m_hGLRC;

CPalette m_cGLLP; // Logical Palette

Step 2: 设置像素格式

创建CView类的WM_CREATE的消息响应函数,进行像素格式的设置,例如:

int COpenGLRenderView::OnCreate(LPCREATESTRUCT lpCreateStruct) {

if (CView::OnCreate(lpCreateStruct) == -1)

// TODO: Add your specialized creation code here int nPixelFormat;

// Pixel format index // Get the window's handle // Get the Device context

HWND hWnd = GetSafeHwnd(); m_hDC = ::GetDC(hWnd);

static PIXELFORMATDESCRIPTOR pfd = {

sizeof(PIXELFORMATDESCRIPTOR),

1,

PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL |

// Size of this structure // Version of this structure

// Draw to Window (not to bitmap) // Support OpenGL calls in window

return -1;

}

PFD_DOUBLEBUFFER, PFD_TYPE_RGBA, 24, 0,0, 32, 0, 0, 0,

0,0,0,0,0,0, 0,0,0,0,0,

// Double buffered mode // RGBA Color mode // Want 24bit color // Not used to select mode // Not used to select mode // Not used to select mode // Size of depth buffer // Not used to select mode // Not used to select mode // Draw in main plane // Not used to select mode // Not used to select mode

PFD_MAIN_PLANE, 0,0,0 };

// Choose a pixel format that best matches that described in pfd nPixelFormat = ChoosePixelFormat(m_hDC, &pfd);

// Set the pixel format for the device context VERIFY(SetPixelFormat(m_hDC, nPixelFormat, &pfd));

// Create the rendering context m_hGLRC = wglCreateContext(m_hDC);

// Create the palette if needed InitializePalette();

// Make the rendering context current, perform initialization, then deselect it VERIFY(wglMakeCurrent(m_hDC, m_hGLRC)); GLSetupDef(m_hDC);

wglMakeCurrent(NULL, NULL);

return 0;

上述步骤的具体含义参看参考文献[1-3].

Step 3: 创建绘制上下文

该步骤在Step 2中已完成,具体的就是:

m_hGLRC = wglCreateContext(m_hDC);

Step 4: 设置调色板

创建CView类的一个成员函数,进行调色板的设置,例如:

void CTriangularPatchView::InitializePalette(void) {

PIXELFORMATDESCRIPTOR pfd; // Pixel Format Descriptor LOGPALETTE *pPal;

// Pointer to memory for logical palette

int nPixelFormat; int nColors; int i;

// Pixel format index

// Number of entries in palette // Counting variable

BYTE RedRange,GreenRange,BlueRange; // Range for each color entry (7,7,and 3)

// Get the pixel format index and retrieve the pixel format description nPixelFormat = GetPixelFormat(m_hDC);

DescribePixelFormat(m_hDC, nPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd);

// Does this pixel format require a palette? If not, do not create a // palette and just return NULL

if (!(pfd.dwFlags & PFD_NEED_PALETTE))

// Number of entries in palette. 8 bits yeilds 256 entries nColors = 1 << pfd.cColorBits;

// Allocate space for a logical palette structure plus all the palette entries pPal = (LOGPALETTE*)malloc(sizeof(LOGPALETTE) +nColors*sizeof(PALETTEENTRY));

// Fill in palette header pPal->palVersion = 0x300;

// Build mask of all 1's. This creates a number represented by having // the low order x bits set, where x = pfd.cRedBits, pfd.cGreenBits, and // pfd.cBlueBits.

RedRange = (1 << pfd.cRedBits) -1; GreenRange = (1 << pfd.cGreenBits) - 1; BlueRange = (1 << pfd.cBlueBits) -1;

// Loop through all the palette entries for (i = 0; i < nColors; i++) {

// Fill in the 8-bit equivalents for each component

pPal->palPalEntry[i].peRed = (i >> pfd.cRedShift) & RedRange; pPal->palPalEntry[i].peRed = (unsigned char)(

pPal->palPalEntry[i].peGreen = (i >> pfd.cGreenShift) & GreenRange; pPal->palPalEntry[i].peGreen = (unsigned char)(

(double)pPal->palPalEntry[i].peGreen * 255.0 / GreenRange); (double) pPal->palPalEntry[i].peRed * 255.0 / RedRange);

// Windows 3.0

pPal->palNumEntries = nColors; // table size

return;

}

}

// Create the palette

m_cGLLP.CreatePalette(pPal);

// Go ahead and select and realize the palette for this device context SelectPalette(m_hDC,(HPALETTE)m_cGLLP,FALSE); RealizePalette(m_hDC);

// Free the memory used for the logical palette structure free(pPal);

pPal->palPalEntry[i].peBlue = (i >> pfd.cBlueShift) & BlueRange; pPal->palPalEntry[i].peBlue = (unsigned char)(

pPal->palPalEntry[i].peFlags = (unsigned char) NULL;

(double)pPal->palPalEntry[i].peBlue * 255.0 / BlueRange);

至此,已经可以调用OpenGL函数了,一定要记住:OpenGL命令只在获取了正确的绘制上下文后才能正确执行,即

wglMakeCurrent(m_hDC, m_hGLRC); // issue OpenGL commands wglMakeCurrent(m_hDC, NULL);

…..

Step 5: 重载OnEraseBkgnd函数

创建CView类的WM_ERASEBKGND的消息响应函数,防止Windows进行额外的背景清除操作,例如:

BOOL COpenGLRenderView::OnEraseBkgnd(CDC* pDC) { }

// TODO: Add your message handler code here and/or call default

return FALSE;

Step 6: 设置OpenGL的基本参数(可选)

在CView类中添加头文件:

#include #include #include

以及成员函数:

void GLSetupDef(void *pData);

创建CView类的一个成员函数,进行OpenGL的基本参数的设置,例如:

void COpenGLRenderView::GLSetupDef(void *pData) {