diff options
author | Chad Versace <chad.versace@linux.intel.com> | 2012-04-03 22:02:55 -0700 |
---|---|---|
committer | Chad Versace <chad.versace@linux.intel.com> | 2012-04-08 12:37:34 -0700 |
commit | 55433959e64cf704574d32d7aec15990391f9b5b (patch) | |
tree | c72393b2c4206b2357d11f67437b91367b1ad8ec /examples | |
parent | 905fa796e5b89424c8b567a21148eb3e5c020709 (diff) |
examples: Add gl_basic
Signed-off-by: Chad Versace <chad.versace@linux.intel.com>
Diffstat (limited to 'examples')
-rw-r--r-- | examples/CMakeLists.txt | 7 | ||||
-rw-r--r-- | examples/README.txt | 2 | ||||
-rw-r--r-- | examples/gl_basic.c | 339 |
3 files changed, 347 insertions, 1 deletions
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 1bb8bf6..3578708 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1 +1,6 @@ -# empty +# ---------------------------------------------------------------------------- +# Target: gl_basic (executable) +# ---------------------------------------------------------------------------- + +add_executable(gl_basic gl_basic.c) +target_link_libraries(gl_basic waffle) diff --git a/examples/README.txt b/examples/README.txt new file mode 100644 index 0000000..195fd2c --- /dev/null +++ b/examples/README.txt @@ -0,0 +1,2 @@ +For a description of each example, see the Doxygen @file comment near the top +of each source file. diff --git a/examples/gl_basic.c b/examples/gl_basic.c new file mode 100644 index 0000000..81a2fa6 --- /dev/null +++ b/examples/gl_basic.c @@ -0,0 +1,339 @@ +// Copyright 2012 Intel Corporation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/// @file gl_basic.c +/// @brief Do some basic GL rendering using Waffle. +/// +/// This example does the following: +/// 1. Dynamically choose the platform and GL API according to command +/// line arguments. +/// 2. Create a window and GL context. +/// 3. Fill the window with red, then green, then blue, sleeping between +/// each buffer swap. + +#define _POSIX_C_SOURCE 199309L // glibc feature macro for nanosleep. + +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include <waffle/waffle.h> + +static const char *usage_message = + "usage:\n" + " gl_basic <platform> <gl_api>\n" + "\n" + "arguments:\n" + " platform: One of android, cocoa, glx, wayland, x11_egl.\n" + " gl_api: One of gl, gles1, gles2.\n" + "\n" + "example:\n" + " gl_basic glx gl\n" + "\n" + "description:\n" + " Create a window. Fill it with red, green, then blue.\n"; + +/// @defgroup Error handlers +/// @{ +/// +/// All error handlers exit. +/// + +static void +error_usage(void) +{ + fprintf(stderr, "usage error\n\n"); + fprintf(stderr, usage_message); + exit(EXIT_FAILURE); +} + + +static void +error_waffle(void) +{ + int32_t code; + char buf[1024]; + const size_t buf_size = 1024; + size_t message_length; + + code = waffle_get_error_m(buf, buf_size, &message_length); + + fflush(stdout); + fprintf(stderr, "waffle: error: %s", waffle_error_to_string(code)); + if (message_length > 0) + fprintf(stderr, ": %s", buf); + fprintf(stderr, "\n"); + + exit(EXIT_FAILURE); +} + +static void +error_get_gl_symbol(const char *name) +{ + fflush(stdout); + fprintf(stderr, + "gl_basic: error: failed to get function pointer for %s\n", name); + exit(EXIT_FAILURE); +} + +/// @} +/// @defgroup GL decalrations +/// @{ + +typedef float GLclampf; +typedef unsigned int GLbitfield; + +enum { + // Copied for <GL/gl.h>. + GL_COLOR_BUFFER_BIT = 0x00004000, +}; + +static void (*glClearColor)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); +static void (*glClear)(GLbitfield mask); + +/// @} +/// @defgroup Parsing Options +/// @{ + +struct options { + int platform; + int gl_api; + const char *display_name; +}; + +struct enum_map { + int i; + const char *s; +}; + +static const struct enum_map platform_map[] = { + {WAFFLE_PLATFORM_ANDROID, "android" }, + {WAFFLE_PLATFORM_COCOA, "cocoa", }, + {WAFFLE_PLATFORM_GLX, "glx" }, + {WAFFLE_PLATFORM_WAYLAND, "wayland" }, + {WAFFLE_PLATFORM_X11_EGL, "x11_egl" }, + {0, 0 }, +}; + +static const struct enum_map gl_api_map[] = { + {WAFFLE_GL, "gl" }, + {WAFFLE_GLES1, "gles1" }, + {WAFFLE_GLES2, "gles2" }, + {0, 0 }, +}; + +/// @brief Translate string to `enum waffle_enum`. +/// +/// @param self is a list of map items. The last item must be zero-filled. +/// @param result is altered only if @a s if found. +/// @return true if @a s was found in @a map. +static bool +enum_map_translate_str( + const struct enum_map *self, + const char *s, + int *result) +{ + const struct enum_map *i; + + for (i = self; i->i != 0; ++i) { + if (!strncmp(s, i->s, strlen(i->s) + 1)) { + *result = i->i; + return true; + } + } + + return false; +} + +/// @return true on success. +static bool +parse_args(int argc, char *argv[], struct options *opts) +{ + const char *arg; + bool ok; + + if (argc != 3) + error_usage(); + + // Set platform. + arg = argv[1]; + ok = enum_map_translate_str(platform_map, arg, &opts->platform); + if (!ok) { + fprintf(stderr, "error: '%s' is not a valid platform", arg); + return false; + } + + // Set gl_api. + arg = argv[2]; + ok = enum_map_translate_str(gl_api_map, arg, &opts->gl_api); + if (!ok) { + fprintf(stderr, "error: '%s' is not a valid GL API", arg); + return false; + } + + // Set display_name. + switch (opts->platform) { + case WAFFLE_PLATFORM_GLX: + case WAFFLE_PLATFORM_X11_EGL: + opts->display_name = getenv("DISPLAY"); + break; + case WAFFLE_PLATFORM_WAYLAND: + opts->display_name = getenv("WAYLAND_DISPLAY"); + break; + default: + opts->display_name = NULL; + break; + } + + return true; +} + +/// @} + +/// Call free() to release result. +static int32_t* +make_waffle_attrib_list(int platform, int gl_api) +{ + int32_t *result = malloc(5 * sizeof(int32_t)); + if (!result) { + fprintf(stderr, "error: out of memory\n"); + return false; + } + + result[0] = WAFFLE_PLATFORM; + result[1] = platform; + result[2] = WAFFLE_GL_API; + result[3] = gl_api; + result[4] = 0; + + return result; +} + +static bool +draw(struct waffle_window *window) +{ + int i; + bool ok; + + static const struct timespec sleep_time = { + // 0.5 sec + .tv_sec = 0, + .tv_nsec = 500000000, + }; + + for (i = 0; i < 3; ++i) { + switch (i) { + case 0: glClearColor(1, 0, 0, 1); break; + case 1: glClearColor(0, 1, 0, 1); break; + case 2: glClearColor(0, 0, 1, 1); break; + case 3: abort(); break; + } + + glClear(GL_COLOR_BUFFER_BIT); + ok = waffle_window_swap_buffers(window); + if (!ok) + return false; + nanosleep(&sleep_time, NULL); + } + + return true; +} + +int +main(int argc, char **argv) +{ + bool ok; + struct options opts; + int32_t *init_attribs; + struct waffle_display *dpy; + const int32_t config_attribs[] = { + WAFFLE_RED_SIZE, 8, + WAFFLE_GREEN_SIZE, 8, + WAFFLE_BLUE_SIZE, 8, + WAFFLE_DOUBLE_BUFFERED, 1, + 0, + }; + struct waffle_config *config; + struct waffle_context *ctx; + struct waffle_window *window; + + ok = parse_args(argc, argv, &opts); + if (!ok) + exit(EXIT_FAILURE); + + init_attribs = make_waffle_attrib_list(opts.platform, opts.gl_api); + if (!init_attribs) + error_waffle(); + + ok = waffle_init(init_attribs); + free(init_attribs); + if (!ok) + error_waffle(); + + glClear = waffle_dlsym_gl("glClear"); + if (!glClear) + error_get_gl_symbol("glClear"); + + glClearColor = waffle_dlsym_gl("glClearColor"); + if (!glClearColor) + error_get_gl_symbol("glClearColor"); + + dpy = waffle_display_connect(opts.display_name); + if (!dpy) + error_waffle(); + + config = waffle_config_choose(dpy, config_attribs); + if (!config) + error_waffle(); + + ctx = waffle_context_create(config, NULL); + if (!ctx) + error_waffle(); + + window = waffle_window_create(config, 320, 240); + if (!window) + error_waffle(); + + ok = waffle_make_current(window, ctx); + if (!ok) + error_waffle(); + + ok = draw(window); + if (!ok) + error_waffle(); + + ok = waffle_window_destroy(window); + if (!ok) + error_waffle(); + + ok = waffle_context_destroy(ctx); + if (!ok) + error_waffle(); + + ok = waffle_config_destroy(config); + if (!ok) + error_waffle(); + + ok = waffle_display_disconnect(dpy); + if (!ok) + error_waffle(); + + ok = waffle_finish(); + if (!ok) + error_waffle(); + + return EXIT_SUCCESS; +} |