小弟使用OpenGL ES2.0在WinCE下画一个三角形,但结果出来的只有空白的窗口,其它什么都没有。请高手帮忙看下,不甚感激!!!!

时间:2021-11-25 07:20:41
小弟使用OpenGL ES2.0在WinCE下画一个三角形,但结果出来的只有空白的窗口,其它什么都没有。请高手帮忙看下,小弟不甚感激!!!!
以下是代码:
// Subproject1.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#include "resource.h"

#include <windows.h>
#include <commctrl.h>

#include <stdlib.h>
#include "esUtil.h"
#include "esUtil_win.h"

#include <stdio.h>

#include <EGL/egl.h>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>

#include <auirt.h>
#include <auirt_i.c>

#define CLASSNAME L"OpenGL ES2.0"
#define APPLICATIONNAME L"OpenGL ES2.0"
#define MAX_LOADSTRING 100


// Global Variables:
TCHAR szTitle[MAX_LOADSTRING];
TCHAR szWindowClass[MAX_LOADSTRING];
HINSTANCE g_hInst = NULL;
ESContext g_esContext = {0};

typedef struct
{
   // Handle to a program object
   GLuint programObject;

} UserData;



int WINAPI WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR     lpCmdLine,
                     int       nCmdShow)
{
MSG msg;
BOOL bRet;
int done = 0;
UserData  userData;

g_hInst = hInstance;
esInitContext ();
g_esContext.userData = &userData;


MyRegisterClass(hInstance);


if (!InitInstance (hInstance, nCmdShow)) 
{

return FALSE; 
}
bRet = esCreateWindow ("OpenGL ES2.0", 800, 480, ES_WINDOW_RGB);
if(0 == bRet)
{

return 0;
}

if ( !Init () )
{

return 0;
}

while (!done)
{
 int gotMsg = (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) != 0);
  if ( gotMsg )
  {
 if (msg.message==WM_QUIT)
     {
         done = 1; 
     }
     else
     {
         TranslateMessage(&msg); 
         DispatchMessage(&msg); 
     }
  }
  else
  {
SendMessage( g_esContext.hWnd, WM_PAINT, 0, 0 );
  }
}

return msg.wParam;
}


GLuint LoadShader ( GLenum type, const char *shaderSrc )
{
   GLuint shader;
   GLint compiled;
   
   // Create the shader object
   shader = glCreateShader ( type );

   if ( shader == 0 )
   {
RETAILMSG(1, (TEXT("shader = 0\r\n")));
return 0;
   }

   // Load the shader source
   glShaderSource ( shader, 1, &shaderSrc, NULL );
   
   // Compile the shader
   glCompileShader ( shader );

   // Check the compile status
   glGetShaderiv ( shader, GL_COMPILE_STATUS, &compiled );

   if ( !compiled ) 
   {
      glDeleteShader ( shader );
      return 0;
   }
   return shader;

}


int Init ()
{
   UserData *userData = (UserData *)g_esContext.userData;
   GLbyte vShaderStr[] =  
      "attribute vec4 vPosition;    \n"
      "void main()                  \n"
      "{                            \n"
      "   gl_Position = vPosition;  \n"
      "}                            \n";
   
   GLbyte fShaderStr[] =  
      "precision mediump float;\n"\
      "void main()                                  \n"
      "{                                            \n"
      "  gl_FragColor = vec4 ( 1.0, 0.0, 0.0, 1.0 );\n"
      "}                                            \n";

   GLuint vertexShader;
   GLuint fragmentShader;
   GLuint programObject;
   GLint linked;

   // Load the vertex/fragment shaders
   vertexShader = LoadShader ( GL_VERTEX_SHADER, (const char *)vShaderStr );
   fragmentShader = LoadShader ( GL_FRAGMENT_SHADER, (const char *)fShaderStr );

   // Create the program object
   programObject = glCreateProgram();
   if ( programObject == 0 )
   {
RETAILMSG(1, (TEXT("programObject = 0\r\n")));
return 0;
   }
      
   
   glAttachShader ( programObject, vertexShader );
   glAttachShader ( programObject, fragmentShader );
   // Bind vPosition to attribute 0   
   glBindAttribLocation ( programObject, 0, "vPosition" );

   // Link the program
   glLinkProgram ( programObject );
   // Check the link status
   glGetProgramiv ( programObject, GL_LINK_STATUS, &linked );
   if ( !linked ) 
   {
      glDeleteProgram ( programObject );
      return FALSE;
   }

   // Store the program object
   userData->programObject = programObject;
   glClearColor ( 0.0f, 0.0f, 0.0f, 0.0f );
   
   return TRUE;
   
}

///
// Draw a triangle using the shader pair created in Init()
//
void Draw ()
{
   UserData *userData = (UserData *)g_esContext.userData;
   GLfloat vVertices[] = {  0.0f,  0.5f, 0.0f, 
                           -0.5f, -0.5f, 0.0f,
                            0.5f, -0.5f, 0.0f };
      
  
   // Set the viewport
   glViewport ( 0, 0, g_esContext.width, g_esContext.height );
  
   // Clear the color buffer --.>  glClearColor 
   glClear ( GL_COLOR_BUFFER_BIT );

   // Use the program object
   glUseProgram ( userData->programObject );
   // Load the vertex data
   glVertexAttribPointer ( 0, 3, GL_FLOAT, GL_FALSE, 0, vVertices );
   glEnableVertexAttribArray ( 0 );

   glDrawArrays ( GL_TRIANGLES, 0, 3 );
 // glFlush();
   eglSwapBuffers ( g_esContext.eglDisplay, g_esContext.eglSurface );

}




//
//  FUNCTION: MyRegisterClass()
//
//  PURPOSE: Registers the window class.
//
//  COMMENTS:
//
//    This function and its usage is only necessary if you want this code
//    to be compatible with Win32 systems prior to the 'RegisterClassEx'
//    function that was added to Windows 95. It is important to call this function
//    so that the application will get 'well formed' small icons associated
//    with it.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASS wc;

    wc.style = 0;
    wc.lpfnWndProc = (WNDPROC) ESWindowProc;
wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = hInstance;
    wc.hIcon = NULL;
    wc.hCursor = NULL;
    wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
    wc.lpszMenuName = NULL;
    wc.lpszClassName = szWindowClass;
    return RegisterClass(&wc);
}

//
//   FUNCTION: InitInstance(HANDLE, int)
//
//   PURPOSE: Saves instance handle and creates main window
//
//   COMMENTS:
//
//        In this function, we save the instance handle in a global variable and
//        create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   g_esContext.hWnd = CreateWindow(szWindowClass, szTitle, (WS_VISIBLE | WS_POPUP | WS_BORDER | WS_SYSMENU | WS_CAPTION),
      0, 0, 800, 480, NULL, NULL, hInstance, NULL);

   if (!g_esContext.hWnd)
   {
      return FALSE;
   }

   ShowWindow(g_esContext.hWnd, nCmdShow);
   UpdateWindow(g_esContext.hWnd);
   return TRUE;
}


///
// CreateEGLContext()
//
//    Creates an EGL rendering context and all associated elements
//
EGLBoolean CreateEGLContext ( EGLNativeWindowType hWnd, EGLDisplay* eglDisplay,
                              EGLContext* eglContext, EGLSurface* eglSurface,
                              EGLint attribList[])
{
   EGLint numConfigs = 0;
   EGLint majorVersion;
   EGLint minorVersion;
   EGLDisplay display;
   EGLContext context;
   EGLSurface surface;
   EGLConfig eglConfig[68];
   EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE, EGL_NONE };



   // Get Display
   display = eglGetDisplay((EGLNativeDisplayType)EGL_DEFAULT_DISPLAY);
   if ( display == EGL_NO_DISPLAY )
   {
 return EGL_FALSE;
   }

   // Initialize EGL
   if ( !eglInitialize(display, &majorVersion, &minorVersion) )
   {
 return EGL_FALSE;
   }
   // Get configs
   if ( !eglGetConfigs(display, eglConfig, 68, &numConfigs) )
   {
 return EGL_FALSE;
   }

  // Choose config

   if ( !eglChooseConfig(display, attribList, eglConfig, 20, &numConfigs) )
   {
  return EGL_FALSE;
   }


   // Create a surface
   surface = eglCreateWindowSurface(display, eglConfig[0], hWnd, NULL);
   if ( surface == EGL_NO_SURFACE )
   {
 return EGL_FALSE;
   } 
   context = eglCreateContext(display, eglConfig[0], EGL_NO_CONTEXT, contextAttribs );
   if ( context == EGL_NO_CONTEXT )
   {
 return EGL_FALSE;
   }   


   // Make the context current
   if ( !eglMakeCurrent(display, surface, surface, context) )
   {
  return EGL_FALSE;
   }

   *eglDisplay = display;
   *eglSurface = surface;
   *eglContext = context;
   return EGL_TRUE;


//////////////////////////////////////////////////////////////////
//
//  Public Functions
//
//

///
//  esInitContext()
//
//      Initialize ES utility context.  This must be called before calling any other
//      functions.
//
void ESUTIL_API esInitContext ()
{

memset( &g_esContext, 0, sizeof(ESContext) );

}

///
//  esCreateWindow()
//
//      title - name for title bar of window
//      width - width of window to create
//      height - height of window to create
//      flags  - bitwise or of window creation flags 
//          ES_WINDOW_ALPHA       - specifies that the framebuffer should have alpha
//          ES_WINDOW_DEPTH       - specifies that a depth buffer should be created
//          ES_WINDOW_STENCIL     - specifies that a stencil buffer should be created
//          ES_WINDOW_MULTISAMPLE - specifies that a multi-sample buffer should be created
//
GLboolean ESUTIL_API esCreateWindow (const char* title, GLint width, GLint height, GLuint flags)
{
   EGLint attribList[] =
   {
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_RED_SIZE, 5,
EGL_GREEN_SIZE, 6,
EGL_BLUE_SIZE, 5,
EGL_DEPTH_SIZE, 1,
EGL_NONE
   };

 
   g_esContext.width = width;
   g_esContext.height = height;
   if ( !CreateEGLContext ( g_esContext.hWnd,
                            &g_esContext.eglDisplay,
                            &g_esContext.eglContext,
                            &g_esContext.eglSurface,
                            attribList) )
   {
  return GL_FALSE;
   }
   return GL_TRUE;
}


///
//  ESWindowProc()
//
//      Main window procedure
//
LRESULT WINAPI ESWindowProc ( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) 
{
LRESULT  lRet = 1; 
RECT  rRect = {0,0,800,480};
PAINTSTRUCT ps;

switch (uMsg) 
{
case WM_PAINT:

BeginPaint(g_esContext.hWnd, &ps);
Draw();
EndPaint(g_esContext.hWnd, &ps);
ValidateRect( g_esContext.hWnd, &rRect);
  break;

case WM_DESTROY:
 PostQuitMessage(0);             
 break; 

default: 
return DefWindowProc (hWnd, uMsg, wParam, lParam);         


return FALSE; 
}

8 个解决方案

#1


只会点OPENGL 1。0

#2


建议 LZ 先用标准的 Opengl 测试程序测试一下系统是否支持,就是那个叫“蚊子”的程序,呵呵...

#3


引用 2 楼 91program 的回复:
建议 LZ 先用标准的 Opengl 测试程序测试一下系统是否支持,就是那个叫“蚊子”的程序,呵呵...


“蚊子”? 可以说的再详细一点吗? 谢谢!!!

#4


opengl有什么蚊子啊,是91想多了吧,那是2D的,这个是3D。

建议从3个地方确认:
(1) 创建窗口,参数是否正确;
(2) 创建Surface,参数是否符合CPU要求;
(3) 创建context,参数是否正确;

另外,不同的CPU,有不同的参数说明,请参考厂商给的例子就OK。(如果有CPU型号,或许我可以给你个例子)

#5


(1)窗口创建没有返回错误(还是说上面代码中使用的参数不对,需要有特定的参数?)
(2)创建Surface和创建Context返回的值都不为0,在代码中多处使用glGetError()没有发现错误
(3)eglChooseConfig返回的支持个数为4
(4)现在修改的情况是:运行后为透明的窗口,需要拖动右上角的关闭按钮,窗口才可以显示出来,但窗口为黑色,没有三角形。
(5)如果可以给我一个测试是否支持OpenGL ES2.0的程序就更好了,谢谢!!  邮箱:767017087@qq.com

#6


我不知道你的例子哪里来的,反正是依赖于公用库EsUtil的。貌似是很早的代码,才会依赖这个东东。在wince平台,不怎么好用~还有auirt.h根本不知道是啥内容。不方便替你调试。

例子不方便上传,给你粘贴代码吧:

powerVR的SDK里边最简单的代码:
/******************************************************************************

 @File         OGLES2HelloTriangle_Windows.cpp

 @Title        OpenGL ES 2.0 Hello Triangle Tutorial

 @Version      

 @Copyright    Copyright (c) Imagination Technologies Limited.

 @Platform     .

 @Description  Basic Tutorial that shows step-by-step how to initialize OpenGL ES
               2.0, use it for drawing a triangle and terminate it.

******************************************************************************/
#include <stdio.h>
#include <windows.h>
#include <TCHAR.h>

#include <EGL/egl.h>
#include <GLES2/gl2.h>

/******************************************************************************
 Defines
******************************************************************************/
//#define NO_GDI 1 /* Remove the GDI functions */

#ifndef NO_GDI

// Windows class name to register
#define WINDOW_CLASS _T("PVRShellClass")

// Width and height of the window
#define WINDOW_WIDTH 640
#define WINDOW_HEIGHT 480

#endif

// Index to bind the attributes to vertex shaders
#define VERTEX_ARRAY 0

/******************************************************************************
 Global variables
******************************************************************************/

// Variable set in the message handler to finish the demo
bool g_bDemoDone = false;

/*!****************************************************************************
 @Function WndProc
 @Input hWnd Handle to the window
 @Input message Specifies the message
 @Input wParam Additional message information
 @Input lParam Additional message information
 @Return LRESULT result code to OS
 @Description Processes messages for the main window
******************************************************************************/
#ifndef NO_GDI
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
/*
Here we are handling 2 system messages: screen saving and monitor power.
They are especially relevent on mobile devices.
*/
#ifndef UNDER_CE
case WM_SYSCOMMAND:
{
switch (wParam)
{
case SC_SCREENSAVE: // Screensaver trying to start ?
case SC_MONITORPOWER: // Monitor trying to enter powersave ?
return 0; // Prevent this from happening
}
break;
}
#endif
// Handles the close message when a user clicks the quit icon of the window
case WM_CLOSE:
g_bDemoDone = true;
PostQuitMessage(0);
return 1;

default:
break;
}

// Calls the default window procedure for messages we did not handle
return DefWindowProc(hWnd, message, wParam, lParam);
}
#endif
/*!****************************************************************************
 @Function TestEGLError
 @Input pszLocation location in the program where the error took
place. ie: function name
 @Return bool true if no EGL error was detected
 @Description Tests for an EGL error and prints it
******************************************************************************/
bool TestEGLError(HWND hWnd, char* pszLocation)
{
/*
eglGetError returns the last error that has happened using egl,
not the status of the last called function. The user has to
check after every single egl call or at least once every frame.
*/
EGLint iErr = eglGetError();
if (iErr != EGL_SUCCESS)
{
#ifndef NO_GDI
TCHAR pszStr[256];
_stprintf(pszStr, _T("%s failed (%d).\n"), pszLocation, iErr);
MessageBox(hWnd, pszStr, _T("Error"), MB_OK|MB_ICONEXCLAMATION);
#endif
return false;
}

return true;
}

#7


2



/*!****************************************************************************
 @Function WinMain
 @Input hInstance Application instance from OS
 @Input hPrevInstance Always NULL
 @Input lpCmdLine command line from OS
 @Input nCmdShow Specifies how the window is to be shown
 @Return int result code to OS
 @Description Main function of the program
******************************************************************************/
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, TCHAR *lpCmdLine, int nCmdShow)
{
// Windows variables
HWND hWnd = 0;
HDC hDC = 0;

// EGL variables
EGLDisplay eglDisplay = 0;
EGLConfig eglConfig = 0;
EGLSurface eglSurface = 0;
EGLContext eglContext = 0;
EGLNativeWindowType eglWindow = 0;

// Matrix used for projection model view (PMVMatrix)
float pfIdentity[] =
{
1.0f,0.0f,0.0f,0.0f,
0.0f,1.0f,0.0f,0.0f,
0.0f,0.0f,1.0f,0.0f,
0.0f,0.0f,0.0f,1.0f
};

// Fragment and vertex shaders code
char* pszFragShader = "\
void main (void)\
{\
gl_FragColor = vec4(1.0, 1.0, 0.66 ,1.0);\
}";
char* pszVertShader = "\
attribute highp vec4 myVertex;\
uniform mediump mat4 myPMVMatrix;\
void main(void)\
{\
gl_Position = myPMVMatrix * myVertex;\
}";

/*
Step 0 - Create a EGLNativeWindowType that we can use for OpenGL ES output
*/
#ifndef NO_GDI
// Register the windows class
WNDCLASS sWC;
    sWC.style = CS_HREDRAW | CS_VREDRAW;
sWC.lpfnWndProc = WndProc;
    sWC.cbClsExtra = 0;
    sWC.cbWndExtra = 0;
    sWC.hInstance = hInstance;
    sWC.hIcon = 0;
    sWC.hCursor = 0;
    sWC.lpszMenuName = 0;
sWC.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
    sWC.lpszClassName = WINDOW_CLASS;
unsigned int nWidth = WINDOW_WIDTH;
unsigned int nHeight = WINDOW_HEIGHT;

ATOM registerClass = RegisterClass(&sWC);
if (!registerClass)
{
MessageBox(0, _T("Failed to register the window class"), _T("Error"), MB_OK | MB_ICONEXCLAMATION);
}
#if defined(UNDER_CE)
// Get the monitor dimensions
{
HMONITOR hMonitor;
BOOL bRet;
POINT p;
MONITORINFO sMInfo;

p.x = 0;
p.y = 0;
hMonitor = MonitorFromPoint(p, MONITOR_DEFAULTTOPRIMARY);
sMInfo.cbSize = sizeof(sMInfo);
bRet = GetMonitorInfo(hMonitor, &sMInfo);
if (!bRet)
{
MessageBox(0, _T("Failed to get monitor info"), _T("Error"), MB_OK|MB_ICONEXCLAMATION);
goto cleanup;
}

nWidth = sMInfo.rcMonitor.right - sMInfo.rcMonitor.left;
nHeight = sMInfo.rcMonitor.bottom - sMInfo.rcMonitor.top;
}
#endif
// Create the eglWindow
RECT sRect;
SetRect(&sRect, 0, 0, nWidth, nHeight);
AdjustWindowRectEx(&sRect, WS_CAPTION | WS_SYSMENU, false, 0);
hWnd = CreateWindow( WINDOW_CLASS, _T("HelloTriangle"), WS_VISIBLE | WS_SYSMENU,
 0, 0, nWidth, nHeight, NULL, NULL, hInstance, NULL);
eglWindow = hWnd;

// Get the associated device context
hDC = GetDC(hWnd);
if (!hDC)
{
MessageBox(0, _T("Failed to create the device context"), _T("Error"), MB_OK|MB_ICONEXCLAMATION);
goto cleanup;
}
#endif
/*
Step 1 - Get the default display.
EGL uses the concept of a "display" which in most environments
corresponds to a single physical screen. Since we usually want
to draw to the main screen or only have a single screen to begin
with, we let EGL pick the default display.
Querying other displays is platform specific.
*/
eglDisplay = eglGetDisplay(hDC);

    if(eglDisplay == EGL_NO_DISPLAY)
         eglDisplay = eglGetDisplay((EGLNativeDisplayType) EGL_DEFAULT_DISPLAY);
/*
Step 2 - Initialize EGL.
EGL has to be initialized with the display obtained in the
previous step. We cannot use other EGL functions except
eglGetDisplay and eglGetError before eglInitialize has been
called.
If we're not interested in the EGL version number we can just
pass NULL for the second and third parameters.
*/
EGLint iMajorVersion, iMinorVersion;
if (!eglInitialize(eglDisplay, &iMajorVersion, &iMinorVersion))
{
#ifndef NO_GDI
MessageBox(0, _T("eglInitialize() failed."), _T("Error"), MB_OK|MB_ICONEXCLAMATION);
#endif
goto cleanup;
}

/*
Step 3 - Make OpenGL ES the current API.
EGL provides ways to set up OpenGL ES and OpenVG contexts
(and possibly other graphics APIs in the future), so we need
to specify the "current API".
*/
eglBindAPI(EGL_OPENGL_ES_API);
if (!TestEGLError(hWnd, "eglBindAPI"))
{
goto cleanup;
}

/*
Step 4 - Specify the required configuration attributes.
An EGL "configuration" describes the pixel format and type of
surfaces that can be used for drawing.
For now we just want to use the default Windows surface,
i.e. it will be visible on screen. The list
has to contain key/value pairs, terminated with EGL_NONE.
 */
const EGLint pi32ConfigAttribs[] =
{
EGL_LEVEL, 0,
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
//EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
//EGL_NATIVE_RENDERABLE, EGL_FALSE,
//EGL_DEPTH_SIZE, EGL_DONT_CARE,
EGL_NONE
};

/*
Step 5 - Find a config that matches all requirements.
eglChooseConfig provides a list of all available configurations
that meet or exceed the requirements given as the second
argument. In most cases we just want the first config that meets
all criteria, so we can limit the number of configs returned to 1.
*/
int iConfigs;
if (!eglChooseConfig(eglDisplay, pi32ConfigAttribs, &eglConfig, 1, &iConfigs) || (iConfigs != 1))
{
#ifndef NO_GDI
MessageBox(0, _T("eglChooseConfig() failed."), _T("Error"), MB_OK|MB_ICONEXCLAMATION);
#endif
goto cleanup;
}

/*
Step 6 - Create a surface to draw to.
Use the config picked in the previous step and the native window
handle when available to create a window surface. A window surface
is one that will be visible on screen inside the native display (or
fullscreen if there is no windowing system).
Pixmaps and pbuffers are surfaces which only exist in off-screen
memory.
*/
eglSurface = eglCreateWindowSurface(eglDisplay, eglConfig, eglWindow, NULL);

    if(eglSurface == EGL_NO_SURFACE)
    {
        eglGetError(); // Clear error
        eglSurface = eglCreateWindowSurface(eglDisplay, eglConfig, NULL, NULL);
}

if (!TestEGLError(hWnd, "eglCreateWindowSurface"))
{
goto cleanup;
}

#8


3


/*
Step 7 - Create a context.
EGL has to create a context for OpenGL ES. Our OpenGL ES resources
like textures will only be valid inside this context
(or shared contexts)
*/
EGLint ai32ContextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
eglContext = eglCreateContext(eglDisplay, eglConfig, NULL, ai32ContextAttribs);
if (!TestEGLError(hWnd, "eglCreateContext"))
{
goto cleanup;
}

/*
Step 8 - Bind the context to the current thread and use our
window surface for drawing and reading.
Contexts are bound to a thread. This means you don't have to
worry about other threads and processes interfering with your
OpenGL ES application.
We need to specify a surface that will be the target of all
subsequent drawing operations, and one that will be the source
of read operations. They can be the same surface.
*/
eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext);
if (!TestEGLError(hWnd, "eglMakeCurrent"))
{
goto cleanup;
}

/*
Step 9 - Draw something with OpenGL ES.
At this point everything is initialized and we're ready to use
OpenGL ES to draw something on the screen.
*/

GLuint uiFragShader, uiVertShader; /* Used to hold the fragment and vertex shader handles */
GLuint uiProgramObject; /* Used to hold the program handle (made out of the two previous shaders */

// Create the fragment shader object
uiFragShader = glCreateShader(GL_FRAGMENT_SHADER);

// Load the source code into it
glShaderSource(uiFragShader, 1, (const char**)&pszFragShader, NULL);

// Compile the source code
glCompileShader(uiFragShader);

// Check if compilation succeeded
GLint bShaderCompiled;
    glGetShaderiv(uiFragShader, GL_COMPILE_STATUS, &bShaderCompiled);

if (!bShaderCompiled)
{
#ifndef NO_GDI
// An error happened, first retrieve the length of the log message
int i32InfoLogLength, i32CharsWritten;
glGetShaderiv(uiFragShader, GL_INFO_LOG_LENGTH, &i32InfoLogLength);

// Allocate enough space for the message and retrieve it
char* pszInfoLog = new char[i32InfoLogLength];
        glGetShaderInfoLog(uiFragShader, i32InfoLogLength, &i32CharsWritten, pszInfoLog);

// Displays the error in a dialog box
#ifndef UNDER_CE
MessageBox(hWnd, i32InfoLogLength ? pszInfoLog : _T(""), _T("Failed to compile fragment shader"), MB_OK|MB_ICONEXCLAMATION);
#else
TCHAR* pszTInfoLog = new TCHAR[i32InfoLogLength];

for(int i = 0; i < i32InfoLogLength; ++i)
pszTInfoLog[i] = (TCHAR) pszInfoLog[i];

MessageBox(hWnd, i32InfoLogLength ? pszTInfoLog : _T(""), _T("Failed to compile fragment shader"), MB_OK|MB_ICONEXCLAMATION);
delete[] pszTInfoLog;
#endif
delete[] pszInfoLog;
#endif
goto cleanup;
}

// Loads the vertex shader in the same way
uiVertShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(uiVertShader, 1, (const char**)&pszVertShader, NULL);
glCompileShader(uiVertShader);
    glGetShaderiv(uiVertShader, GL_COMPILE_STATUS, &bShaderCompiled);
if (!bShaderCompiled)
{
#ifndef NO_GDI
int i32InfoLogLength, i32CharsWritten;
glGetShaderiv(uiVertShader, GL_INFO_LOG_LENGTH, &i32InfoLogLength);
char* pszInfoLog = new char[i32InfoLogLength];
        glGetShaderInfoLog(uiVertShader, i32InfoLogLength, &i32CharsWritten, pszInfoLog);
#ifndef UNDER_CE
MessageBox(hWnd, i32InfoLogLength ? pszInfoLog : _T(""), _T("Failed to compile vertex shader"), MB_OK|MB_ICONEXCLAMATION);
#else
TCHAR* pszTInfoLog = new TCHAR[i32InfoLogLength];

for(int i = 0; i < i32InfoLogLength; ++i)
pszTInfoLog[i] = (TCHAR) pszInfoLog[i];

MessageBox(hWnd, i32InfoLogLength ? pszTInfoLog : _T(""), _T("Failed to compile vertex shader"), MB_OK|MB_ICONEXCLAMATION);
delete[] pszTInfoLog;
#endif
delete[] pszInfoLog;
#endif
goto cleanup;
}

// Create the shader program
    uiProgramObject = glCreateProgram();

// Attach the fragment and vertex shaders to it
    glAttachShader(uiProgramObject, uiFragShader);
    glAttachShader(uiProgramObject, uiVertShader);

// Bind the custom vertex attribute "myVertex" to location VERTEX_ARRAY
    glBindAttribLocation(uiProgramObject, VERTEX_ARRAY, "myVertex");

// Link the program
    glLinkProgram(uiProgramObject);

// Check if linking succeeded in the same way we checked for compilation success
    GLint bLinked;
    glGetProgramiv(uiProgramObject, GL_LINK_STATUS, &bLinked);
if (!bLinked)
{
#ifndef NO_GDI
int i32InfoLogLength, i32CharsWritten;
glGetProgramiv(uiProgramObject, GL_INFO_LOG_LENGTH, &i32InfoLogLength);
char* pszInfoLog = new char[i32InfoLogLength];
glGetProgramInfoLog(uiProgramObject, i32InfoLogLength, &i32CharsWritten, pszInfoLog);

#ifndef UNDER_CE
MessageBox(hWnd, i32InfoLogLength ? pszInfoLog : _T(""), _T("Failed to link program"), MB_OK|MB_ICONEXCLAMATION);
#else
TCHAR* pszTInfoLog = new TCHAR[i32InfoLogLength];

for(int i = 0; i < i32InfoLogLength; ++i)
pszTInfoLog[i] = (TCHAR) pszInfoLog[i];

MessageBox(hWnd, i32InfoLogLength ? pszTInfoLog : _T(""), _T("Failed to link program"), MB_OK|MB_ICONEXCLAMATION);
delete[] pszTInfoLog;
#endif
delete[] pszInfoLog;
#endif
goto cleanup;
}

// Actually use the created program
    glUseProgram(uiProgramObject);

// Sets the clear color.
// The colours are passed per channel (red,green,blue,alpha) as float values from 0.0 to 1.0
glClearColor(0.6f, 0.8f, 1.0f, 1.0f);

// We're going to draw a triangle to the screen so create a vertex buffer object for our triangle
GLuint ui32Vbo; // Vertex buffer object handle

// Interleaved vertex data
GLfloat afVertices[] = { -0.4f,-0.4f,0.0f, // Position
0.4f ,-0.4f,0.0f,
0.0f ,0.4f ,0.0f};

// Generate the vertex buffer object (VBO)
glGenBuffers(1, &ui32Vbo);

// Bind the VBO so we can fill it with data
glBindBuffer(GL_ARRAY_BUFFER, ui32Vbo);

// Set the buffer's data
unsigned int uiSize = 3 * (sizeof(GLfloat) * 3); // Calc afVertices size (3 vertices * stride (3 GLfloats per vertex))
glBufferData(GL_ARRAY_BUFFER, uiSize, afVertices, GL_STATIC_DRAW);

// Draws a triangle for 800 frames
for(int i = 0; i < 800; ++i)
{
// Check if the message handler finished the demo
if (g_bDemoDone) break;

/*
Clears the color buffer.
glClear() can also be used to clear the depth or stencil buffer
(GL_DEPTH_BUFFER_BIT or GL_STENCIL_BUFFER_BIT)
*/
glClear(GL_COLOR_BUFFER_BIT);
if (!TestEGLError(hWnd, "glClear"))
{
goto cleanup;
}

/*
Bind the projection model view matrix (PMVMatrix) to
the associated uniform variable in the shader
*/

// First gets the location of that variable in the shader using its name
int i32Location = glGetUniformLocation(uiProgramObject, "myPMVMatrix");

// Then passes the matrix to that variable
glUniformMatrix4fv( i32Location, 1, GL_FALSE, pfIdentity);

/*
Enable the custom vertex attribute at index VERTEX_ARRAY.
We previously binded that index to the variable in our shader "vec4 MyVertex;"
*/
glEnableVertexAttribArray(VERTEX_ARRAY);

// Sets the vertex data to this attribute index
glVertexAttribPointer(VERTEX_ARRAY, 3, GL_FLOAT, GL_FALSE, 0, 0);

/*
Draws a non-indexed triangle array from the pointers previously given.
This function allows the use of other primitive types : triangle strips, lines, ...
For indexed geometry, use the function glDrawElements() with an index list.
*/
glDrawArrays(GL_TRIANGLES, 0, 3);
if (!TestEGLError(hWnd, "glDrawArrays"))
{
goto cleanup;
}

/*
Swap Buffers.
Brings to the native display the current render surface.
*/
eglSwapBuffers(eglDisplay, eglSurface);
if (!TestEGLError(hWnd, "eglSwapBuffers"))
{
goto cleanup;
}
#ifndef NO_GDI
// Managing the window messages
MSG msg;
PeekMessage(&msg, hWnd, NULL, NULL, PM_REMOVE);
TranslateMessage(&msg);
DispatchMessage(&msg);
#endif
}

// Frees the OpenGL handles for the program and the 2 shaders
glDeleteProgram(uiProgramObject);
glDeleteShader(uiFragShader);
glDeleteShader(uiVertShader);

// Delete the VBO as it is no longer needed
glDeleteBuffers(1, &ui32Vbo);

/*
Step 10 - Terminate OpenGL ES and destroy the window (if present).
eglTerminate takes care of destroying any context or surface created
with this display, so we don't need to call eglDestroySurface or
eglDestroyContext here.
*/
cleanup:
eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglTerminate(eglDisplay);

/*
Step 11 - Destroy the eglWindow.
Again, this is platform specific and delegated to a separate function.
*/
#ifndef NO_GDI
// Release the device context
if (hDC) ReleaseDC(hWnd, hDC);

// Destroy the eglWindow
if (hWnd) DestroyWindow(hWnd);
#endif
return 0;
}

/******************************************************************************
 End of file (OGLES2HelloTriangle_Windows.cpp)
******************************************************************************/

#1


只会点OPENGL 1。0

#2


建议 LZ 先用标准的 Opengl 测试程序测试一下系统是否支持,就是那个叫“蚊子”的程序,呵呵...

#3


引用 2 楼 91program 的回复:
建议 LZ 先用标准的 Opengl 测试程序测试一下系统是否支持,就是那个叫“蚊子”的程序,呵呵...


“蚊子”? 可以说的再详细一点吗? 谢谢!!!

#4


opengl有什么蚊子啊,是91想多了吧,那是2D的,这个是3D。

建议从3个地方确认:
(1) 创建窗口,参数是否正确;
(2) 创建Surface,参数是否符合CPU要求;
(3) 创建context,参数是否正确;

另外,不同的CPU,有不同的参数说明,请参考厂商给的例子就OK。(如果有CPU型号,或许我可以给你个例子)

#5


(1)窗口创建没有返回错误(还是说上面代码中使用的参数不对,需要有特定的参数?)
(2)创建Surface和创建Context返回的值都不为0,在代码中多处使用glGetError()没有发现错误
(3)eglChooseConfig返回的支持个数为4
(4)现在修改的情况是:运行后为透明的窗口,需要拖动右上角的关闭按钮,窗口才可以显示出来,但窗口为黑色,没有三角形。
(5)如果可以给我一个测试是否支持OpenGL ES2.0的程序就更好了,谢谢!!  邮箱:767017087@qq.com

#6


我不知道你的例子哪里来的,反正是依赖于公用库EsUtil的。貌似是很早的代码,才会依赖这个东东。在wince平台,不怎么好用~还有auirt.h根本不知道是啥内容。不方便替你调试。

例子不方便上传,给你粘贴代码吧:

powerVR的SDK里边最简单的代码:
/******************************************************************************

 @File         OGLES2HelloTriangle_Windows.cpp

 @Title        OpenGL ES 2.0 Hello Triangle Tutorial

 @Version      

 @Copyright    Copyright (c) Imagination Technologies Limited.

 @Platform     .

 @Description  Basic Tutorial that shows step-by-step how to initialize OpenGL ES
               2.0, use it for drawing a triangle and terminate it.

******************************************************************************/
#include <stdio.h>
#include <windows.h>
#include <TCHAR.h>

#include <EGL/egl.h>
#include <GLES2/gl2.h>

/******************************************************************************
 Defines
******************************************************************************/
//#define NO_GDI 1 /* Remove the GDI functions */

#ifndef NO_GDI

// Windows class name to register
#define WINDOW_CLASS _T("PVRShellClass")

// Width and height of the window
#define WINDOW_WIDTH 640
#define WINDOW_HEIGHT 480

#endif

// Index to bind the attributes to vertex shaders
#define VERTEX_ARRAY 0

/******************************************************************************
 Global variables
******************************************************************************/

// Variable set in the message handler to finish the demo
bool g_bDemoDone = false;

/*!****************************************************************************
 @Function WndProc
 @Input hWnd Handle to the window
 @Input message Specifies the message
 @Input wParam Additional message information
 @Input lParam Additional message information
 @Return LRESULT result code to OS
 @Description Processes messages for the main window
******************************************************************************/
#ifndef NO_GDI
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
/*
Here we are handling 2 system messages: screen saving and monitor power.
They are especially relevent on mobile devices.
*/
#ifndef UNDER_CE
case WM_SYSCOMMAND:
{
switch (wParam)
{
case SC_SCREENSAVE: // Screensaver trying to start ?
case SC_MONITORPOWER: // Monitor trying to enter powersave ?
return 0; // Prevent this from happening
}
break;
}
#endif
// Handles the close message when a user clicks the quit icon of the window
case WM_CLOSE:
g_bDemoDone = true;
PostQuitMessage(0);
return 1;

default:
break;
}

// Calls the default window procedure for messages we did not handle
return DefWindowProc(hWnd, message, wParam, lParam);
}
#endif
/*!****************************************************************************
 @Function TestEGLError
 @Input pszLocation location in the program where the error took
place. ie: function name
 @Return bool true if no EGL error was detected
 @Description Tests for an EGL error and prints it
******************************************************************************/
bool TestEGLError(HWND hWnd, char* pszLocation)
{
/*
eglGetError returns the last error that has happened using egl,
not the status of the last called function. The user has to
check after every single egl call or at least once every frame.
*/
EGLint iErr = eglGetError();
if (iErr != EGL_SUCCESS)
{
#ifndef NO_GDI
TCHAR pszStr[256];
_stprintf(pszStr, _T("%s failed (%d).\n"), pszLocation, iErr);
MessageBox(hWnd, pszStr, _T("Error"), MB_OK|MB_ICONEXCLAMATION);
#endif
return false;
}

return true;
}

#7


2



/*!****************************************************************************
 @Function WinMain
 @Input hInstance Application instance from OS
 @Input hPrevInstance Always NULL
 @Input lpCmdLine command line from OS
 @Input nCmdShow Specifies how the window is to be shown
 @Return int result code to OS
 @Description Main function of the program
******************************************************************************/
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, TCHAR *lpCmdLine, int nCmdShow)
{
// Windows variables
HWND hWnd = 0;
HDC hDC = 0;

// EGL variables
EGLDisplay eglDisplay = 0;
EGLConfig eglConfig = 0;
EGLSurface eglSurface = 0;
EGLContext eglContext = 0;
EGLNativeWindowType eglWindow = 0;

// Matrix used for projection model view (PMVMatrix)
float pfIdentity[] =
{
1.0f,0.0f,0.0f,0.0f,
0.0f,1.0f,0.0f,0.0f,
0.0f,0.0f,1.0f,0.0f,
0.0f,0.0f,0.0f,1.0f
};

// Fragment and vertex shaders code
char* pszFragShader = "\
void main (void)\
{\
gl_FragColor = vec4(1.0, 1.0, 0.66 ,1.0);\
}";
char* pszVertShader = "\
attribute highp vec4 myVertex;\
uniform mediump mat4 myPMVMatrix;\
void main(void)\
{\
gl_Position = myPMVMatrix * myVertex;\
}";

/*
Step 0 - Create a EGLNativeWindowType that we can use for OpenGL ES output
*/
#ifndef NO_GDI
// Register the windows class
WNDCLASS sWC;
    sWC.style = CS_HREDRAW | CS_VREDRAW;
sWC.lpfnWndProc = WndProc;
    sWC.cbClsExtra = 0;
    sWC.cbWndExtra = 0;
    sWC.hInstance = hInstance;
    sWC.hIcon = 0;
    sWC.hCursor = 0;
    sWC.lpszMenuName = 0;
sWC.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
    sWC.lpszClassName = WINDOW_CLASS;
unsigned int nWidth = WINDOW_WIDTH;
unsigned int nHeight = WINDOW_HEIGHT;

ATOM registerClass = RegisterClass(&sWC);
if (!registerClass)
{
MessageBox(0, _T("Failed to register the window class"), _T("Error"), MB_OK | MB_ICONEXCLAMATION);
}
#if defined(UNDER_CE)
// Get the monitor dimensions
{
HMONITOR hMonitor;
BOOL bRet;
POINT p;
MONITORINFO sMInfo;

p.x = 0;
p.y = 0;
hMonitor = MonitorFromPoint(p, MONITOR_DEFAULTTOPRIMARY);
sMInfo.cbSize = sizeof(sMInfo);
bRet = GetMonitorInfo(hMonitor, &sMInfo);
if (!bRet)
{
MessageBox(0, _T("Failed to get monitor info"), _T("Error"), MB_OK|MB_ICONEXCLAMATION);
goto cleanup;
}

nWidth = sMInfo.rcMonitor.right - sMInfo.rcMonitor.left;
nHeight = sMInfo.rcMonitor.bottom - sMInfo.rcMonitor.top;
}
#endif
// Create the eglWindow
RECT sRect;
SetRect(&sRect, 0, 0, nWidth, nHeight);
AdjustWindowRectEx(&sRect, WS_CAPTION | WS_SYSMENU, false, 0);
hWnd = CreateWindow( WINDOW_CLASS, _T("HelloTriangle"), WS_VISIBLE | WS_SYSMENU,
 0, 0, nWidth, nHeight, NULL, NULL, hInstance, NULL);
eglWindow = hWnd;

// Get the associated device context
hDC = GetDC(hWnd);
if (!hDC)
{
MessageBox(0, _T("Failed to create the device context"), _T("Error"), MB_OK|MB_ICONEXCLAMATION);
goto cleanup;
}
#endif
/*
Step 1 - Get the default display.
EGL uses the concept of a "display" which in most environments
corresponds to a single physical screen. Since we usually want
to draw to the main screen or only have a single screen to begin
with, we let EGL pick the default display.
Querying other displays is platform specific.
*/
eglDisplay = eglGetDisplay(hDC);

    if(eglDisplay == EGL_NO_DISPLAY)
         eglDisplay = eglGetDisplay((EGLNativeDisplayType) EGL_DEFAULT_DISPLAY);
/*
Step 2 - Initialize EGL.
EGL has to be initialized with the display obtained in the
previous step. We cannot use other EGL functions except
eglGetDisplay and eglGetError before eglInitialize has been
called.
If we're not interested in the EGL version number we can just
pass NULL for the second and third parameters.
*/
EGLint iMajorVersion, iMinorVersion;
if (!eglInitialize(eglDisplay, &iMajorVersion, &iMinorVersion))
{
#ifndef NO_GDI
MessageBox(0, _T("eglInitialize() failed."), _T("Error"), MB_OK|MB_ICONEXCLAMATION);
#endif
goto cleanup;
}

/*
Step 3 - Make OpenGL ES the current API.
EGL provides ways to set up OpenGL ES and OpenVG contexts
(and possibly other graphics APIs in the future), so we need
to specify the "current API".
*/
eglBindAPI(EGL_OPENGL_ES_API);
if (!TestEGLError(hWnd, "eglBindAPI"))
{
goto cleanup;
}

/*
Step 4 - Specify the required configuration attributes.
An EGL "configuration" describes the pixel format and type of
surfaces that can be used for drawing.
For now we just want to use the default Windows surface,
i.e. it will be visible on screen. The list
has to contain key/value pairs, terminated with EGL_NONE.
 */
const EGLint pi32ConfigAttribs[] =
{
EGL_LEVEL, 0,
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
//EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
//EGL_NATIVE_RENDERABLE, EGL_FALSE,
//EGL_DEPTH_SIZE, EGL_DONT_CARE,
EGL_NONE
};

/*
Step 5 - Find a config that matches all requirements.
eglChooseConfig provides a list of all available configurations
that meet or exceed the requirements given as the second
argument. In most cases we just want the first config that meets
all criteria, so we can limit the number of configs returned to 1.
*/
int iConfigs;
if (!eglChooseConfig(eglDisplay, pi32ConfigAttribs, &eglConfig, 1, &iConfigs) || (iConfigs != 1))
{
#ifndef NO_GDI
MessageBox(0, _T("eglChooseConfig() failed."), _T("Error"), MB_OK|MB_ICONEXCLAMATION);
#endif
goto cleanup;
}

/*
Step 6 - Create a surface to draw to.
Use the config picked in the previous step and the native window
handle when available to create a window surface. A window surface
is one that will be visible on screen inside the native display (or
fullscreen if there is no windowing system).
Pixmaps and pbuffers are surfaces which only exist in off-screen
memory.
*/
eglSurface = eglCreateWindowSurface(eglDisplay, eglConfig, eglWindow, NULL);

    if(eglSurface == EGL_NO_SURFACE)
    {
        eglGetError(); // Clear error
        eglSurface = eglCreateWindowSurface(eglDisplay, eglConfig, NULL, NULL);
}

if (!TestEGLError(hWnd, "eglCreateWindowSurface"))
{
goto cleanup;
}

#8


3


/*
Step 7 - Create a context.
EGL has to create a context for OpenGL ES. Our OpenGL ES resources
like textures will only be valid inside this context
(or shared contexts)
*/
EGLint ai32ContextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
eglContext = eglCreateContext(eglDisplay, eglConfig, NULL, ai32ContextAttribs);
if (!TestEGLError(hWnd, "eglCreateContext"))
{
goto cleanup;
}

/*
Step 8 - Bind the context to the current thread and use our
window surface for drawing and reading.
Contexts are bound to a thread. This means you don't have to
worry about other threads and processes interfering with your
OpenGL ES application.
We need to specify a surface that will be the target of all
subsequent drawing operations, and one that will be the source
of read operations. They can be the same surface.
*/
eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext);
if (!TestEGLError(hWnd, "eglMakeCurrent"))
{
goto cleanup;
}

/*
Step 9 - Draw something with OpenGL ES.
At this point everything is initialized and we're ready to use
OpenGL ES to draw something on the screen.
*/

GLuint uiFragShader, uiVertShader; /* Used to hold the fragment and vertex shader handles */
GLuint uiProgramObject; /* Used to hold the program handle (made out of the two previous shaders */

// Create the fragment shader object
uiFragShader = glCreateShader(GL_FRAGMENT_SHADER);

// Load the source code into it
glShaderSource(uiFragShader, 1, (const char**)&pszFragShader, NULL);

// Compile the source code
glCompileShader(uiFragShader);

// Check if compilation succeeded
GLint bShaderCompiled;
    glGetShaderiv(uiFragShader, GL_COMPILE_STATUS, &bShaderCompiled);

if (!bShaderCompiled)
{
#ifndef NO_GDI
// An error happened, first retrieve the length of the log message
int i32InfoLogLength, i32CharsWritten;
glGetShaderiv(uiFragShader, GL_INFO_LOG_LENGTH, &i32InfoLogLength);

// Allocate enough space for the message and retrieve it
char* pszInfoLog = new char[i32InfoLogLength];
        glGetShaderInfoLog(uiFragShader, i32InfoLogLength, &i32CharsWritten, pszInfoLog);

// Displays the error in a dialog box
#ifndef UNDER_CE
MessageBox(hWnd, i32InfoLogLength ? pszInfoLog : _T(""), _T("Failed to compile fragment shader"), MB_OK|MB_ICONEXCLAMATION);
#else
TCHAR* pszTInfoLog = new TCHAR[i32InfoLogLength];

for(int i = 0; i < i32InfoLogLength; ++i)
pszTInfoLog[i] = (TCHAR) pszInfoLog[i];

MessageBox(hWnd, i32InfoLogLength ? pszTInfoLog : _T(""), _T("Failed to compile fragment shader"), MB_OK|MB_ICONEXCLAMATION);
delete[] pszTInfoLog;
#endif
delete[] pszInfoLog;
#endif
goto cleanup;
}

// Loads the vertex shader in the same way
uiVertShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(uiVertShader, 1, (const char**)&pszVertShader, NULL);
glCompileShader(uiVertShader);
    glGetShaderiv(uiVertShader, GL_COMPILE_STATUS, &bShaderCompiled);
if (!bShaderCompiled)
{
#ifndef NO_GDI
int i32InfoLogLength, i32CharsWritten;
glGetShaderiv(uiVertShader, GL_INFO_LOG_LENGTH, &i32InfoLogLength);
char* pszInfoLog = new char[i32InfoLogLength];
        glGetShaderInfoLog(uiVertShader, i32InfoLogLength, &i32CharsWritten, pszInfoLog);
#ifndef UNDER_CE
MessageBox(hWnd, i32InfoLogLength ? pszInfoLog : _T(""), _T("Failed to compile vertex shader"), MB_OK|MB_ICONEXCLAMATION);
#else
TCHAR* pszTInfoLog = new TCHAR[i32InfoLogLength];

for(int i = 0; i < i32InfoLogLength; ++i)
pszTInfoLog[i] = (TCHAR) pszInfoLog[i];

MessageBox(hWnd, i32InfoLogLength ? pszTInfoLog : _T(""), _T("Failed to compile vertex shader"), MB_OK|MB_ICONEXCLAMATION);
delete[] pszTInfoLog;
#endif
delete[] pszInfoLog;
#endif
goto cleanup;
}

// Create the shader program
    uiProgramObject = glCreateProgram();

// Attach the fragment and vertex shaders to it
    glAttachShader(uiProgramObject, uiFragShader);
    glAttachShader(uiProgramObject, uiVertShader);

// Bind the custom vertex attribute "myVertex" to location VERTEX_ARRAY
    glBindAttribLocation(uiProgramObject, VERTEX_ARRAY, "myVertex");

// Link the program
    glLinkProgram(uiProgramObject);

// Check if linking succeeded in the same way we checked for compilation success
    GLint bLinked;
    glGetProgramiv(uiProgramObject, GL_LINK_STATUS, &bLinked);
if (!bLinked)
{
#ifndef NO_GDI
int i32InfoLogLength, i32CharsWritten;
glGetProgramiv(uiProgramObject, GL_INFO_LOG_LENGTH, &i32InfoLogLength);
char* pszInfoLog = new char[i32InfoLogLength];
glGetProgramInfoLog(uiProgramObject, i32InfoLogLength, &i32CharsWritten, pszInfoLog);

#ifndef UNDER_CE
MessageBox(hWnd, i32InfoLogLength ? pszInfoLog : _T(""), _T("Failed to link program"), MB_OK|MB_ICONEXCLAMATION);
#else
TCHAR* pszTInfoLog = new TCHAR[i32InfoLogLength];

for(int i = 0; i < i32InfoLogLength; ++i)
pszTInfoLog[i] = (TCHAR) pszInfoLog[i];

MessageBox(hWnd, i32InfoLogLength ? pszTInfoLog : _T(""), _T("Failed to link program"), MB_OK|MB_ICONEXCLAMATION);
delete[] pszTInfoLog;
#endif
delete[] pszInfoLog;
#endif
goto cleanup;
}

// Actually use the created program
    glUseProgram(uiProgramObject);

// Sets the clear color.
// The colours are passed per channel (red,green,blue,alpha) as float values from 0.0 to 1.0
glClearColor(0.6f, 0.8f, 1.0f, 1.0f);

// We're going to draw a triangle to the screen so create a vertex buffer object for our triangle
GLuint ui32Vbo; // Vertex buffer object handle

// Interleaved vertex data
GLfloat afVertices[] = { -0.4f,-0.4f,0.0f, // Position
0.4f ,-0.4f,0.0f,
0.0f ,0.4f ,0.0f};

// Generate the vertex buffer object (VBO)
glGenBuffers(1, &ui32Vbo);

// Bind the VBO so we can fill it with data
glBindBuffer(GL_ARRAY_BUFFER, ui32Vbo);

// Set the buffer's data
unsigned int uiSize = 3 * (sizeof(GLfloat) * 3); // Calc afVertices size (3 vertices * stride (3 GLfloats per vertex))
glBufferData(GL_ARRAY_BUFFER, uiSize, afVertices, GL_STATIC_DRAW);

// Draws a triangle for 800 frames
for(int i = 0; i < 800; ++i)
{
// Check if the message handler finished the demo
if (g_bDemoDone) break;

/*
Clears the color buffer.
glClear() can also be used to clear the depth or stencil buffer
(GL_DEPTH_BUFFER_BIT or GL_STENCIL_BUFFER_BIT)
*/
glClear(GL_COLOR_BUFFER_BIT);
if (!TestEGLError(hWnd, "glClear"))
{
goto cleanup;
}

/*
Bind the projection model view matrix (PMVMatrix) to
the associated uniform variable in the shader
*/

// First gets the location of that variable in the shader using its name
int i32Location = glGetUniformLocation(uiProgramObject, "myPMVMatrix");

// Then passes the matrix to that variable
glUniformMatrix4fv( i32Location, 1, GL_FALSE, pfIdentity);

/*
Enable the custom vertex attribute at index VERTEX_ARRAY.
We previously binded that index to the variable in our shader "vec4 MyVertex;"
*/
glEnableVertexAttribArray(VERTEX_ARRAY);

// Sets the vertex data to this attribute index
glVertexAttribPointer(VERTEX_ARRAY, 3, GL_FLOAT, GL_FALSE, 0, 0);

/*
Draws a non-indexed triangle array from the pointers previously given.
This function allows the use of other primitive types : triangle strips, lines, ...
For indexed geometry, use the function glDrawElements() with an index list.
*/
glDrawArrays(GL_TRIANGLES, 0, 3);
if (!TestEGLError(hWnd, "glDrawArrays"))
{
goto cleanup;
}

/*
Swap Buffers.
Brings to the native display the current render surface.
*/
eglSwapBuffers(eglDisplay, eglSurface);
if (!TestEGLError(hWnd, "eglSwapBuffers"))
{
goto cleanup;
}
#ifndef NO_GDI
// Managing the window messages
MSG msg;
PeekMessage(&msg, hWnd, NULL, NULL, PM_REMOVE);
TranslateMessage(&msg);
DispatchMessage(&msg);
#endif
}

// Frees the OpenGL handles for the program and the 2 shaders
glDeleteProgram(uiProgramObject);
glDeleteShader(uiFragShader);
glDeleteShader(uiVertShader);

// Delete the VBO as it is no longer needed
glDeleteBuffers(1, &ui32Vbo);

/*
Step 10 - Terminate OpenGL ES and destroy the window (if present).
eglTerminate takes care of destroying any context or surface created
with this display, so we don't need to call eglDestroySurface or
eglDestroyContext here.
*/
cleanup:
eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglTerminate(eglDisplay);

/*
Step 11 - Destroy the eglWindow.
Again, this is platform specific and delegated to a separate function.
*/
#ifndef NO_GDI
// Release the device context
if (hDC) ReleaseDC(hWnd, hDC);

// Destroy the eglWindow
if (hWnd) DestroyWindow(hWnd);
#endif
return 0;
}

/******************************************************************************
 End of file (OGLES2HelloTriangle_Windows.cpp)
******************************************************************************/