* General Public License for more details.
*/
-#include <SDL.h>
+#include <png.h>
+#include <jpeglib.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "glext.h"
+#include "base_config.h"
+#include "base_image.h"
+
+#include "fs.h"
+#include "fs_png.h"
+#include "fs_jpg.h"
+
+/*---------------------------------------------------------------------------*/
+
+void image_size(int *W, int *H, int w, int h)
+{
+ /* Round the image size up to the next power-of-two. */
+
+ *W = w ? 1 : 0;
+ *H = h ? 1 : 0;
+
+ while (*W < w) *W *= 2;
+ while (*H < h) *H *= 2;
+}
/*---------------------------------------------------------------------------*/
-void image_swab(SDL_Surface *src)
+static void *image_load_png(const char *filename, int *width,
+ int *height,
+ int *bytes)
{
- int i, j, b = (src->format->BitsPerPixel == 32) ? 4 : 3;
+ fs_file fh;
+
+ png_structp readp = NULL;
+ png_infop infop = NULL;
+ png_bytep *bytep = NULL;
+ unsigned char *p = NULL;
+
+ /* Initialize all PNG import data structures. */
+
+ if (!(fh = fs_open(filename, "r")))
+ return NULL;
+
+ if (!(readp = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0)))
+ return NULL;
+
+ if (!(infop = png_create_info_struct(readp)))
+ return NULL;
- SDL_LockSurface(src);
+ /* Enable the default PNG error handler. */
+
+ if (setjmp(png_jmpbuf(readp)) == 0)
{
- unsigned char *s = (unsigned char *) src->pixels;
- unsigned char t;
+ int w, h, b, i;
- /* Iterate over each pixel of the image. */
+ /* Read the PNG header. */
- for (i = 0; i < src->h; i++)
- for (j = 0; j < src->w; j++)
- {
- int k = (i * src->w + j) * b;
+ png_set_read_fn(readp, fh, fs_png_read);
+ png_read_info(readp, infop);
- /* Swap the red and blue channels of each. */
+ png_set_expand(readp);
+ png_set_strip_16(readp);
+ png_set_packing(readp);
- t = s[k + 2];
- s[k + 2] = s[k + 0];
- s[k + 0] = t;
- }
+ png_read_update_info(readp, infop);
+
+ /* Extract and check image properties. */
+
+ w = (int) png_get_image_width (readp, infop);
+ h = (int) png_get_image_height(readp, infop);
+
+ switch (png_get_color_type(readp, infop))
+ {
+ case PNG_COLOR_TYPE_GRAY: b = 1; break;
+ case PNG_COLOR_TYPE_GRAY_ALPHA: b = 2; break;
+ case PNG_COLOR_TYPE_RGB: b = 3; break;
+ case PNG_COLOR_TYPE_RGB_ALPHA: b = 4; break;
+
+ default: longjmp(png_jmpbuf(readp), -1);
+ }
+
+ if (!(bytep = png_malloc(readp, h * png_sizeof(png_bytep))))
+ longjmp(png_jmpbuf(readp), -1);
+
+ /* Allocate the final pixel buffer and read pixels there. */
+
+ if ((p = (unsigned char *) malloc(w * h * b)))
+ {
+ for (i = 0; i < h; i++)
+ bytep[i] = p + w * b * (h - i - 1);
+
+ png_read_image(readp, bytep);
+ png_read_end(readp, NULL);
+
+ if (width) *width = w;
+ if (height) *height = h;
+ if (bytes) *bytes = b;
+ }
+
+ png_free(readp, bytep);
}
- SDL_UnlockSurface(src);
+ else p = NULL;
+
+ /* Free all resources. */
+
+ png_destroy_read_struct(&readp, &infop, NULL);
+ fs_close(fh);
+
+ return p;
}
-void image_white(SDL_Surface *src)
+static void *image_load_jpg(const char *filename, int *width,
+ int *height,
+ int *bytes)
{
- int i, j, b = (src->format->BitsPerPixel == 32) ? 4 : 3;
+ GLubyte *p = NULL;
+ fs_file fp;
- SDL_LockSurface(src);
+ if ((fp = fs_open(filename, "r")))
{
- unsigned char *s = (unsigned char *) src->pixels;
+ struct jpeg_decompress_struct cinfo;
+ struct jpeg_error_mgr jerr;
- /* Iterate over each pixel of the image. */
+ int w, h, b, i = 0;
- for (i = 0; i < src->h; i++)
- for (j = 0; j < src->w; j++)
- {
- int k = (i * src->w + j) * b;
+ /* Initialize the JPG decompressor. */
- /* Whiten the RGB channels without touching any Alpha. */
+ cinfo.err = jpeg_std_error(&jerr);
+ jpeg_create_decompress(&cinfo);
- s[k + 0] = 0xFF;
- s[k + 1] = 0xFF;
- s[k + 2] = 0xFF;
+ /* Set up a VFS source manager. */
+
+ fs_jpg_src(&cinfo, fp);
+
+ /* Grab the JPG header info. */
+
+ jpeg_read_header(&cinfo, TRUE);
+ jpeg_start_decompress(&cinfo);
+
+ w = cinfo.output_width;
+ h = cinfo.output_height;
+ b = cinfo.output_components;
+
+ /* Allocate the final pixel buffer and copy pixels there. */
+
+ if ((p = (GLubyte *) malloc (w * h * b)))
+ {
+ while (cinfo.output_scanline < cinfo.output_height)
+ {
+ GLubyte *buffer = p + w * b * (h - i - 1);
+ i += jpeg_read_scanlines(&cinfo, &buffer, 1);
}
+
+ if (width) *width = w;
+ if (height) *height = h;
+ if (bytes) *bytes = b;
+ }
+
+ jpeg_finish_decompress(&cinfo);
+ jpeg_destroy_decompress(&cinfo);
+
+ fs_close(fp);
}
- SDL_UnlockSurface(src);
+
+ return p;
}
-SDL_Surface *image_scale(SDL_Surface *src, int n)
+void *image_load(const char *filename, int *width,
+ int *height,
+ int *bytes)
{
- 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)
+ const char *ext = filename + strlen(filename) - 4;
+
+ if (strcmp(ext, ".png") == 0 || strcmp(ext, ".PNG") == 0)
+ return image_load_png(filename, width, height, bytes);
+ else if (strcmp(ext, ".jpg") == 0 || strcmp(ext, ".JPG") == 0)
+ return image_load_jpg(filename, width, height, bytes);
+
+ return NULL;
+}
+
+/*---------------------------------------------------------------------------*/
+
+/*
+ * Allocate and return a power-of-two image buffer with the given pixel buffer
+ * centered within in.
+ */
+void *image_next2(const void *p, int w, int h, int b, int *w2, int *h2)
+{
+ unsigned char *src = (unsigned char *) p;
+ unsigned char *dst = NULL;
+
+ int W;
+ int H;
+
+ image_size(&W, &H, w, h);
+
+ if ((dst = (unsigned char *) calloc(W * H * b, sizeof (unsigned char))))
{
- SDL_LockSurface(src);
- SDL_LockSurface(dst);
- {
- unsigned char *s = (unsigned char *) src->pixels;
- unsigned char *d = (unsigned char *) dst->pixels;
+ int r, dr = (H - h) / 2;
+ int c, dc = (W - w) / 2;
+ int i;
- /* Iterate each component of each distination pixel. */
+ for (r = 0; r < h; ++r)
+ for (c = 0; c < w; ++c)
+ for (i = 0; i < b; ++i)
+ {
+ int R = r + dr;
+ int C = c + dc;
- 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;
+ dst[(R * W + C) * b + i] = src[(r * w + c) * b + i];
+ }
- /* Average the NxN source pixel block for each. */
+ if (w2) *w2 = W;
+ if (h2) *h2 = 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];
+ return dst;
+}
- d[(di * dst->w + dj) * b + k] =
- (unsigned char) (c / (n * n));
- }
- }
- SDL_UnlockSurface(dst);
- SDL_UnlockSurface(src);
+/*
+ * Allocate and return a new down-sampled image buffer.
+ */
+void *image_scale(const void *p, int w, int h, int b, int *wn, int *hn, int n)
+{
+ unsigned char *src = (unsigned char *) p;
+ unsigned char *dst = NULL;
+
+ int W = w / n;
+ int H = h / n;
+
+ if ((dst = (unsigned char *) calloc(W * H * b, sizeof (unsigned char))))
+ {
+ int si, di;
+ int sj, dj;
+ int i;
+
+ /* Iterate each component of each destination pixel. */
+
+ for (di = 0; di < H; di++)
+ for (dj = 0; dj < W; dj++)
+ for (i = 0; i < b; i++)
+ {
+ int c = 0;
+
+ /* Average the NxN source pixel block for each. */
+
+ for (si = di * n; si < (di + 1) * n; si++)
+ for (sj = dj * n; sj < (dj + 1) * n; sj++)
+ c += src[(si * w + sj) * b + i];
+
+ dst[(di * W + dj) * b + i] =
+ (unsigned char) (c / (n * n));
+ }
+
+ if (wn) *wn = W;
+ if (hn) *hn = H;
}
return dst;
}
+/*
+ * Whiten the RGB channels of the given image without touching any alpha.
+ */
+void image_white(void *p, int w, int h, int b)
+{
+ unsigned char *s = (unsigned char *) p;
+
+ int r;
+ int c;
+
+ for (r = 0; r < h; r++)
+ for (c = 0; c < w; c++)
+ {
+ int k = (r * w + c) * b;
+
+ s[k + 0] = 0xFF;
+
+ if (b > 2)
+ {
+ s[k + 1] = 0xFF;
+ s[k + 2] = 0xFF;
+ }
+ }
+}
+
+/*
+ * Allocate and return an image buffer of the given image flipped horizontally
+ * and/or vertically.
+ */
+void *image_flip(const void *p, int w, int h, int b, int hflip, int vflip)
+{
+ unsigned char *q;
+
+ assert(hflip || vflip);
+
+ if (!p)
+ return NULL;
+
+ if ((q = malloc(w * b * h)))
+ {
+ int r, c, i;
+
+ for (r = 0; r < h; r++)
+ for (c = 0; c < w; c++)
+ for (i = 0; i < b; i++)
+ {
+ int pr = vflip ? h - r - 1 : r;
+ int pc = hflip ? w - c - 1 : c;
+
+ int qi = r * w * b + c * b + i;
+ int pi = pr * w * b + pc * b + i;
+
+ q[qi] = ((const unsigned char *) p)[pi];
+ }
+ return q;
+ }
+ return NULL;
+}
+
/*---------------------------------------------------------------------------*/