WinCE OpenGL繪製立方體和紋理貼圖

        最近工作之餘,開始學習OpenGL,  想到WINCE也是支持OpenGL的,只不過是嵌入式的OpenGL ES。於是嘗試寫了一個WINCE下的OpenGL測試程序,實現了繪製立方體和紋理。效果圖如下:

     

      需要注意的是,WINCE系統上開發OpenGL程序需具備以下條件:

      1. 處理器的支持,嵌入式處理器需支持3D加速渲染(測試使用的是Telichips 8901);

      2. WINCE內核的支持,定製內核時需添加OpenGL ES相關組件。

      以下是具體的參考代碼:

/********************************************************************
filename: 	WinceOpenGLDemo.cpp
created:	2011-01-05
author:		firehood
purpose:	利用OpenGL ES實現了繪製立方體和紋理效果
*********************************************************************/

// WinceOpenGLDemo.cpp : 定義應用程序的入口點。
//

#include "stdafx.h"
#include "WinceOpenGLDemo.h"
#include <windows.h>
#include <commctrl.h>
#include "ImgLoader.h"
// OpenGL ES Includes   
#include <GLES/gl.h>
#include <GLES/glext.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>

// OpenGL lib
#pragma comment(lib, "OpenGlLib\\libGLESv1_CM.lib")   
#pragma comment(lib, "OpenGlLib\\libEGL.lib")

// 全局變量:
HINSTANCE	g_hInst;			// 當前實例
TCHAR       szAppName[] = L"OpenGLES";        /*The application name and the window caption*/
CImgLoader  g_Image;
// OpenGL variables   
EGLDisplay glesDisplay;  // EGL display   
EGLSurface glesSurface;  // EGL rendering surface   
EGLContext glesContext;  // EGL rendering context  

GLuint texture[6] = {0};  

// 立方體定點座標
GLshort vertices[] = {  
	-1,-1,1,  
	1,-1,1,  
	1,1,1,  
	-1,1,1,  

	-1,-1,-1,  
	-1,1,-1,  
	1,1,-1,  
	1,-1,-1,  

	-1,1,-1,  
	-1,1,1,  
	1,1,1,  
	1,1,-1,  

	-1,-1,-1,  
	1,-1,-1,  
	1,-1,1,  
	-1,-1,1,  

	1,-1,-1,  
	1,1,-1,  
	1,1,1,  
	1,-1,1,  

	-1,-1,-1,  
	-1,-1,1,  
	-1,1,1,  
	-1,1,-1
};  

// 各個面紋理座標
GLshort texCoords[] = {  
	0,0,1,0,1,1,0,1,      
	0,0,1,0,1,1,0,1,     
	0,0,1,0,1,1,0,1,     
	0,0,1,0,1,1,0,1,     
	0,0,1,0,1,1,0,1,     
	0,0,1,0,1,1,0,1,     
};  

// 三角形索引數據
GLbyte indices1[] = {  
	0,1,3,2,  
	0,0,0,0,  
	0,0,0,0,  
	0,0,0,0,  
	0,0,0,0,  
	0,0,0,0 
}; 
GLbyte indices2[] = {  
	0,0,0,0,  
	4,5,7,6,  
	0,0,0,0,  
	0,0,0,0,  
	0,0,0,0,  
	0,0,0,0 
}; 
GLbyte indices3[] = {  
	0,0,0,0,  
	0,0,0,0,  
	8,9,11,10,  
	0,0,0,0,  
	0,0,0,0,  
	0,0,0,0 
};  
GLbyte indices4[] = {  
	0,0,0,0,  
	0,0,0,0,  
	0,0,0,0,  
	12,13,15,14,  
	0,0,0,0,  
	0,0,0,0
};  
GLbyte indices5[] = {  
	0,0,0,0,  
	0,0,0,0,  
	0,0,0,0,  
	0,0,0,0,  
	16,17,19,18,  
	0,0,0,0
};  
GLbyte indices6[] = {  
	0,0,0,0,  
	0,0,0,0,  
	0,0,0,0,  
	0,0,0,0,  
	0,0,0,0,  
	20,21,23,22
};

// 此代碼模塊中包含的函數的前向聲明:
ATOM			MyRegisterClass(HINSTANCE, LPTSTR);
BOOL			InitInstance(HINSTANCE, int);
LRESULT CALLBACK	WndProc(HWND, UINT, WPARAM, LPARAM);

BOOL InitOGLES(HWND hWnd);
void CreateSurface();
BOOL LoadTexture(LPCTSTR lpFileName,GLuint *id);
void Render();
void Clean();

int WINAPI WinMain(HINSTANCE hInstance,
                   HINSTANCE hPrevInstance,
                   LPTSTR    lpCmdLine,
                   int       nCmdShow)
{
	MSG msg;

	// 執行應用程序初始化:
	if (!InitInstance(hInstance, nCmdShow)) 
	{
		return FALSE;
	}

	BOOL done = FALSE;
	// 主消息循環:
	while(!done)  
	{  
		if(PeekMessage(&msg,NULL,0,0,PM_REMOVE))  
		{  
			if(msg.message==WM_QUIT)  
				done = TRUE;  
			else  
			{   
				TranslateMessage(&msg);  
				DispatchMessage(&msg);  
			}  
		}  
		else
		{
			Render();
		};
	}  

	return (int) msg.wParam;
}

//
//  函數: MyRegisterClass()
//
//  目的: 註冊窗口類。
//
//  註釋:
//
ATOM MyRegisterClass(HINSTANCE hInstance, LPTSTR szWindowClass)
{
	WNDCLASS wc;

	wc.style         = CS_HREDRAW | CS_VREDRAW;
	wc.lpfnWndProc   = WndProc;
	wc.cbClsExtra    = 0;
	wc.cbWndExtra    = 0;
	wc.hInstance     = hInstance;
	wc.hIcon         = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WINCEOPENGLDEMO));
	wc.hCursor       = 0;
	wc.hbrBackground = (HBRUSH) GetStockObject(NULL_BRUSH);
	wc.lpszMenuName  = 0;
	wc.lpszClassName = szWindowClass;

	return RegisterClass(&wc);
}

//
//   函數: InitInstance(HINSTANCE, int)
//
//   目的: 保存實例句柄並創建主窗口
//
//   註釋:
//
//        在此函數中,我們在全局變量中保存實例句柄並
//        創建和顯示主程序窗口。
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
    HWND hWnd;

    g_hInst = hInstance; // 將實例句柄存儲在全局變量中

    if (!MyRegisterClass(hInstance, szAppName))
    {
    	return FALSE;
    }

    hWnd = CreateWindow(
		szAppName,
		szAppName,
		WS_VISIBLE,
        0,
		0,
		::GetSystemMetrics(SM_CXSCREEN),
		::GetSystemMetrics(SM_CYSCREEN),
		NULL,
		NULL,
		hInstance,
		NULL);

    if (!hWnd)
    {
        return FALSE;
    }
   
	if(!InitOGLES(hWnd))
	{
		printf("InitOGLES failed\n");
		return FALSE;
	}
	CreateSurface();

    ShowWindow(hWnd, SW_SHOW);
    UpdateWindow(hWnd);

    return TRUE;
}

//
//  函數: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  目的: 處理主窗口的消息。
//
//  WM_COMMAND	- 處理應用程序菜單
//  WM_PAINT	- 繪製主窗口
//  WM_DESTROY	- 發送退出消息並返回
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    PAINTSTRUCT ps;
    HDC hdc;

    switch (message) 
    {
        case WM_CREATE:
            break;
        case WM_PAINT:
            hdc = BeginPaint(hWnd, &ps);
            
            // TODO: 在此添加任意繪圖代碼...
            
            EndPaint(hWnd, &ps);
            break;
        case WM_DESTROY:
			{
				Clean();
				PostQuitMessage(0);
			}
            break;

        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

BOOL InitOGLES(HWND hWnd)
{    
	EGLint matchingConfigs;     
	EGLint majorVersion = 0;  
	EGLint minorVersion = 0;  

	glesDisplay = eglGetDisplay(GetDC(hWnd));  //Ask for an available display 
	if( glesDisplay == EGL_NO_DISPLAY || eglGetError() != EGL_SUCCESS )  
		return FALSE;  

	EGLConfig *configs_list;  
	EGLint     num_configs;  
	// Display initialization (we don't care about the OGLES version numbers)   
	if( eglInitialize( glesDisplay, &majorVersion, &minorVersion) == EGL_FALSE)  
	{
		printf("eglInitialize failed, eglGetError = 0x%04x\n",eglGetError());
		return FALSE;  
	}
	// find out how many configurations are supported   
	if ( eglGetConfigs( glesDisplay, NULL, 0, &num_configs)==EGL_FALSE || eglGetError() != EGL_SUCCESS )  
		return FALSE;  
	configs_list = (EGLConfig*) malloc(num_configs * sizeof(EGLConfig));  
	if (configs_list == NULL)  
		return FALSE;  
	// Get Configurations   
	if( eglGetConfigs( glesDisplay, configs_list, num_configs, &num_configs)== EGL_FALSE || eglGetError() != EGL_SUCCESS )  
		return FALSE;  
	// Obtain the first configuration with a depth buffer of 16 bits   
	EGLint attrs[] = {
		EGL_RED_SIZE,      5,
		EGL_GREEN_SIZE,    6,
		EGL_BLUE_SIZE,     5,
		EGL_DEPTH_SIZE,   16,
		EGL_NONE
	};
	if (!eglChooseConfig(glesDisplay, attrs, configs_list, num_configs, &matchingConfigs))  
	{  
		return eglGetError();  
	}  
	// If there isn't any configuration enough good   
	if (matchingConfigs < 1)    
		return FALSE;     
	/*eglCreateWindowSurface creates an onscreen EGLSurface and returns  
	a handle  to it. Any EGL rendering context created with a  
	compatible EGLConfig can be used to render into this surface.*/  
	glesSurface = eglCreateWindowSurface(glesDisplay, configs_list[0], hWnd, 0);    
	if(!glesSurface)   
		return FALSE;  

	// Let's create our rendering context   
	glesContext=eglCreateContext(glesDisplay, configs_list[0], 0, 0);  
	if(!glesContext)   
		return FALSE;  
	//Now we will activate the context for rendering     
	eglMakeCurrent(glesDisplay, glesSurface, glesSurface, glesContext);   

	/*Remember: because we are programming for a mobile device, we cant  
	use any of the OpenGL ES functions that finish in 'f', we must use  
	the fixed point version (they finish in 'x'*/  
	glClearColorx(0, 0, 0, 0);  
	glShadeModel(GL_SMOOTH);    
 
	RECT rc;  
	GetWindowRect(hWnd, &rc);  
	UINT width = rc.right - rc.left;
	UINT height = rc.bottom - rc.top;
	// 設置OpenGL場景的大小   
	glViewport(rc.left, rc.top, width, height);      

	// 設置投影矩陣   
	glMatrixMode(GL_PROJECTION);  
	glLoadIdentity();
	
	// 投影變換(透視投影)
	float ratio = (float) width / height;  
	glFrustumf(-ratio, ratio, -1, 1, 2, 10);
	//glOrthox(FixedFromInt(-50),FixedFromInt(50), FixedFromInt(-50), FixedFromInt(50), FixedFromInt(-50), FixedFromInt(50));
	
	// 選擇模型觀察矩陣   
	glMatrixMode(GL_MODELVIEW);   
	// 重置模型觀察矩陣   
	glLoadIdentity();  

	return TRUE;  
}

void CreateSurface()  
{  
	glDisable(GL_DITHER);  

	// 告訴系統對透視進行修正   
	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);  
	// 黑色背景   
	glClearColor(0, 0, 0, 0);  
	
	// 啓用陰影平滑   
	glShadeModel(GL_SMOOTH);  
	
	// 設置深度緩存
	glClearDepthf(1.0f);  
	// 啓用深度測試   
	glEnable(GL_DEPTH_TEST);  
	// 所作深度測試的類型
	glDepthFunc(GL_LEQUAL);  
	
	// 啓用2D紋理
	glEnable(GL_TEXTURE_2D); 
	// 加載紋理
	LoadTexture(_T("\\NAND2\\OpenGlRes\\1.png"),&texture[0]);
	LoadTexture(_T("\\NAND2\\OpenGlRes\\1.png"),&texture[1]);
	LoadTexture(_T("\\NAND2\\OpenGlRes\\1.png"),&texture[2]);
	LoadTexture(_T("\\NAND2\\OpenGlRes\\1.png"),&texture[3]);
	LoadTexture(_T("\\NAND2\\OpenGlRes\\1.png"),&texture[4]);
	LoadTexture(_T("\\NAND2\\OpenGlRes\\1.png"),&texture[5]);
}

void Render()
{
	static float rotation = 0;
	// 清除屏幕和深度緩存   
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);  

	glMatrixMode(GL_MODELVIEW);  
	// 重置當前的模型觀察矩陣   
	glLoadIdentity();  

	// 座標變換
	glTranslatef(0.0f, 0.0f, -5.0f);  

	// 設置旋轉   
	glRotatef(rotation++, 0.0f, 1.0f, 0.0f);  
	glRotatef(rotation++, 1.0f, 0.0f, 0.0f);  
	
	glEnableClientState(GL_VERTEX_ARRAY);  
	glEnableClientState(GL_TEXTURE_COORD_ARRAY); 

	glVertexPointer(3, GL_SHORT, 0, vertices);  
	glTexCoordPointer(2, GL_SHORT, 0, texCoords);   

	// 繪製立方體並綁定紋理
	glBindTexture(GL_TEXTURE_2D, texture[0]);
	glDrawElements(GL_TRIANGLE_STRIP, 4,  GL_UNSIGNED_BYTE, indices1);  
	glBindTexture(GL_TEXTURE_2D, texture[1]);
	glDrawElements(GL_TRIANGLE_STRIP, 8,  GL_UNSIGNED_BYTE, indices2);  
	glBindTexture(GL_TEXTURE_2D, texture[2]);
	glDrawElements(GL_TRIANGLE_STRIP, 12,  GL_UNSIGNED_BYTE, indices3);  
	glBindTexture(GL_TEXTURE_2D, texture[3]);
	glDrawElements(GL_TRIANGLE_STRIP, 16,  GL_UNSIGNED_BYTE, indices4);  
	glBindTexture(GL_TEXTURE_2D, texture[4]);
	glDrawElements(GL_TRIANGLE_STRIP, 20,  GL_UNSIGNED_BYTE, indices5);  
	glBindTexture(GL_TEXTURE_2D, texture[5]);
	glDrawElements(GL_TRIANGLE_STRIP, 24,  GL_UNSIGNED_BYTE, indices6);  

	glDisableClientState(GL_TEXTURE_COORD_ARRAY);  
	glDisableClientState(GL_VERTEX_ARRAY);  

	eglSwapBuffers(glesDisplay, glesSurface);  
}

void Clean()
{  
	if(glesDisplay)  
	{  
		eglMakeCurrent(glesDisplay, NULL, NULL, NULL);    
		if(glesContext) eglDestroyContext(glesDisplay, glesContext);  
		if(glesSurface) eglDestroySurface(glesDisplay, glesSurface);  
		eglTerminate(glesDisplay);  
	}
}   

BOOL LoadTexture(LPCTSTR lpFileName,GLuint *id)
{
	if(!g_Image.Load(lpFileName))
		return FALSE;
	
	// 創建紋理
	glGenTextures(1, id);
	// 綁定紋理
	glBindTexture(GL_TEXTURE_2D, *id);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 

	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, g_Image.Width(), g_Image.Height(), 0, GL_RGB, GL_UNSIGNED_BYTE, g_Image.GetBmpImage()); 

	g_Image.Free();

	return TRUE;
}


 以下實現了一個文件加載類,用以將外部圖片資源轉化成繪製紋理時所需的位圖數據。參考代碼如下:

/********************************************************************
filename: 	CImgLoader.h
created:	2011-01-05
author:		firehood

purpose:	文件加載類,將外部圖片資源轉化成繪製紋理時所需的位圖數據
            圖片格式支持bmp、png、jpg.
*********************************************************************/
#pragma once

class CImgLoader
{
public:
	CImgLoader(void);
	~CImgLoader(void);
public:
	// 加載圖片資源
	BOOL Load(LPCTSTR lpFileName);
	// 獲取位圖數據
	unsigned char* GetBmpImage(void);
	// 釋放圖片資源
	void Free();
	// 獲取圖像寬度
	int Width();
	// 獲取圖像高度
	int Height();
private:
	int m_Width;                  // 圖像寬度
	int m_Height;                 // 圖像高度
	unsigned char *m_pImage;      // 指向圖像數據的指針
};

 

/********************************************************************
filename: 	CImgLoader.cpp
created:	2011-01-05
author:		firehood

purpose:	文件加載類,將外部圖片資源轉化成繪製紋理時所需的位圖數據
            圖片格式支持bmp、png、jpg.
*********************************************************************/

#include "StdAfx.h"
#include "ImgLoader.h"
// IImage Includer
#include <imaging.h>
#include <initguid.h>
#include <imgguids.h> 
// IImage lib
#pragma comment(lib, "Imaging.lib")

CImgLoader::CImgLoader(void)
{
	m_pImage = NULL;
	m_Width = 0;
	m_Height = 0;
}

CImgLoader::~CImgLoader(void)
{
}

// 加載圖片資源
BOOL CImgLoader::Load(LPCTSTR lpFileName)
{
	IImagingFactory *pImgFactory = NULL;
	IImage *pImage = NULL;
	IBitmapImage *pBmpImg = NULL;
	// 
	CoInitializeEx(NULL, COINIT_MULTITHREADED);
	if (!SUCCEEDED(CoCreateInstance(CLSID_ImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_IImagingFactory, (void **) &pImgFactory))) 
		return FALSE;
	if (!SUCCEEDED(pImgFactory->CreateImageFromFile(lpFileName, &pImage))) 
		return FALSE;
	// 獲取圖像大小信息
	ImageInfo ImgInfo;
	pImage->GetImageInfo(&ImgInfo);

	m_Width = ImgInfo.Width;
	m_Height = ImgInfo.Height;

	if (FAILED(pImgFactory->CreateBitmapFromImage(
		pImage,m_Width,m_Height,PixelFormat24bppRGB,
		InterpolationHintDefault,&pBmpImg)))
	{
		return FALSE;
	}
	RECT rect = {0,0,m_Width,m_Height};
	BitmapData *BmpData = new BitmapData;

	if (FAILED(pBmpImg->LockBits(&rect,
		ImageLockModeRead|ImageLockModeWrite,
		PixelFormat24bppRGB,BmpData)))
	{
		return FALSE;
	}
	int line = BmpData->Stride;
	LPBYTE lpData, lpLine, lpCurPixel; 
	lpData = lpLine = (LPBYTE)BmpData->Scan0;   // 獲取BMP位圖實際值的地址指針
	// 若爲Bottom-Up(從下到上)的位圖,則指向buffer的結尾
	// 若爲Top-Down(從上到下)的位圖,則指向buffer的開頭
	// int nBytesPP = nBPP >> 3;     // 左移三位即除以8,獲取圖像每像素字節數
	m_pImage = new unsigned char[m_Width * m_Height * 3];
	memset(m_pImage, 0, m_Width * m_Height * 3);
	if(m_pImage == NULL)
		return FALSE;
	if (line>0)
	{
		int pos = m_Width * m_Height * 3-1;
		for(int i = 0; i<m_Height; i++)                  // 行
		{
			lpLine = lpData + i * line;               // 獲取圖像每一行地址指針
			for(int j = m_Width-1; j>-1; j--)           // 列
			{
				lpCurPixel = lpLine + j * 3;          // 獲取每行每像素地址指針
				m_pImage[pos--] = *lpCurPixel ;       // R
				m_pImage[pos--] = *(lpCurPixel + 1);  // G
				m_pImage[pos--] = *(lpCurPixel + 2);  // B
			}
		}
	}
	else
	{
		int pos = 0 ;
		for(int i = m_Height-1; i>-1; i--)               // 行
		{
			lpLine = lpData + i * line;               // 獲取圖像每一行地址指針
			for(int j = 0; j<m_Width; j++)              // 列
			{
				lpCurPixel = lpLine + j * 3;          // 獲取每行每像素地址指針
				m_pImage[pos++] = *(lpCurPixel + 2);  // R
				m_pImage[pos++] = *(lpCurPixel + 1);  // G
				m_pImage[pos++] = *lpCurPixel;        // B
			}
		}
	}
	if (FAILED(pBmpImg->UnlockBits(BmpData)))
	{
		return FALSE;
	}
	delete BmpData;
	pBmpImg = NULL;
	pImage->Release(); 
	pImgFactory->Release(); 
	return TRUE;
}

// 獲取圖片數據
unsigned char* CImgLoader::GetBmpImage(void)
{
	return m_pImage;
}

// 獲取圖像寬度
int CImgLoader::Width()
{
	return m_Width;
}

// 獲取圖像高度
int CImgLoader::Height()
{
	return m_Height;
}

// 釋放圖片資源
void CImgLoader::Free()
{
	if(m_pImage)
	{
		delete []m_pImage;
		m_pImage = NULL;
	}
}


 


    

發佈了52 篇原創文章 · 獲贊 23 · 訪問量 38萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章