This code sample uses Screen Graphics Subsystem with OpenGL ES 1.X as the rendering API.

/**
** gles1-vsync
** Windowed vsync that uses OpenGL ES 1.X for rendering API.
**
** Features:
** - configurable window size through the -size=(width)x(height) option
** - configurable window position through the -pos=(x),(y) option
** - adjustable swap interval through the -interval=(n) option;
** a swap interval of 0 lets the app run as fast as possible
** numbers of 1 or more limit the rate to the number of vsync periods
** - application responds to size changes from window manager or delegate
** - rendering is suspended if window is not visible
**
** Copyright 2010, QNX Software Systems Ltd. All Rights Reserved
**
** Permission to use, copy, modify, and distribute this software and its
** documentation for any purpose and without fee is hereby granted,
** provided that the above copyright notice appear in all copies and that
** both that copyright notice and this permission notice appear in
** supporting documentation.
**
** This file is provided AS IS with no warranties of any kind. The author
** shall have no liability with respect to the infringement of copyrights,
** trade secrets or any patents by this file or any part thereof. In no
** event will the author be liable for any lost revenue or profits or
** other special, indirect and consequential damages.
*/
/**
** Include the header files for libraries we are using.
**/
#include <ctype.h> /* Header file for isdigit */
#include <stdio.h> /* Header file for fprintf */
#include <stdlib.h> /* Header file for EXIT_FAILURE, EXIT_SUCCESS, atoi */
#include <string.h> /* Header file for strncmp */
#include <sys/keycodes.h> /* Header file for KEYCODE_ESCAPE */
#include <screen/screen.h> /* Header file for the native screen API */
#include <EGL/egl.h> /* Header file for EGL */
#include <GLES/gl.h> /* Header file for OpenGL ES 1.X */
/**
** Here is the list of attributes that will be passed to EGL to get us
** a pixel format configuration. An EGL configuration is required by
** EGL when creating surfaces and rendering contexts. Since we will
** modify certain values in this list when certain command line arguments
** are provided, we will organize our attributes as an aggregate of named
** key/value pairs of EGLint's. This way we won't have to track the
** index locations various attributes in a one-dimensional array.
**/
struct {
EGLint surface_type;
EGLint red_size;
EGLint green_size;
EGLint blue_size;
EGLint alpha_size;
EGLint samples;
EGLint config_id;
} egl_conf_attr = {
.surface_type = EGL_WINDOW_BIT, /* Ask for displayable and pbuffer surfaces */
.red_size = EGL_DONT_CARE, /* Minimum number of red bits per pixel */
.green_size = EGL_DONT_CARE, /* Minimum number of green bits per pixel */
.blue_size = EGL_DONT_CARE, /* Minimum number of blue bits per pixel */
.alpha_size = EGL_DONT_CARE, /* Minimum number of alpha bits per pixel */
.samples = EGL_DONT_CARE, /* Minimum number of samples per pixel */
.config_id = EGL_DONT_CARE, /* used to get a specific EGL config */
};
/* This function will convert EGL error codes into more meaningful messages. */
static void
egl_perror(const char *msg) {
static const char *errmsg[] = {
"function succeeded",
"EGL is not initialized, or could not be initialized, for the specified display",
"cannot access a requested resource",
"failed to allocate resources for the requested operation",
"an unrecognized attribute or attribute value was passed in an attribute list",
"an EGLConfig argument does not name a valid EGLConfig",
"an EGLContext argument does not name a valid EGLContext",
"the current surface of the calling thread is no longer valid",
"an EGLDisplay argument does not name a valid EGLDisplay",
"arguments are inconsistent",
"an EGLNativePixmapType argument does not refer to a valid native pixmap",
"an EGLNativeWindowType argument does not refer to a valid native window",
"one or more argument values are invalid",
"an EGLSurface argument does not name a valid surface configured for rendering",
"a power management event has occurred",
};
fprintf(stderr, "%s: %s\n", msg, errmsg[eglGetError() - EGL_SUCCESS]);
}
/* This function will parse the configuration string and/or select an appropriate
* configuration based on configuration attributes.*/
EGLConfig choose_config(EGLDisplay egl_disp, const char* str)
{
EGLConfig egl_conf = (EGLConfig)0; /* the resulting EGL config */
EGLConfig *egl_configs; /* describes the color and ancillary buffers */
EGLint egl_num_configs; /* number of configs that match our attributes */
EGLint val; /* an EGL integer value */
EGLBoolean rc; /* the return value of EGL functions */
const char *tok; /* a pointer that will traverse the string */
EGLint i; /* variable used to loop on matching configs */
/**
** We start by parsing the config string, which is a comma-separated list
** of specifiers. We don't have to use strtok because the syntax is quite
** simple. All we will need is strncmp and atoi. We start by skipping any
** whitespace or separators. The str argument might be null, indicating
** that we must find a config that matches the default criteria. In this
** case, we must skip any processing of the str and make sure that there
** is a default value for all configuration attributes (usually
** EGL_DONT_CARE.)
**/
if (str != NULL) {
tok = str;
while (*tok == ' ' || *tok == ',') {
tok++;
}
/**
** Loop as long as there are tokens to be processed.
**/
while (*tok != '\0') {
if (strncmp(tok, "rgba8888", strlen("rgba8888")) == 0) {
egl_conf_attr.red_size = 8;
egl_conf_attr.green_size = 8;
egl_conf_attr.blue_size = 8;
egl_conf_attr.alpha_size = 8;
tok += strlen("rgba8888");
} else if (strncmp(tok, "rgba5551", strlen("rgba5551")) == 0) {
egl_conf_attr.red_size = 5;
egl_conf_attr.green_size = 5;
egl_conf_attr.blue_size = 5;
egl_conf_attr.alpha_size = 1;
tok += strlen("rgba5551");
} else if (strncmp(tok, "rgba4444", strlen("rgba4444")) == 0) {
egl_conf_attr.red_size = 4;
egl_conf_attr.green_size = 4;
egl_conf_attr.blue_size = 4;
egl_conf_attr.alpha_size = 4;
tok += strlen("rgba4444");
} else if (strncmp(tok, "rgb565", strlen("rgb565")) == 0) {
egl_conf_attr.red_size = 5;
egl_conf_attr.green_size = 6;
egl_conf_attr.blue_size = 5;
egl_conf_attr.alpha_size = 0;
tok += strlen("rgb565");
} else if (isdigit(*tok)) {
/**
** An integer value could either be an EGL configuration id or
** a multi-sampling count. An 'x' immediately after the integer
** indicates that it is a multi-sampling specifier.
**/
val = atoi(tok);
while (isdigit(*(++tok)));
if (*tok == 'x') {
egl_conf_attr.samples = val;
tok++;
} else {
/**
** Using the EGL_CONFIG_ID attribute allows us to get a
** configuration by its id without a typecast,
** i.e. egl_conf = (EGLConfig)val. Note that the EGL spec says
** that when the EGL_CONFIG_ID attribute is specified, all
** other attributes are ignored, so we don't have to shorten
** the list ourselves in this case.
**/
egl_conf_attr.config_id = val;
}
} else {
/**
** Print a message on the console if we encounter something we
** don't know. This way, the user will know that he might not get
** the config he was expecting.
**/
fprintf(stderr, "Invalid configuration specifier: ");
while (*tok != ' ' && *tok != ',' && *tok != '\0') {
fputc(*tok++, stderr);
}
fputc('\n', stderr);
}
/**
** Skip any spaces and separators between this token and the next one.
**/
while (*tok == ' ' || *tok == ',') {
tok++;
}
}
}
/* Use eglGetConfigs to retrieve EGL configurations */
rc = eglGetConfigs(egl_disp, NULL, 0, &egl_num_configs);
if (rc != EGL_TRUE) {
egl_perror("eglGetConfigs");
return egl_conf;
}
if (egl_num_configs == 0) {
fprintf(stderr, "eglGetConfigs: could not find a configuration\n");
return egl_conf;
}
/**
** Now the total number of configs has been stored in egl_num_configs.
** We will malloc enough memory to hold all the configs. We need this to
** traverse the configs to find a perfect match.
**/
egl_configs = malloc(egl_num_configs * sizeof(*egl_configs));
if (egl_configs == NULL) {
fprintf(stderr, "could not allocate memory for %d EGL configs\n", egl_num_configs);
return egl_conf;
}
/**
** The second time we call eglGetConfigs, it is with an array of configs
** big enough to store all the results. The list of EGL configs is
** expected to be static, which means our list of matching configs should
** be static as well. As long as the call succeeds, we don't have to check
** for egl_num_configs again.
**/
rc = eglGetConfigs(egl_disp, egl_configs,
egl_num_configs, &egl_num_configs);
if (rc != EGL_TRUE) {
egl_perror("eglGetConfigs");
free(egl_configs);
return egl_conf;
}
/**
** Now we just have to go through the list of configs and find one that
** has all the attributes we are looking for. Some attributes like the
** surface type or the renderable type are masks. All the others are just
** integers that we need to match unless we don't care about the value.
**/
for (i = 0; i < egl_num_configs; i++) {
/**
** Make sure the config id matches what we asked for.
**/
if (egl_conf_attr.config_id != EGL_DONT_CARE) {
eglGetConfigAttrib(egl_disp, egl_configs[i], EGL_CONFIG_ID, &val);
if (val == egl_conf_attr.config_id) {
egl_conf = egl_configs[i];
break;
} else {
continue;
}
}
/**
** Make sure the surface type matches what we asked for.
**/
eglGetConfigAttrib(egl_disp, egl_configs[i], EGL_SURFACE_TYPE, &val);
if ((val & egl_conf_attr.surface_type) != egl_conf_attr.surface_type) {
continue;
}
/**
** Make sure the renderable type has the OpenGL ES bit.
**/
eglGetConfigAttrib(egl_disp, egl_configs[i], EGL_RENDERABLE_TYPE, &val);
if (!(val & EGL_OPENGL_ES_BIT)) {
continue;
}
/**
** Make sure the number of red bits matches what we asked for.
**/
if (egl_conf_attr.red_size != EGL_DONT_CARE) {
eglGetConfigAttrib(egl_disp, egl_configs[i], EGL_RED_SIZE, &val);
if (val != egl_conf_attr.red_size) {
continue;
}
}
/**
** Make sure the number of green bits matches what we asked for.
**/
if (egl_conf_attr.green_size != EGL_DONT_CARE) {
eglGetConfigAttrib(egl_disp, egl_configs[i], EGL_GREEN_SIZE, &val);
if (val != egl_conf_attr.green_size) {
continue;
}
}
/**
** Make sure the number of blue bits matches what we asked for.
**/
if (egl_conf_attr.blue_size != EGL_DONT_CARE) {
eglGetConfigAttrib(egl_disp, egl_configs[i], EGL_BLUE_SIZE, &val);
if (val != egl_conf_attr.blue_size) {
continue;
}
}
/**
** Make sure the number of alpha bits matches what we asked for.
**/
if (egl_conf_attr.alpha_size != EGL_DONT_CARE) {
eglGetConfigAttrib(egl_disp, egl_configs[i], EGL_ALPHA_SIZE, &val);
if (val != egl_conf_attr.alpha_size) {
continue;
}
}
/**
** Make sure the number of samples matches what we asked for.
**/
if (egl_conf_attr.samples != EGL_DONT_CARE) {
eglGetConfigAttrib(egl_disp, egl_configs[i], EGL_SAMPLES, &val);
if (val != egl_conf_attr.samples) {
continue;
}
}
/**
** This config has the pixel format we asked for, so we can keep it
** and stop looking.
**/
egl_conf = egl_configs[i];
break;
}
/**
** At this point, it is important to remember to free the array allocated
** to hold all configs before returning.
**/
free(egl_configs);
if (egl_conf == (EGLConfig)0) {
/**
** The value of egl_conf will be that of a matching config if one was
** found or (EGLConfig)0 if there were no exact matches. The calling
** function can decide to do what it wants with the result. For example,
** it could ask for a different config if no matches were found, or it can
** simply fail and report the error.
**/
fprintf(stderr, "eglChooseConfig: could not find a matching configuration\n");
}
return egl_conf;
}
int choose_format(EGLDisplay egl_disp, EGLConfig egl_conf)
{
EGLint buffer_bit_depth, alpha_bit_depth;
eglGetConfigAttrib(egl_disp, egl_conf, EGL_BUFFER_SIZE, &buffer_bit_depth);
eglGetConfigAttrib(egl_disp, egl_conf, EGL_ALPHA_SIZE, &alpha_bit_depth);
switch (buffer_bit_depth) {
case 32: {
return SCREEN_FORMAT_RGBA8888;
}
case 24: {
return SCREEN_FORMAT_RGB888;
}
case 16: {
switch (alpha_bit_depth) {
case 4: {
return SCREEN_FORMAT_RGBA4444;
}
case 1: {
return SCREEN_FORMAT_RGBA5551;
}
default: {
return SCREEN_FORMAT_RGB565;
}
}
break;
}
default: {
return SCREEN_FORMAT_BYTE;
}
}
}
/**
** The function is used to initialize the OpenGL ES viewport and
** projection matrix. It also computes the position of vertices that will be
** used to do rendering. We compute the position of those vertices based on
** the window's dimensions instead of using scale and translation matrices.
** Because it is unlikely that the size will change very often, this is more
** efficient than applying transformations every time a frame is rendered.
**/
static void resize(GLshort *points, GLint width, GLint height, GLint barwidth)
{
/**
** The first four vertices take up 8 shorts. These vertices define a
** rectangle that goes from (0,0) to (barwidth,height). A translation
** matrix will be used to slide this rectangle across the viewport.
**/
points[0] = 0;
points[1] = height;
points[2] = barwidth;
points[3] = height;
points[4] = 0;
points[5] = 0;
points[6] = barwidth;
points[7] = 0;
/**
** The last six vertices take up 12 shorts. These vertices define two
** triangles that share a vertex. Because the OpenGL ES coordinate system
** starts at the bottom left instead of the top left corner, all y values
** need to be inverted. In other words, the hourglass needs to be
** translated up and down as the window height increases and decreases
** respectively.
**/
points[8] = 10;
points[9] = height - 10;
points[10] = 110;
points[11] = height - 10;
points[12] = 60;
points[13] = height - 60;
points[14] = 60;
points[15] = height - 60;
points[16] = 110;
points[17] = height - 110;
points[18] = 10;
points[19] = height - 110;
/* Update the viewport and projection matrix */
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrthof(0.0f, (GLfloat)width, 0.0f, (GLfloat)height, -1.0f, 1.0f);
glMatrixMode(GL_MODELVIEW);
}
/**
** This is the entry point of our native application. This is where we will
** parse command line arguments, create our window, handle events, and do our
** rendering.
**/
int main(int argc, char **argv)
{
/**
** This is the size for an invisible exit button. We choose a value that's
** big enough to be useable with touchscreens and pointer devices.
**/
const int exit_area_size = 20;
/**
** Make the sliding vertical blue bar 32 pixels wide. Any number would be
** fine here, as long as it is no larger than the width of the window.
**/
const int barwidth = 32;
/**
** We will use the surface attributes to choose between single-buffered
** and double-buffered rendering. Again, to avoid having to keep track of
** indexes in a one-dimensional array of attribute/value pairs, we use
** an aggregate of named attribute/value pairs of EGLint's.
**/
struct {
EGLint render_buffer[2];
EGLint none;
} egl_surf_attr = {
.render_buffer = { EGL_RENDER_BUFFER, EGL_BACK_BUFFER }, /* Ask for double-buffering */
.none = EGL_NONE /* End of list */
};
screen_context_t screen_ctx; /* connection to screen windowing system */
screen_window_t screen_win; /* native handle for our window */
screen_event_t screen_ev; /* handle used to pop events from our queue */
EGLDisplay egl_disp; /* abstract display on which graphics are drawn */
EGLConfig egl_conf; /* describes the color and ancillary buffers */
EGLSurface egl_surf; /* refers to our window's rendering surface */
EGLContext egl_ctx; /* a handle to a rendering context */
int usage = SCREEN_USAGE_OPENGL_ES1; /* we will use OpenGL ES 1.X to do our rendering */
int size[2] = { -1, -1 }; /* width and height of our window */
int pos[2] = { 0, 0 }; /* x,y position of our window */
int nbuffers = 2; /* number of buffers backing the window */
int format; /* native visual type / screen format */
int val; /* a generic variable used to set/get window properties */
EGLint interval = 1; /* EGL swap interval */
int verbose = EGL_FALSE; /* EGL_TRUE if the verbose option was set */
int vis = 1; /* boolean that indicates if our window is visible */
int pause = 0; /* EGL_TRUE if rendering is frozen */
const char *conf_str = NULL; /* configuration string */
const char *tok; /* used to process command-line arguments */
int rval = EXIT_FAILURE; /* application exits with value stored here */
int rc; /* return value from functions */
int i; /* loop/frame counter */
GLshort points[20]; /* we'll store the vertices in this array */
/**
** We start by processing the command line arguments. The first argument
** is skipped because it contains the name of the program. Arguments
** follow the syntax -(option)=(value).
**/
for (i = 1; i < argc; i++) {
if (strncmp(argv[i], "-config=", strlen("-config=")) == 0) {
/**
** The syntax of the EGL configuration option is
** -config=[option][,[option]...]. All we need is to do is pass
** the string after the '=' to choose_config, which will parse the
** options and find the right EGL config.
**/
conf_str = argv[i] + strlen("-config=");
} else if (strncmp(argv[i], "-size=", strlen("-size=")) == 0) {
/**
** The syntax of the size option is -size=(width)x(height).
** Because atoi stops processing at the first non-digit character,
** we can simply call atoi on the string after the '=' to get the
** width, and call atoi again on the string after the 'x' to get
** the height.
**/
tok = argv[i] + strlen("-size=");
size[0] = atoi(tok);
while (*tok >= '0' && *tok <= '9') {
tok++;
}
size[1] = atoi(tok+1);
} else if (strncmp(argv[i], "-pos=", strlen("-pos=")) == 0) {
/**
** The syntax of the pos option is -pos=(x),(y).
** Because atoi stops processing at the first non-digit character,
** we can simply call atoi on the string after the '=' to get the
** x offset, and call atoi again on the string after the ',' to
** get the y offset.
**/
tok = argv[i] + strlen("-pos=");
pos[0] = atoi(tok);
while (*tok >= '0' && *tok <= '9') {
tok++;
}
pos[1] = atoi(tok+1);
} else if (strncmp(argv[i], "-interval=", strlen("-interval=")) == 0) {
/**
** The syntax of the interval option is -interval=(number). All
** we need is to convert the number that starts after the '='.
**/
interval = atoi(argv[i] + strlen("-interval="));
} else if (strcmp(argv[i], "-single-buffer") == 0) {
/**
** The -single-buffer option on the command line will cause the
** rendering to be done to a single on-screen buffer. There are
** typically artifacts associated with single-buffered rendering
** caused by rendering to a visible surface.
**/
nbuffers = 1;
} else if (strcmp(argv[i], "-double-buffer") == 0) {
/**
** The -double-buffer option on the command line will cause the
** rendering to be on alternating back buffers. This eliminates
** artifacts associated with single-buffered rendering.
**/
nbuffers = 2;
} else if (strncmp(argv[i], "-verbose", strlen("-verbose")) == 0) {
/**
** The verbose option has no special syntax. It just has to be
** present on the command line to cause the verbose messages to
** be printed.
**/
verbose = EGL_TRUE;
} else {
/**
** Make sure we say something instead of silently ignoring a
** command line option.
**/
fprintf(stderr, "Invalid command-line option: %s\n", argv[i]);
}
}
/**
** Before we can do any kind of rendering, we must establish a connection
** to a display. We don't have any particular preference, so we'll just
** ask for the default display, unless a display id is specified on the
** command line.
**/
egl_disp = eglGetDisplay(EGL_DEFAULT_DISPLAY);
if (egl_disp == EGL_NO_DISPLAY) {
egl_perror("eglGetDisplay");
goto fail1;
}
/**
** Now we initialize EGL on the display. We can't do anything with this
** EGL display until EGL has been initialized. OpenGL ES 1.X is supported
** by all versions of EGL, so it is not necessary to check for the major
** and minor version numbers.
**/
rc = eglInitialize(egl_disp, NULL, NULL);
if (rc != EGL_TRUE) {
egl_perror("eglInitialize");
goto fail2;
}
/**
** Choosing an EGL configuration can be a tedious process. Here, we call
** choose_config which will do all the necessary work. In this case, this
** includes parsing a configuration string and/or select an appropriate
** configuration based on some configuration attributes.
**/
egl_conf = choose_config(egl_disp, conf_str);
if (egl_conf == (EGLConfig)0) {
goto fail2;
}
/**
** Now we need to create an OpenGL ES rendering context. The context will
** keep track of the OpenGL ES 1.X state among other things. We don't have
** to specify the current rendering API with an eglBindApi call because
** OpenGL ES is the default rendering API. The third argument to
** eglCreateContext is another EGL rendering context that we wish to share
** data with. We pass EGL_NO_CONTEXT to indicate that we won't need any
** of the textures or vertex buffer objects created in another EGL render
** context. The last argument is an attribute list that can be used to
** specify an API version number. We would use it to override the
** EGL CONTEXT CLIENT VERSION default value of 1 to 2 if we were writing
** an OpenGL ES 2.X application.
**/
egl_ctx = eglCreateContext(egl_disp, egl_conf, EGL_NO_CONTEXT, NULL);
if (egl_ctx == EGL_NO_CONTEXT) {
egl_perror("eglCreateContext");
goto fail2;
}
/**
** If the application was started with the -verbose command line argument,
** we will print a few information strings about the EGL configuration we
** end-up using. This might be useful if the -config option was not
** provided, or if the user doesn't know the particular details of a given
** pixel format. We will get the information by using the
** eglGetConfigAttrib with several interesting attribute names.
**/
if (verbose) {
printf("EGL_VENDOR = %s\n", eglQueryString(egl_disp, EGL_VENDOR));
printf("EGL_VERSION = %s\n", eglQueryString(egl_disp, EGL_VERSION));
printf("EGL_CLIENT_APIS = %s\n", eglQueryString(egl_disp, EGL_CLIENT_APIS));
printf("EGL_EXTENSIONS = %s\n\n", eglQueryString(egl_disp, EGL_EXTENSIONS));
i = -1;
eglGetConfigAttrib(egl_disp, egl_conf, EGL_CONFIG_ID, &i);
printf("EGL_CONFIG_ID = %d\n", i);
i = 0;
eglGetConfigAttrib(egl_disp, egl_conf, EGL_RED_SIZE, &i);
printf("EGL_RED_SIZE = %d\n", i);
i = 0;
eglGetConfigAttrib(egl_disp, egl_conf, EGL_GREEN_SIZE, &i);
printf("EGL_GREEN_SIZE = %d\n", i);
i = 0;
eglGetConfigAttrib(egl_disp, egl_conf, EGL_BLUE_SIZE, &i);
printf("EGL_BLUE_SIZE = %d\n", i);
i = 0;
eglGetConfigAttrib(egl_disp, egl_conf, EGL_ALPHA_SIZE, &i);
printf("EGL_ALPHA_SIZE = %d\n", i);
i = 0;
eglGetConfigAttrib(egl_disp, egl_conf, EGL_DEPTH_SIZE, &i);
printf("EGL_DEPTH_SIZE = %d\n", i);
i = 0;
eglGetConfigAttrib(egl_disp, egl_conf, EGL_LEVEL, &i);
printf("EGL_LEVEL = %d\n", i);
i = 0;
eglGetConfigAttrib(egl_disp, egl_conf, EGL_NATIVE_RENDERABLE, &i);
printf("EGL_NATIVE_RENDERABLE = %s\n", i ? "EGL_TRUE" : "EGL_FALSE");
i = 0;
eglGetConfigAttrib(egl_disp, egl_conf, EGL_NATIVE_VISUAL_TYPE, &i);
printf("EGL_NATIVE_VISUAL_TYPE = %d\n", i);
i = 0;
eglGetConfigAttrib(egl_disp, egl_conf, EGL_RENDERABLE_TYPE, &i);
printf("EGL_RENDERABLE_TYPE = 0x%04x\n", i);
i = 0;
eglGetConfigAttrib(egl_disp, egl_conf, EGL_SURFACE_TYPE, &i);
printf("EGL_SURFACE_TYPE = 0x%04x\n", i);
i = 0;
eglGetConfigAttrib(egl_disp, egl_conf, EGL_TRANSPARENT_TYPE, &i);
if (i == EGL_TRANSPARENT_RGB) {
printf("EGL_TRANSPARENT_TYPE = EGL_TRANSPARENT_RGB\n");
i = 0;
eglGetConfigAttrib(egl_disp, egl_conf, EGL_TRANSPARENT_RED_VALUE, &i);
printf("EGL_TRANSPARENT_RED = 0x%02x\n", i);
i = 0;
eglGetConfigAttrib(egl_disp, egl_conf, EGL_TRANSPARENT_GREEN_VALUE, &i);
printf("EGL_TRANSPARENT_GREEN = 0x%02x\n", i);
i = 0;
eglGetConfigAttrib(egl_disp, egl_conf, EGL_TRANSPARENT_BLUE_VALUE, &i);
printf("EGL_TRANSPARENT_BLUE = 0x%02x\n\n", i);
} else {
printf("EGL_TRANSPARENT_TYPE = EGL_NONE\n\n");
}
}
rc = screen_create_context(&screen_ctx, 0);
if (rc) {
perror("screen_context_create");
goto fail3;
}
rc = screen_create_window(&screen_win, screen_ctx);
if (rc) {
perror("screen_create_window");
goto fail4;
}
format = choose_format(egl_disp, egl_conf);
rc = screen_set_window_property_iv(screen_win, SCREEN_PROPERTY_FORMAT, &format);
if (rc) {
perror("screen_set_window_property_iv(SCREEN_PROPERTY_FORMAT)");
goto fail5;
}
rc = screen_set_window_property_iv(screen_win, SCREEN_PROPERTY_USAGE, &usage);
if (rc) {
perror("screen_set_window_property_iv(SCREEN_PROPERTY_USAGE)");
goto fail5;
}
rc = screen_set_window_property_iv(screen_win, SCREEN_PROPERTY_SWAP_INTERVAL, &interval);
if (rc) {
perror("screen_set_window_property_iv(SCREEN_PROPERTY_SWAP_INTERVAL)");
goto fail5;
}
if (size[0] > 0 && size[1] > 0) {
rc = screen_set_window_property_iv(screen_win, SCREEN_PROPERTY_SIZE, size);
if (rc) {
perror("screen_set_window_property_iv(SCREEN_PROPERTY_SIZE)");
goto fail5;
}
} else {
rc = screen_get_window_property_iv(screen_win, SCREEN_PROPERTY_SIZE, size);
if (rc) {
perror("screen_get_window_property_iv(SCREEN_PROPERTY_SIZE)");
goto fail5;
}
}
if (pos[0] != 0 || pos[1] != 0) {
rc = screen_set_window_property_iv(screen_win, SCREEN_PROPERTY_POSITION, pos);
if (rc) {
perror("screen_set_window_property_iv(SCREEN_PROPERTY_POSITION)");
goto fail5;
}
}
rc = screen_create_window_buffers(screen_win, nbuffers);
if (rc) {
perror("screen_create_window_buffers");
goto fail5;
}
rc = screen_create_event(&screen_ev);
if (rc) {
perror("screen_create_event");
goto fail5;
}
/**
** Now that we have created a native platform window we can use it to
** create an EGL on-screen rendering surface. We'll be able to use this
** surface as the target of our OpenGL ES 1.X rendering. We'll use the
** same EGL display and config to create the EGL surface as the ones we
** used to create our native window. The EGL config just needs to be
** compatible with the one used to create the window.
**/
egl_surf = eglCreateWindowSurface(egl_disp, egl_conf,
screen_win, (EGLint*)&egl_surf_attr);
if (egl_surf == EGL_NO_SURFACE) {
egl_perror("eglCreateWindowSurface");
goto fail6;
}
/**
** eglMakeCurrent binds ctx to the current rendering thread and to a draw
** and a read surface. In our case, we want to draw to our EGL surface and
** don't really care about where we read from. EGL does not allow
** specifying EGL_NO_SURFACE for the read surface only, so we will simply
** use egl_surf for both reading and writing. Once eglMakeCurrent
** completes successfully, all OpenGL ES 1.X calls will be executed on
** the context and surface provided as arguments.
**/
rc = eglMakeCurrent(egl_disp, egl_surf, egl_surf, egl_ctx);
if (rc != EGL_TRUE) {
egl_perror("eglMakeCurrent");
goto fail7;
}
/**
** The eglSwapInterval function specifies the minimum number of video
** frame periods per buffer swap for the window associated with the
** current context. If the interval is 0, the application renders as
** fast as it can. Interval values of 1 or more limit the rendering
** to fractions of the display's refresh rate, i.e. 60, 30, 20, 15, etc
** fps in the case of a display with a refresh rate of 60 Hz.
**/
rc = eglSwapInterval(egl_disp, interval);
if (rc != EGL_TRUE) {
egl_perror("eglSwapInterval");
goto fail8;
}
/**
** At this point, we can start doing OpenGL ES stuff. Our application is
** quite simple, so we'll just do the initialization here followed by
** some basic rendering in our application loop.
**/
if (verbose) {
printf("GL_VENDOR = %s\n", (char *)glGetString(GL_VENDOR));
printf("GL_RENDERER = %s\n", (char *)glGetString(GL_RENDERER));
printf("GL_VERSION = %s\n", (char *)glGetString(GL_VERSION));
printf("GL_EXTENSIONS = %s\n", (char *)glGetString(GL_EXTENSIONS));
}
/* The resize function initializes the viewport and geometry */
resize(points, size[0], size[1], barwidth);
/* Set the clear color to yellow */
glClearColor(1.0f, 1.0f, 0.0f, 1.0f);
/* We will use one vertex array for all of our rendering */
glVertexPointer(2, GL_SHORT, 0, (const GLvoid *)points);
glEnableClientState(GL_VERTEX_ARRAY);
/**
** This is our main application loop. It keeps on running unless an error
** occurs or we receive a close event from the windowing system. The
** application loop consists of two parts. The first part processes any
** events that have been put in our queue. The second part does the
** rendering. When the window is visible, we don't wait if the event queue
** is empty and move on to the rendering part immediately. When the window
** is not visible we skip the rendering part.
**/
i = 0;
while (1) {
/**
** We start the loop by processing any events that might be in our
** queue. The only event that is of interest to us are the resize
** and close events. The timeout variable is set to 0 (no wait) or
** forever depending if the window is visible or invisible.
**/
while (!screen_get_event(screen_ctx, screen_ev, vis ? 0 : ~0)) {
rc = screen_get_event_property_iv(screen_ev, SCREEN_PROPERTY_TYPE, &val);
if (rc || val == SCREEN_EVENT_NONE) {
break;
}
switch (val) {
case SCREEN_EVENT_CLOSE:
/**
** All we have to do when we receive the close event is
** exit the application loop. Because we have a loop
** within a loop, a simple break won't work. We'll just
** use a goto to take us out of here.
**/
goto end;
case SCREEN_EVENT_PROPERTY:
/**
** We are interested in visibility changes so we can pause
** or unpause the rendering.
**/
screen_get_event_property_iv(screen_ev, SCREEN_PROPERTY_NAME, &val);
switch (val) {
case SCREEN_PROPERTY_VISIBLE:
/**
** The new visibility status is not included in the
** event, so we must get it ourselves.
**/
screen_get_window_property_iv(screen_win, SCREEN_PROPERTY_VISIBLE, &vis);
break;
}
break;
case SCREEN_EVENT_POINTER:
/**
** To provide a way of gracefully terminating our application,
** we will exit if there is a pointer select event in the upper
** right corner of our window. This should happen if the mouse's
** left button is clicked or if a touch screen display is pressed.
** The event will come as a screen pointer event, with an (x,y)
** coordinate relative to the window's upper left corner and a
** select value. We have to verify ourselves that the coordinates
** of the pointer are in the upper right hand area.
**/
screen_get_event_property_iv(screen_ev, SCREEN_PROPERTY_BUTTONS, &val);
if (val) {
screen_get_event_property_iv(screen_ev, SCREEN_PROPERTY_POSITION, pos);
if (pos[0] >= size[0] - exit_area_size &&
pos[1] < exit_area_size) {
goto end;
}
}
break;
case SCREEN_EVENT_KEYBOARD:
screen_get_event_property_iv(screen_ev, SCREEN_PROPERTY_KEY_FLAGS, &val);
if (val & KEY_DOWN) {
screen_get_event_property_iv(screen_ev, SCREEN_PROPERTY_KEY_SYM, &val);
switch (val) {
case KEYCODE_ESCAPE:
goto end;
case KEYCODE_F:
pause = !pause;
break;
default:
break;
}
}
break;
}
}
/**
** The second part of the application loop is the rendering. We want
** to skip the rendering part if our window is not visible. This will
** leave the CPU and GPU to other applications and make the system a
** little bit more responsive while we are invisible.
**/
if (vis && !pause) {
/* Start by clearing the window */
glClear(GL_COLOR_BUFFER_BIT);
/**
** We could use glLoadIdentity or glPushMatrix here. If we used
** glLoadIdentity, we would have to call glLoadIdentity again when
** we draw the hourglass. We assume that glPushMatrix,
** glTranslatef, glPopMatrix is more efficient than
** glLoadIdentity, glTranslatef, and glLoadIdentity.
**/
glPushMatrix();
/* Use translation to animate the vertical bar */
glTranslatef((GLfloat)(i++ % (size[0] - barwidth)), 0.0f, 0.0f);
/* We want the animated vertical bar to be drawn in blue */
glColor4f(0.0f, 0.0f, 1.0f, 1.0f);
/* Render the vertical bar */
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
/* We don't want the hourglass to be translated */
glPopMatrix();
/* We want the hourglass to be drawn in gray */
glColor4f(0.62745f, 0.62745f, 0.62745f, 1.0f);
/* Render the hourglass */
glDrawArrays(GL_TRIANGLES, 4, 6);
/**
** Posting of the new frame requires a call to eglSwapBuffers.
** For now, this is true even when using single buffering. If an
** event has occured that invalidates the surface we are currently
** using, eglSwapBuffers will return EGL_FALSE and set the error
** code to EGL_BAD_NATIVE_WINDOW. At this point, we could destroy
** our EGL surface, close our OpenKODE window, and start again.
** This application will simply exit when any errors occur.
**/
rc = eglSwapBuffers(egl_disp, egl_surf);
if (rc != EGL_TRUE) {
egl_perror("eglSwapBuffers");
break;
}
}
}
/**
** If we made it here, it means everything ran successfully. We'll thus
** change the exit return value to indicate success.
**/
end:
rval = EXIT_SUCCESS;
/**
** Before we can destroy any of the resources we have created for this
** application, we must deactivate the rendering context that we were
** using and release the surfaces we were drawing to and reading from.
** This is done by calling eglMakeCurrent with EGL_NO_SURFACE and
** EGL_NO_CONTEXT for arguments. Note that the call to eglMakeCurrent
** will generate an error unless all arguments are EGL_NO_SURFACE and
** EGL_NO_CONTEXT, or all arguments are valid EGLSurface and EGLContext
** objects.
**/
fail8:
eglMakeCurrent(egl_disp, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
/**
** Destroy the EGL surface if one was created.
**/
fail7:
eglDestroySurface(egl_disp, egl_surf);
fail6:
screen_destroy_event(screen_ev);
fail5:
screen_destroy_window(screen_win);
fail4:
screen_destroy_context(screen_ctx);
/**
** Destroy the EGL render context if one was created.
**/
fail3:
eglDestroyContext(egl_disp, egl_ctx);
/**
** Terminate our connection to the EGL display. Since we are just about to
** exit, we can also release any resources that were allocated for this
** thread. This is done by calling eglReleaseThread. On most systems,
** those resources would probably be released automatically when the
** program exists.
**/
fail2:
eglTerminate(egl_disp);
eglReleaseThread();
/**
** Return with EXIT_SUCCESS or EXIT_FAILURE.
**/
fail1:
return rval;
}