我的第1个OpenGL ES程序 for WinCE5 HTC TouchHD

cheungmine

中午吃过饭,闲来无事,看着我的手机(HTC TouchHD),忽然想编一个OpenGL程序玩玩。下载了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.right - r.left, r.bottom - );

/*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:///index.php/OpenGL_ES%E7%AE%80%E4%BB%8B​

 

你会像我一样,从上面学到更多的知识。