OpenGL入门系列- OpenGL_ES 在 本地操作系统窗口上绘制的过程过程
2014-09-27 20:26
666 查看
EGL 是 Opengl_ES 和 本地操作系统窗口的粘合剂, 它是一种API, opengl_es和本地窗口交互就是利用的EGL。
第一步: 首先要创建本地操作系统的窗口
第二步: EGL要绑定到本地窗口,把本地窗口的类型(X11, Windows, Other)告诉EGL
第三步: 初始化EGL(EGL内部相关数据结构)
第四步:查询窗口配置,比如窗口属性,颜色信息,深度缓存信息等。
第五步:有选择的更改一些窗口配置
第六步:创建一块可绘制区域。
第七步:创建渲染上下文(上下文一个数据结构,保存渲染状态等信息)
第八步:切换到当前的渲染上下文
第九步: 进入消息循环,渲染。
代码例子:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//接收可变参数头文件
#include <stdarg.h>
#include <sys/time.h>
#include <GLES2/gl2.h>
#include <EGL/egl.h>
#include "esUtil.h"
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>
// X11 related local variables
static Display *x_display = NULL;
///
// CreateEGLContext()
//
// Creates an EGL rendering context and all associated elements
//
EGLBoolean CreateEGLContext ( EGLNativeWindowType hWnd, EGLDisplay* eglDisplay,
EGLContext* eglContext, EGLSurface* eglSurface,
EGLint attribList[])
{
EGLint numConfigs;
EGLint majorVersion;
EGLint minorVersion;
EGLDisplay display;
EGLContext context;
EGLSurface surface;
EGLConfig config;
EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE, EGL_NONE };
// Get Display 链接本地窗口系统,参数窗口类型
display = eglGetDisplay((EGLNativeDisplayType)x_display);
if ( display == EGL_NO_DISPLAY )
{
return EGL_FALSE;
}
// Initialize EGL 初始化EGL
if ( !eglInitialize(display, &majorVersion, &minorVersion) )
{
return EGL_FALSE;
}
// Get configs 获取surface 配置
if ( !eglGetConfigs(display, NULL, 0, &numConfigs) )
{
return EGL_FALSE;
}
// Choose config
if ( !eglChooseConfig(display, attribList, &config, 1, &numConfigs) )
{
return EGL_FALSE;
}
// Create a surface //创建一块区域
surface = eglCreateWindowSurface(display, config, (EGLNativeWindowType)hWnd, NULL);
if ( surface == EGL_NO_SURFACE )
{
return EGL_FALSE;
}
// Create a GL context //创建一个渲染上下文数据结构,保存渲染状态和相关操作
context = eglCreateContext(display, config, 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;
}
///
// WinCreate()
//
// This function initialized the native X11 display and window for EGL
//
EGLBoolean WinCreate(ESContext *esContext, const char *title)
{
Window root;
XSetWindowAttributes swa;
XSetWindowAttributes xattr;
Atom wm_state;
XWMHints hints;
XEvent xev;
EGLConfig ecfg;
EGLint num_config;
Window win;
/*
* X11 native display initialization
*/
x_display = XOpenDisplay(NULL);
if ( x_display == NULL )
{
return EGL_FALSE;
}
root = DefaultRootWindow(x_display);
swa.event_mask = ExposureMask | PointerMotionMask | KeyPressMask;
win = XCreateWindow(
x_display, root,
0, 0, esContext->width, esContext->height, 0,
CopyFromParent, InputOutput,
CopyFromParent, CWEventMask,
&swa );
xattr.override_redirect = FALSE;
XChangeWindowAttributes ( x_display, win, CWOverrideRedirect, &xattr );
hints.input = TRUE;
hints.flags = InputHint;
XSetWMHints(x_display, win, &hints);
// make the window visible on the screen
XMapWindow (x_display, win);
XStoreName (x_display, win, title);
// get identifiers for the provided atom name strings
wm_state = XInternAtom (x_display, "_NET_WM_STATE", FALSE);
memset ( &xev, 0, sizeof(xev) );
xev.type = ClientMessage;
xev.xclient.window = win;
xev.xclient.message_type = wm_state;
xev.xclient.format = 32;
xev.xclient.data.l[0] = 1;
xev.xclient.data.l[1] = FALSE;
XSendEvent (
x_display,
DefaultRootWindow ( x_display ),
FALSE,
SubstructureNotifyMask,
&xev );
esContext->hWnd = (EGLNativeWindowType) win;
return EGL_TRUE;
}
///
// userInterrupt()
//
// Reads from X11 event loop and interrupt program if there is a keypress, or
// window close action.
//
GLboolean userInterrupt(ESContext *esContext)
{
XEvent xev;
KeySym key;
GLboolean userinterrupt = GL_FALSE;
char text;
// Pump all messages from X server. Keypresses are directed to keyfunc (if defined)
while ( XPending ( x_display ) )
{
XNextEvent( x_display, &xev );
if ( xev.type == KeyPress )
{
if (XLookupString(&xev.xkey,&text,1,&key,0)==1)
{
if (esContext->keyFunc != NULL)
esContext->keyFunc(esContext, text, 0, 0);
}
}
if ( xev.type == DestroyNotify )
userinterrupt = GL_TRUE;
}
return userinterrupt;
}
//////////////////////////////////////////////////////////////////
//
// Public Functions
//
//
///
// esInitContext()
//
// Initialize ES utility context. This must be called before calling any other
// functions.
//
void ESUTIL_API esInitContext ( ESContext *esContext )
{
if ( esContext != NULL )
{
memset( 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 ( ESContext *esContext, const char* title, GLint width, GLint height, GLuint flags )
{
EGLint attribList[] =
{
EGL_RED_SIZE, 5,
EGL_GREEN_SIZE, 6,
EGL_BLUE_SIZE, 5,
EGL_ALPHA_SIZE, (flags & ES_WINDOW_ALPHA) ? 8 : EGL_DONT_CARE,
EGL_DEPTH_SIZE, (flags & ES_WINDOW_DEPTH) ? 8 : EGL_DONT_CARE,
EGL_STENCIL_SIZE, (flags & ES_WINDOW_STENCIL) ? 8 : EGL_DONT_CARE,
EGL_SAMPLE_BUFFERS, (flags & ES_WINDOW_MULTISAMPLE) ? 1 : 0,
EGL_NONE
};
if ( esContext == NULL )
{
return GL_FALSE;
}
esContext->width = width;
esContext->height = height;
if ( !WinCreate ( esContext, title) )
{
return GL_FALSE;
}
if ( !CreateEGLContext ( esContext->hWnd,
&esContext->eglDisplay,
&esContext->eglContext,
&esContext->eglSurface,
attribList) )
{
return GL_FALSE;
}
return GL_TRUE;
}
///
// esMainLoop()
//
// Start the main loop for the OpenGL ES application
//
void ESUTIL_API esMainLoop ( ESContext *esContext )
{
struct timeval t1, t2;
struct timezone tz;
float deltatime;
float totaltime = 0.0f;
unsigned int frames = 0;
gettimeofday ( &t1 , &tz );
while(userInterrupt(esContext) == GL_FALSE)
{
gettimeofday(&t2, &tz);
deltatime = (float)(t2.tv_sec - t1.tv_sec + (t2.tv_usec - t1.tv_usec) * 1e-6);
t1 = t2;
if (esContext->updateFunc != NULL)
esContext->updateFunc(esContext, deltatime);
if (esContext->drawFunc != NULL)
esContext->drawFunc(esContext);
eglSwapBuffers(esContext->eglDisplay, esContext->eglSurface);
totaltime += deltatime;
frames++;
if (totaltime > 2.0f)
{
printf("%4d frames rendered in %1.4f seconds -> FPS=%3.4f\n", frames, totaltime, frames/totaltime);
totaltime -= 2.0f;
frames = 0;
}
}
}
///
// esRegisterDrawFunc()
//
void ESUTIL_API esRegisterDrawFunc ( ESContext *esContext, void (ESCALLBACK *drawFunc) (ESContext* ) )
{
esContext->drawFunc = drawFunc;
}
///
// esRegisterUpdateFunc()
//
void ESUTIL_API esRegisterUpdateFunc ( ESContext *esContext, void (ESCALLBACK *updateFunc) ( ESContext*, float ) )
{
esContext->updateFunc = updateFunc;
}
///
// esRegisterKeyFunc()
//
void ESUTIL_API esRegisterKeyFunc ( ESContext *esContext,
void (ESCALLBACK *keyFunc) (ESContext*, unsigned char, int, int ) )
{
esContext->keyFunc = keyFunc;
}
///
// esLogMessage()
//
// Log an error message to the debug output for the platform
//
void ESUTIL_API esLogMessage ( const char *formatStr, ... )
{
va_list params;
char buf[BUFSIZ];
va_start ( params, formatStr );
vsprintf ( buf, formatStr, params );
printf ( "%s", buf );
va_end ( params );
}
///
// esLoadTGA()
//
// Loads a 24-bit TGA image from a file. This is probably the simplest TGA loader ever.
// Does not support loading of compressed TGAs nor TGAa with alpha channel. But for the
// sake of the examples, this is sufficient.
//
char* ESUTIL_API esLoadTGA ( char *fileName, int *width, int *height )
{
char *buffer = NULL;
FILE *f;
unsigned char tgaheader[12];
unsigned char attributes[6];
unsigned int imagesize;
f = fopen(fileName, "rb");
if(f == NULL) return NULL;
if(fread(&tgaheader, sizeof(tgaheader), 1, f) == 0)
{
fclose(f);
return NULL;
}
if(fread(attributes, sizeof(attributes), 1, f) == 0)
{
fclose(f);
return 0;
}
*width = attributes[1] * 256 + attributes[0];
*height = attributes[3] * 256 + attributes[2];
imagesize = attributes[4] / 8 * *width * *height;
buffer = malloc(imagesize);
if (buffer == NULL)
{
fclose(f);
return 0;
}
if(fread(buffer, 1, imagesize, f) != imagesize)
{
free(buffer);
return NULL;
}
fclose(f);
return buffer;
}
第一步: 首先要创建本地操作系统的窗口
第二步: EGL要绑定到本地窗口,把本地窗口的类型(X11, Windows, Other)告诉EGL
第三步: 初始化EGL(EGL内部相关数据结构)
第四步:查询窗口配置,比如窗口属性,颜色信息,深度缓存信息等。
第五步:有选择的更改一些窗口配置
第六步:创建一块可绘制区域。
第七步:创建渲染上下文(上下文一个数据结构,保存渲染状态等信息)
第八步:切换到当前的渲染上下文
第九步: 进入消息循环,渲染。
代码例子:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//接收可变参数头文件
#include <stdarg.h>
#include <sys/time.h>
#include <GLES2/gl2.h>
#include <EGL/egl.h>
#include "esUtil.h"
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>
// X11 related local variables
static Display *x_display = NULL;
///
// CreateEGLContext()
//
// Creates an EGL rendering context and all associated elements
//
EGLBoolean CreateEGLContext ( EGLNativeWindowType hWnd, EGLDisplay* eglDisplay,
EGLContext* eglContext, EGLSurface* eglSurface,
EGLint attribList[])
{
EGLint numConfigs;
EGLint majorVersion;
EGLint minorVersion;
EGLDisplay display;
EGLContext context;
EGLSurface surface;
EGLConfig config;
EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE, EGL_NONE };
// Get Display 链接本地窗口系统,参数窗口类型
display = eglGetDisplay((EGLNativeDisplayType)x_display);
if ( display == EGL_NO_DISPLAY )
{
return EGL_FALSE;
}
// Initialize EGL 初始化EGL
if ( !eglInitialize(display, &majorVersion, &minorVersion) )
{
return EGL_FALSE;
}
// Get configs 获取surface 配置
if ( !eglGetConfigs(display, NULL, 0, &numConfigs) )
{
return EGL_FALSE;
}
// Choose config
if ( !eglChooseConfig(display, attribList, &config, 1, &numConfigs) )
{
return EGL_FALSE;
}
// Create a surface //创建一块区域
surface = eglCreateWindowSurface(display, config, (EGLNativeWindowType)hWnd, NULL);
if ( surface == EGL_NO_SURFACE )
{
return EGL_FALSE;
}
// Create a GL context //创建一个渲染上下文数据结构,保存渲染状态和相关操作
context = eglCreateContext(display, config, 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;
}
///
// WinCreate()
//
// This function initialized the native X11 display and window for EGL
//
EGLBoolean WinCreate(ESContext *esContext, const char *title)
{
Window root;
XSetWindowAttributes swa;
XSetWindowAttributes xattr;
Atom wm_state;
XWMHints hints;
XEvent xev;
EGLConfig ecfg;
EGLint num_config;
Window win;
/*
* X11 native display initialization
*/
x_display = XOpenDisplay(NULL);
if ( x_display == NULL )
{
return EGL_FALSE;
}
root = DefaultRootWindow(x_display);
swa.event_mask = ExposureMask | PointerMotionMask | KeyPressMask;
win = XCreateWindow(
x_display, root,
0, 0, esContext->width, esContext->height, 0,
CopyFromParent, InputOutput,
CopyFromParent, CWEventMask,
&swa );
xattr.override_redirect = FALSE;
XChangeWindowAttributes ( x_display, win, CWOverrideRedirect, &xattr );
hints.input = TRUE;
hints.flags = InputHint;
XSetWMHints(x_display, win, &hints);
// make the window visible on the screen
XMapWindow (x_display, win);
XStoreName (x_display, win, title);
// get identifiers for the provided atom name strings
wm_state = XInternAtom (x_display, "_NET_WM_STATE", FALSE);
memset ( &xev, 0, sizeof(xev) );
xev.type = ClientMessage;
xev.xclient.window = win;
xev.xclient.message_type = wm_state;
xev.xclient.format = 32;
xev.xclient.data.l[0] = 1;
xev.xclient.data.l[1] = FALSE;
XSendEvent (
x_display,
DefaultRootWindow ( x_display ),
FALSE,
SubstructureNotifyMask,
&xev );
esContext->hWnd = (EGLNativeWindowType) win;
return EGL_TRUE;
}
///
// userInterrupt()
//
// Reads from X11 event loop and interrupt program if there is a keypress, or
// window close action.
//
GLboolean userInterrupt(ESContext *esContext)
{
XEvent xev;
KeySym key;
GLboolean userinterrupt = GL_FALSE;
char text;
// Pump all messages from X server. Keypresses are directed to keyfunc (if defined)
while ( XPending ( x_display ) )
{
XNextEvent( x_display, &xev );
if ( xev.type == KeyPress )
{
if (XLookupString(&xev.xkey,&text,1,&key,0)==1)
{
if (esContext->keyFunc != NULL)
esContext->keyFunc(esContext, text, 0, 0);
}
}
if ( xev.type == DestroyNotify )
userinterrupt = GL_TRUE;
}
return userinterrupt;
}
//////////////////////////////////////////////////////////////////
//
// Public Functions
//
//
///
// esInitContext()
//
// Initialize ES utility context. This must be called before calling any other
// functions.
//
void ESUTIL_API esInitContext ( ESContext *esContext )
{
if ( esContext != NULL )
{
memset( 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 ( ESContext *esContext, const char* title, GLint width, GLint height, GLuint flags )
{
EGLint attribList[] =
{
EGL_RED_SIZE, 5,
EGL_GREEN_SIZE, 6,
EGL_BLUE_SIZE, 5,
EGL_ALPHA_SIZE, (flags & ES_WINDOW_ALPHA) ? 8 : EGL_DONT_CARE,
EGL_DEPTH_SIZE, (flags & ES_WINDOW_DEPTH) ? 8 : EGL_DONT_CARE,
EGL_STENCIL_SIZE, (flags & ES_WINDOW_STENCIL) ? 8 : EGL_DONT_CARE,
EGL_SAMPLE_BUFFERS, (flags & ES_WINDOW_MULTISAMPLE) ? 1 : 0,
EGL_NONE
};
if ( esContext == NULL )
{
return GL_FALSE;
}
esContext->width = width;
esContext->height = height;
if ( !WinCreate ( esContext, title) )
{
return GL_FALSE;
}
if ( !CreateEGLContext ( esContext->hWnd,
&esContext->eglDisplay,
&esContext->eglContext,
&esContext->eglSurface,
attribList) )
{
return GL_FALSE;
}
return GL_TRUE;
}
///
// esMainLoop()
//
// Start the main loop for the OpenGL ES application
//
void ESUTIL_API esMainLoop ( ESContext *esContext )
{
struct timeval t1, t2;
struct timezone tz;
float deltatime;
float totaltime = 0.0f;
unsigned int frames = 0;
gettimeofday ( &t1 , &tz );
while(userInterrupt(esContext) == GL_FALSE)
{
gettimeofday(&t2, &tz);
deltatime = (float)(t2.tv_sec - t1.tv_sec + (t2.tv_usec - t1.tv_usec) * 1e-6);
t1 = t2;
if (esContext->updateFunc != NULL)
esContext->updateFunc(esContext, deltatime);
if (esContext->drawFunc != NULL)
esContext->drawFunc(esContext);
eglSwapBuffers(esContext->eglDisplay, esContext->eglSurface);
totaltime += deltatime;
frames++;
if (totaltime > 2.0f)
{
printf("%4d frames rendered in %1.4f seconds -> FPS=%3.4f\n", frames, totaltime, frames/totaltime);
totaltime -= 2.0f;
frames = 0;
}
}
}
///
// esRegisterDrawFunc()
//
void ESUTIL_API esRegisterDrawFunc ( ESContext *esContext, void (ESCALLBACK *drawFunc) (ESContext* ) )
{
esContext->drawFunc = drawFunc;
}
///
// esRegisterUpdateFunc()
//
void ESUTIL_API esRegisterUpdateFunc ( ESContext *esContext, void (ESCALLBACK *updateFunc) ( ESContext*, float ) )
{
esContext->updateFunc = updateFunc;
}
///
// esRegisterKeyFunc()
//
void ESUTIL_API esRegisterKeyFunc ( ESContext *esContext,
void (ESCALLBACK *keyFunc) (ESContext*, unsigned char, int, int ) )
{
esContext->keyFunc = keyFunc;
}
///
// esLogMessage()
//
// Log an error message to the debug output for the platform
//
void ESUTIL_API esLogMessage ( const char *formatStr, ... )
{
va_list params;
char buf[BUFSIZ];
va_start ( params, formatStr );
vsprintf ( buf, formatStr, params );
printf ( "%s", buf );
va_end ( params );
}
///
// esLoadTGA()
//
// Loads a 24-bit TGA image from a file. This is probably the simplest TGA loader ever.
// Does not support loading of compressed TGAs nor TGAa with alpha channel. But for the
// sake of the examples, this is sufficient.
//
char* ESUTIL_API esLoadTGA ( char *fileName, int *width, int *height )
{
char *buffer = NULL;
FILE *f;
unsigned char tgaheader[12];
unsigned char attributes[6];
unsigned int imagesize;
f = fopen(fileName, "rb");
if(f == NULL) return NULL;
if(fread(&tgaheader, sizeof(tgaheader), 1, f) == 0)
{
fclose(f);
return NULL;
}
if(fread(attributes, sizeof(attributes), 1, f) == 0)
{
fclose(f);
return 0;
}
*width = attributes[1] * 256 + attributes[0];
*height = attributes[3] * 256 + attributes[2];
imagesize = attributes[4] / 8 * *width * *height;
buffer = malloc(imagesize);
if (buffer == NULL)
{
fclose(f);
return 0;
}
if(fread(buffer, 1, imagesize, f) != imagesize)
{
free(buffer);
return NULL;
}
fclose(f);
return buffer;
}
相关文章推荐
- OpenGL入门学习之十五——从“绘制一个立方体”来看OpenGL的进化过程
- OpenGL入门学习——第十五课,从“绘制一个立方体”来看OpenGL的进化过程
- OpenGL 入门基础教程 —— 在第一个窗口绘制一个三角形
- Joe's OpenGL ES 2.0 系列经典入门教程(第一课:Introduction)
- MAC Cocoa Opengl入门系列教程一(基本图元绘制)
- OpenGL入门学习之十五——从“绘制一个立方体”来看OpenGL的进化过程
- OpenGL入门学习——第十五课 从“绘制一个立方体”来看OpenGL的进化过程
- [Visual C++系列]2.4 在窗口中绘制设备相关位图,图标,设备无关位图
- USB入门系列之六 —— USB设备的枚举过程
- Flex快速入门系列之五:crossdomain.xml文件创建以及允许本地跨域访问远程资源
- 【OpenGL4.0】GLSL渲染语言入门与VBO、VAO使用:绘制一个三角形
- Java版SLG游戏开发入门[0]--让绘制的窗口响应鼠标事件 推荐
- USB入门系列之五 ---- USB设备的枚举过程(zz)
- Android应用程序窗口(Activity)的测量(Measure)、布局(Layout)和绘制(Draw)过程分析(上)
- OpenGL_ES|WinCE纹理贴图的方式绘制字符串
- OpenGL_ES|WinCE纹理贴图的方式绘制字符串
- 【技术类】【遥感入门系列】3、遥感电磁辐射与遥感过程
- D3D初学入门一(配置开发环境及绘制D3D窗口)
- Win32 OpenGL编程系列 2D例子 -- 七巧板图形绘制
- opengl|es - 2D绘制