我的第1个OpenGL ES程序 for WinCE5 HTC TouchHD
cheungmine
中午吃过饭,闲来无事,看着我的手机(HTC TouchHD),忽然想编一个OpenGL程序玩玩。CSDN上下载了OpenGL ES的开发包。
解压之后发现了:bin/arm/Release目录下有几个文件:
libGLES_CM.dll
libGLES_CM.lib
libGLES_CM.exp
等等。就准备把 libGLES_CM.dll 拷贝到我的手机的Windows下,提示已经有了这个文件,要不要覆盖?当然不覆盖。原来我的TouchHD支持OGL啊。太好了,马上编译例子Tutorial 1代码。其实就是新建一个Win32的移动程序空项目,平台是Windows Mobile 6.0Professional,然后把tutorial1.h和tutorial1.cpp文件拷贝到我的项目里,并添加到项目。编译不通过,提示文件目录不存在。马上添加包含目录和包含的库选项。编译通过。但是部署后,运行,失败。
网上搜,结果例子代码有问题,改正后的代码如下:
#ifndef _TUTORIAL1_H #define _TUTORIAL1_H #include <windows.h> //needed include for window system calls //OpenGL ES Includes #include <GLES/gl.h> /*EGL is the "machine" that glues OpenGL ES with the underlying windowing system. We need it to create a suitable context and a drawable window*/ #include <GLES/egl.h> /*Because we are building software device dependent (the PDA), we have care about its limitations. PDA's doesn't have a FPU unit, so all floating point operations are emulated in the CPU. To have real data type, PDA's uses reals with a fixed point format. For a fixed point number we only need an integer, with the same size (in bytes) that a float, that is, a normal int number. The first 16 bits of the int will be the "integer" part, and the last 16 bits will be the "real" part. This will cause a lack of precision, but it is better than emulate all FPU in the CPU. To convert an integer number to a fixed point number we need to displace its bits to the left, as the FixedFromInt function does. In this chapter we only will need the conversion int->fixed point. Other conversions will be showed when needed, in later chapters. A complete description of the fixed point maths is beyond the purpose of this set of tutorials, but the topic will be widely covered through the chapters. OpenGL ES offers us a set of functions that works with fixed point (Glfixed). These functions are available through the OpenGL ES OES_fixed_point extension. A little word about the OpenGL ES extensions: They are divided into two categories: those that are fully integrated into the profile definition (core additions); and those that remain extensions (profile extensions). Core additions do not use extension suffixes and does not requires initialization, whereas profile extensions retain their extension suffixes. OES_fixed_point is a core addition. The other extensions are listed and explained in the OpenGL ES 1.1 specification.*/ #define PRECISION 16 #define ONE (1 << PRECISION) #define ZERO 0 inline GLfixed FixedFromInt(int value) {return value << PRECISION;}; int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPTSTR lpCmdLine,int nCmdShow); LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); BOOL InitOGLES();// Our GL initialization function void Render(); // Our Render function void Clean(); //Our clean function. It will clean all used resources #endif
#include "tutorial1.h" //We need the defines and prototypes of there // cheungmine #pragma comment(lib, "E:/GU2005/GCE/OpenGL_ES_WCE/ogl-es-bin-0.83/dist/bin/arm/Debug/libGLES_CM.lib") //Some useful global handles HINSTANCE hInst; //Will hold the current instance of the application HWND hWnd; // A handle to the window we will create HDC hDC; // A handle to the device context of the window. Needed to //create the OpenGL ES context // OpenGL variables EGLDisplay glesDisplay; // EGL display EGLSurface glesSurface; // EGL rendering surface EGLContext glesContext; // EGL rendering context TCHAR szAppName[] = L"OpenGLES"; /*The application name and the window caption*/ /*This is the WinMain function. Here we will create the rendering window, initialize OpenGL ES, write the message loop, and, at the end, clean all and release all used resources*/ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { MSG msg; //This is the message variable for the message loop WNDCLASS wc; /*This structure will hold some init values for our window*/ hInst = hInstance; // Initialization of our global variable bool done = FALSE; /*This block of code is to ensure that the user only can run one instance of the application. First we search for a window with the same class name, if found, we will focus it and return*/ if(hWnd = FindWindow(szAppName, szAppName)) { /* Set focus to foremost child window. The "| 0x01" is used to bring any owned windows to the foreground and activate them.*/ SetForegroundWindow((HWND)((ULONG) hWnd | 0x00000001)); return 0; } wc.style = CS_HREDRAW | CS_VREDRAW; /*Will force a redraw if the window is resized, both horizontally or vertically*/ wc.lpfnWndProc = (WNDPROC) WndProc; /*this is a function pointer, to tell the OS what function should call when a message needs to be processed*/ wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon(hInstance, NULL);//Load default icon wc.hCursor = 0; // Default cursor wc.hbrBackground = 0; //We don't care about the background color wc.lpszMenuName = NULL; //This application does not have a menu wc.lpszClassName = szAppName; /*Important, here we must fill the application class name (the class name is not the same than the caption of the window, but many times they are the same)*/ //Before creating the window, we must register this new window class if(!RegisterClass(&wc)) return FALSE; hWnd=CreateWindow(szAppName, //Class Name szAppName, //Caption string WS_VISIBLE,//Window style CW_USEDEFAULT,CW_USEDEFAULT,//Starting [x,y] pos. CW_USEDEFAULT, CW_USEDEFAULT, //Width and height NULL, NULL, //Parent window and menu handle hInst, NULL); /*Instance handle. Custom value to pass in the creation with the WM_CREATE message*/ if(!hWnd) return FALSE; if(!InitOGLES()) return FALSE; //OpenGL ES Initialization //Bring the window to front, focus it and refresh it ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); //Message Loop while(!done) { if(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) { if(msg.message==WM_QUIT) done=TRUE; else { TranslateMessage(&msg); DispatchMessage(&msg); } } else Render(); } //Clean up all Clean(); return 0; } //---------------------------------------------------------------------------- LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_PAINT: ValidateRect(hWnd,NULL); //Needed to avoid new WM_PAINT messages return 0; case WM_DESTROY: PostQuitMessage(0); return 0; }; return DefWindowProc(hWnd, message, wParam, lParam); } //---------------------------------------------------------------------------- BOOL InitOGLES() { EGLint matchingConfigs; hDC = GetWindowDC(hWnd); glesDisplay = eglGetDisplay(hDC); //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, NULL, NULL ) == EGL_FALSE || eglGetError() != EGL_SUCCESS ) 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[3] = { 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); /*In order to set a viewport that fits entirely our window, we need to know the window dimensions. They could be obtained through the WinCE call GetWindowRect, using our window handle*/ RECT r; GetWindowRect(hWnd, &r); glViewport(r.left, r.top, r.right - r.left, r.bottom - r.top); /*Setup of the projection matrix. We will use an ortho cube centered at (0,0,0) with 100 units of edge*/ glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrthox(FixedFromInt(-50), FixedFromInt(50), FixedFromInt(-50), FixedFromInt(50), FixedFromInt(-50), FixedFromInt(50)); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); return TRUE; } //---------------------------------------------------------------------------- void Render() { static int rotation = 0; /* Vertex 1 Vertex 2 Vertex 3*/ GLshort vertexArray[9] = {-25,-25,0, 25,-25,0, 0,25,0 }; GLubyte colorArray[12] = {255,0,0,0, 0,255,0,0, 0,0,255,0}; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); glTranslatex(0, 0, FixedFromInt(-10)); glRotatex(FixedFromInt(rotation++), 0, ONE,0); //Enable the vertices array glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(3, GL_SHORT, 0, vertexArray); //3 = XYZ coordinates, GL_SHORT = data type, 0 = 0 stride bytes //Enable the vertex color array glEnableClientState(GL_COLOR_ARRAY); glColorPointer(4,GL_UNSIGNED_BYTE, 0, colorArray); //4 = RGBA format, GL_UNSIGNED_BYTE = data type,0=0 stide bytes glDrawArrays(GL_TRIANGLES, 0, 3); /*We want draw triangles, 0 = first element(vertice), 3 = number of items (vertices) to draw from the array*/ glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_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); } //We have to destroy the window too DestroyWindow(hWnd); UnregisterClass(szAppName, hInst); }
运行,结果出来了,很好。一个OGL窗口在我的手机里。中间一个缓缓转动的三角形。
好了,该干活了。就闲扯到这里。以后我还会陆续发布一些OGL ES的东西,无论我自己写的还是抄来的,权作茶余饭后的消遣。
下面是我看过的链接:
http://sourceforge.net/projects/ogl-es/files/
http://wiki.forum.nokia.com/index.php/OpenGL_ES%E7%AE%80%E4%BB%8B
http://blog.csdn.net/dymx101/archive/2010/02/03/5284348.aspx
你会像我一样,从上面学到更多的知识。