| /* |
| * Copyright © 2011 Collabora, Ltd. |
| * |
| * Permission to use, copy, modify, distribute, and sell this software and its |
| * documentation for any purpose is hereby granted without fee, provided that |
| * the above copyright notice appear in all copies and that both that copyright |
| * notice and this permission notice appear in supporting documentation, and |
| * that the name of the copyright holders not be used in advertising or |
| * publicity pertaining to distribution of the software without specific, |
| * written prior permission. The copyright holders make no representations |
| * about the suitability of this software for any purpose. It is provided "as |
| * is" without express or implied warranty. |
| * |
| * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, |
| * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO |
| * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR |
| * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, |
| * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER |
| * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE |
| * OF THIS SOFTWARE. |
| */ |
| |
| #include "wscreensaver-glue.h" |
| |
| double frand(double f) |
| { |
| double r = random(); |
| return r * f / (double)RAND_MAX; |
| } |
| |
| void clear_gl_error(void) |
| { |
| while (glGetError() != GL_NO_ERROR) |
| ; |
| } |
| |
| void check_gl_error(const char *msg) |
| { |
| const char *emsg; |
| int err = glGetError(); |
| |
| switch (err) |
| { |
| case GL_NO_ERROR: |
| return; |
| |
| #define ERR(tok) case tok: emsg = #tok; break; |
| ERR(GL_INVALID_ENUM) |
| ERR(GL_INVALID_VALUE) |
| ERR(GL_INVALID_OPERATION) |
| ERR(GL_STACK_OVERFLOW) |
| ERR(GL_STACK_UNDERFLOW) |
| ERR(GL_OUT_OF_MEMORY) |
| #undef ERR |
| |
| default: |
| fprintf(stderr, "%s: %s: unknown GL error 0x%04x\n", |
| progname, msg, err); |
| exit(1); |
| } |
| |
| fprintf(stderr, "%s: %s: GL error %s\n", progname, msg, emsg); |
| exit(1); |
| } |
| |
| static void |
| read_xpm_color(uint32_t *ctable, const char *line) |
| { |
| unsigned char key; |
| char cstr[10]; |
| char *end; |
| uint32_t value; |
| |
| if (sscanf(line, "%1c c %9s", &key, cstr) < 2) { |
| fprintf(stderr, "%s: error in XPM color definition '%s'\n", |
| progname, line); |
| return; |
| } |
| |
| value = strtol(&cstr[1], &end, 16); |
| |
| if (strcmp(cstr, "None") == 0) |
| ctable[key] = 0x00000000; |
| else if (cstr[0] != '#' || !(cstr[1] != '\0' && *end == '\0')) { |
| fprintf(stderr, "%s: error interpreting XPM color '%s'\n", |
| progname, cstr); |
| return; |
| } else { |
| ctable[key] = value | 0xff000000; |
| } |
| } |
| |
| static void |
| read_xpm_row(char *data, const char *line, uint32_t *ctable, int width) |
| { |
| uint32_t *pixel = (uint32_t *)data; |
| uint8_t *p = (uint8_t *)line; |
| int i; |
| |
| for (i = 0; i < width; ++i) |
| pixel[i] = ctable[p[i]]; |
| } |
| |
| XImage *xpm_to_ximage(char **xpm_data) |
| { |
| XImage *xi; |
| int colors; |
| int cpp; |
| int i; |
| uint32_t ctable[256] = { 0 }; |
| |
| xi = malloc(sizeof *xi); |
| if (!xi) |
| return NULL; |
| xi->data = NULL; |
| |
| if (sscanf(xpm_data[0], "%d %d %d %d", &xi->width, |
| &xi->height, &colors, &cpp) < 4) |
| goto errout; |
| |
| if (xi->width < 1 || xi->height < 1 || cpp != 1) |
| goto errout; |
| |
| xi->bytes_per_line = xi->width * sizeof(uint32_t); |
| xi->data = malloc(xi->height * xi->bytes_per_line); |
| if (!xi->data) |
| goto errout; |
| |
| for (i = 0; i < colors; ++i) |
| read_xpm_color(ctable, xpm_data[i + 1]); |
| |
| for (i = 0; i < xi->height; ++i) |
| read_xpm_row(xi->data + i * xi->bytes_per_line, |
| xpm_data[i + colors + 1], ctable, xi->width); |
| |
| return xi; |
| |
| errout: |
| fprintf(stderr, "%s: error processing XPM data.\n", progname); |
| XDestroyImage(xi); |
| return NULL; |
| } |
| |
| void XDestroyImage(XImage *xi) |
| { |
| free(xi->data); |
| free(xi); |
| } |