X-Git-Url: http://vcs.maemo.org/git/?a=blobdiff_plain;f=share%2Fimage.c;h=4623547d8321798408f48661e3eb85f9f5383ab8;hb=d9f6f8642b9a4f326c0854efe969195a8d0d2e2a;hp=b5af04d6def776e814cb4a29f9e86ec7f6022b01;hpb=c6d6c9e34bdbdc6e4d9e922130f8a8b0f3a0d20a;p=neverball diff --git a/share/image.c b/share/image.c index b5af04d..4623547 100644 --- a/share/image.c +++ b/share/image.c @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2003 Robert Kooima * * NEVERBALL is free software; you can redistribute it and/or modify @@ -14,248 +14,176 @@ #include #include -#include #include #include +#include +#include #include "glext.h" #include "image.h" +#include "base_image.h" #include "config.h" +#include "fs.h" +#include "fs_png.h" + /*---------------------------------------------------------------------------*/ -void image_snap(char *filename) +void image_snap(const char *filename) { + fs_file filep = NULL; + png_structp writep = NULL; + png_infop infop = NULL; + png_bytep *bytep = NULL; + int w = config_get_d(CONFIG_WIDTH); int h = config_get_d(CONFIG_HEIGHT); int i; - SDL_Surface *buf = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 24, - RMASK, GMASK, BMASK, 0); - SDL_Surface *img = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 24, - RMASK, GMASK, BMASK, 0); - - glReadPixels(0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE, buf->pixels); + unsigned char *p = NULL; - for (i = 0; i < h; i++) - memcpy((GLubyte *) img->pixels + 3 * w * i, - (GLubyte *) buf->pixels + 3 * w * (h - i), 3 * w); + /* Initialize all PNG export data structures. */ - SDL_SaveBMP(img, filename); + if (!(filep = fs_open(filename, "w"))) + return; + if (!(writep = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0))) + return; + if (!(infop = png_create_info_struct(writep))) + return; - SDL_FreeSurface(img); - SDL_FreeSurface(buf); -} - -void image_size(int *W, int *H, int w, int h) -{ - *W = 1; - *H = 1; + /* Enable the default PNG error handler. */ - while (*W < w) *W *= 2; - while (*H < h) *H *= 2; -} - -/*---------------------------------------------------------------------------*/ - -void image_swab(SDL_Surface *src) -{ - int i, j, b = (src->format->BitsPerPixel == 32) ? 4 : 3; - - SDL_LockSurface(src); + if (setjmp(png_jmpbuf(writep)) == 0) { - unsigned char *s = (unsigned char *) src->pixels; - unsigned char t; + /* Initialize the PNG header. */ - /* Iterate over each pixel of the image. */ + png_set_write_fn(writep, filep, fs_png_write, fs_png_flush); + png_set_IHDR(writep, infop, w, h, 8, + PNG_COLOR_TYPE_RGB, + PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT); - for (i = 0; i < src->h; i++) - for (j = 0; j < src->w; j++) - { - int k = (i * src->w + j) * b; + /* Allocate the pixel buffer and copy pixels there. */ - /* Swap the red and blue channels of each. */ + if ((p = (unsigned char *) malloc(w * h * 3))) + { + glReadPixels(0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE, p); - t = s[k + 2]; - s[k + 2] = s[k + 0]; - s[k + 0] = t; - } - } - SDL_UnlockSurface(src); -} + /* Allocate and initialize the row pointers. */ -void image_white(SDL_Surface *src) -{ - int i, j, b = (src->format->BitsPerPixel == 32) ? 4 : 3; - - SDL_LockSurface(src); - { - unsigned char *s = (unsigned char *) src->pixels; + if ((bytep = (png_bytep *) png_malloc(writep, h * sizeof (png_bytep)))) + { + for (i = 0; i < h; ++i) + bytep[h - i - 1] = (png_bytep) (p + i * w * 3); - /* Iterate over each pixel of the image. */ + png_set_rows (writep, infop, bytep); - for (i = 0; i < src->h; i++) - for (j = 0; j < src->w; j++) - { - int k = (i * src->w + j) * b; + /* Write the PNG image file. */ - /* Whiten the RGB channels without touching any Alpha. */ + png_write_info(writep, infop); + png_write_png (writep, infop, 0, NULL); - s[k + 0] = 0xFF; - s[k + 1] = 0xFF; - s[k + 2] = 0xFF; + free(bytep); } + free(p); + } } - SDL_UnlockSurface(src); + + /* Release all resources. */ + + png_destroy_write_struct(&writep, &infop); + fs_close(filep); } -SDL_Surface *image_scale(SDL_Surface *src, int n) +/*---------------------------------------------------------------------------*/ + +/* + * Create an OpenGL texture object using the given image buffer. + */ +static GLuint make_texture(const void *p, int w, int h, int b) { - int si, di; - int sj, dj; - int k, b = (src->format->BitsPerPixel == 32) ? 4 : 3; - - SDL_Surface *dst = SDL_CreateRGBSurface(SDL_SWSURFACE, - src->w / n, - src->h / n, - src->format->BitsPerPixel, - src->format->Rmask, - src->format->Gmask, - src->format->Bmask, - src->format->Amask); - if (dst) - { - SDL_LockSurface(src); - SDL_LockSurface(dst); - { - unsigned char *s = (unsigned char *) src->pixels; - unsigned char *d = (unsigned char *) dst->pixels; + static const GLenum format[] = + { 0, GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_RGB, GL_RGBA }; - /* Iterate each component of each distination pixel. */ + GLuint o = 0; - for (di = 0; di < src->h / n; di++) - for (dj = 0; dj < src->w / n; dj++) - for (k = 0; k < b; k++) - { - int c = 0; + /* Scale the image as configured, or to fit the OpenGL limitations. */ - /* Average the NxN source pixel block for each. */ +#ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT + int a = config_get_d(CONFIG_ANISO); +#endif + int m = config_get_d(CONFIG_MIPMAP); + int k = config_get_d(CONFIG_TEXTURES); + int W = w; + int H = h; - for (si = di * n; si < (di + 1) * n; si++) - for (sj = dj * n; sj < (dj + 1) * n; sj++) - c += s[(si * src->w + sj) * b + k]; + GLint max; - d[(di * dst->w + dj) * b + k] = - (unsigned char) (c / (n * n)); - } - } - SDL_UnlockSurface(dst); - SDL_UnlockSurface(src); - } + void *q = NULL; - return dst; -} + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max); -/*---------------------------------------------------------------------------*/ + while (w / k > (int) max || h / k > (int) max) + k *= 2; -/* - * Create on OpenGL texture object using the given SDL surface and - * format, scaled using the current scale factor. When scaling, - * assume dimensions are used only for layout and lie about the size. - */ -GLuint make_image_from_surf(int *w, int *h, SDL_Surface *s) -{ - int t = config_get_d(CONFIG_TEXTURES); - GLuint o = 0; + if (k > 1) + q = image_scale(p, w, h, b, &W, &H, k); + + /* Generate and configure a new OpenGL texture. */ glGenTextures(1, &o); glBindTexture(GL_TEXTURE_2D, o); - if (t > 1) - { - SDL_Surface *d = image_scale(s, t); - - /* Load the scaled image. */ + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); - if (d->format->BitsPerPixel == 32) - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, d->w, d->h, 0, - GL_RGBA, GL_UNSIGNED_BYTE, d->pixels); - else - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, d->w, d->h, 0, - GL_RGB, GL_UNSIGNED_BYTE, d->pixels); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - SDL_FreeSurface(d); - } - else +#ifdef GL_GENERATE_MIPMAP_SGIS + if (m) { - /* Load the unscaled image. */ - - if (s->format->BitsPerPixel == 32) - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, s->w, s->h, 0, - GL_RGBA, GL_UNSIGNED_BYTE, s->pixels); - else - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, s->w, s->h, 0, - GL_RGB, GL_UNSIGNED_BYTE, s->pixels); + glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, + GL_LINEAR_MIPMAP_LINEAR); } +#endif +#ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT + if (a) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, a); +#endif - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + /* Copy the image to an OpenGL texture. */ - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexImage2D(GL_TEXTURE_2D, 0, + format[b], W, H, 0, + format[b], GL_UNSIGNED_BYTE, q ? q : p); + + if (q) free(q); - if (w) *w = s->w; - if (h) *h = s->h; return o; } -/*---------------------------------------------------------------------------*/ - /* - * Load an image from the named file. If the image is not RGBA, - * convert it to RGBA. Return an OpenGL texture object. + * Load an image from the named file. Return an OpenGL texture object. */ -GLuint make_image_from_file(int *W, int *H, - int *w, int *h, const char *name) +GLuint make_image_from_file(const char *filename) { - SDL_Surface *src; - SDL_Surface *dst; - SDL_Rect rect; - + void *p; + int w; + int h; + int b; GLuint o = 0; - /* Load the file. */ + /* Load the image. */ - if ((src = IMG_Load(config_data(name)))) + if ((p = image_load(filename, &w, &h, &b))) { - int w2; - int h2; - - image_size(&w2, &h2, src->w, src->h); - - if (w) *w = src->w; - if (h) *h = src->h; - - /* Create a new destination surface. */ - - if ((dst = SDL_CreateRGBSurface(SDL_SWSURFACE, w2, h2, 32, - RMASK, GMASK, BMASK, AMASK))) - { - /* Copy source pixels to the center of the destination. */ - - rect.x = (Sint16) (w2 - src->w) / 2; - rect.y = (Sint16) (h2 - src->h) / 2; - - SDL_SetAlpha(src, 0, 0); - SDL_BlitSurface(src, NULL, dst, &rect); - - o = make_image_from_surf(W, H, dst); - - SDL_FreeSurface(dst); - } - SDL_FreeSurface(src); + o = make_texture(p, w, h, b); + free(p); } + return o; } @@ -267,66 +195,122 @@ GLuint make_image_from_file(int *W, int *H, * Return an OpenGL texture object. */ GLuint make_image_from_font(int *W, int *H, - int *w, int *h, const char *text, TTF_Font *font, int k) + int *w, int *h, + const char *text, TTF_Font *font) { - SDL_Color fg = { 0xFF, 0xFF, 0xFF, 0xFF }; - - SDL_Surface *src; - SDL_Surface *dst; - SDL_Rect rect; - GLuint o = 0; /* Render the text. */ if (text && strlen(text) > 0) { - if ((src = TTF_RenderText_Blended(font, text, fg))) + SDL_Color col = { 0xFF, 0xFF, 0xFF, 0xFF }; + SDL_Surface *orig; + + if ((orig = TTF_RenderUTF8_Blended(font, text, col))) { - int w2; - int h2; + void *p; + int w2; + int h2; + int b = orig->format->BitsPerPixel / 8; - image_size(&w2, &h2, src->w, src->h); + SDL_Surface *src; + SDL_PixelFormat fmt; - if (w) *w = src->w; - if (h) *h = src->h; + fmt = *orig->format; + + fmt.Rmask = RMASK; + fmt.Gmask = GMASK; + fmt.Bmask = BMASK; + fmt.Amask = AMASK; - /* Create a new destination surface. */ - - if ((dst = SDL_CreateRGBSurface(SDL_SWSURFACE, w2, h2, 32, - RMASK, GMASK, BMASK, AMASK))) + if ((src = SDL_ConvertSurface(orig, &fmt, orig->flags)) == NULL) { - /* Copy source pixels to the center of the destination. */ + fprintf(stderr, _("Failed to convert SDL_ttf surface: %s\n"), + SDL_GetError()); + + /* Pretend everything's just fine. */ - rect.x = (Sint16) (w2 - src->w) / 2; - rect.y = (Sint16) (h2 - src->h) / 2; + src = orig; + } + else + SDL_FreeSurface(orig); + + /* Pad the text to power-of-two. */ + + p = image_next2(src->pixels, src->w, src->h, b, &w2, &h2); - SDL_SetAlpha(src, 0, 0); - SDL_BlitSurface(src, NULL, dst, &rect); + if (w) *w = src->w; + if (h) *h = src->h; + if (W) *W = w2; + if (H) *H = h2; - image_white(dst); + /* Saturate the color channels. Modulate ONLY in alpha. */ - o = make_image_from_surf(W, H, dst); + image_white(p, w2, h2, b); - SDL_FreeSurface(dst); - } + /* Create the OpenGL texture object. */ + + o = make_texture(p, w2, h2, b); + + free(p); SDL_FreeSurface(src); } - - if (W) *W *= k; - if (H) *H *= k; - if (w) *w *= k; - if (h) *h *= k; } else { - if (W) *W = 0; - if (H) *H = 0; + /* Empty string. */ + if (w) *w = 0; if (h) *h = 0; + if (W) *W = 0; + if (H) *H = 0; } return o; } /*---------------------------------------------------------------------------*/ + +/* + * Load an image from the named file. Return an SDL surface. + */ +SDL_Surface *load_surface(const char *filename) +{ + void *p; + int w; + int h; + int b; + + SDL_Surface *srf = NULL; + + Uint32 rmask; + Uint32 gmask; + Uint32 bmask; + Uint32 amask; + +#if SDL_BYTEORDER == SDL_BIG_ENDIAN + rmask = 0xFF000000; + gmask = 0x00FF0000; + bmask = 0x0000FF00; + amask = 0x000000FF; +#else + rmask = 0x000000FF; + gmask = 0x0000FF00; + bmask = 0x00FF0000; + amask = 0xFF000000; +#endif + + if ((p = image_load(filename, &w, &h, &b))) + { + void *q; + + if ((q = image_flip(p, w, h, b, 0, 1))) + srf = SDL_CreateRGBSurfaceFrom(q, w, h, b * 8, w * b, + rmask, gmask, bmask, amask); + free(p); + } + return srf; +} + +/*---------------------------------------------------------------------------*/