-/*
+/*
* Copyright (C) 2003 Robert Kooima
*
* NEVERBALL is free software; you can redistribute it and/or modify
#include <SDL.h>
#include <SDL_ttf.h>
-#include <SDL_image.h>
#include <string.h>
#include <math.h>
+#include <png.h>
+#include <stdlib.h>
#include "glext.h"
#include "image.h"
+#include "base_image.h"
#include "config.h"
/*---------------------------------------------------------------------------*/
-void image_snap(char *filename)
+void image_snap(const char *filename)
{
+ 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 = fopen(filename, FMODE_WB)))
+ 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_init_io (writep, filep);
+ 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);
+ fclose(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(config_data(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;
}
* 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_RenderUTF8_Blended(font, text, fg)))
+ SDL_Color col = { 0xFF, 0xFF, 0xFF, 0xFF };
+ SDL_Surface *src;
+
+ if ((src = TTF_RenderUTF8_Blended(font, text, col)))
{
- int w2;
- int h2;
+ void *p;
+ int w2;
+ int h2;
+ int b = src->format->BitsPerPixel / 8;
- image_size(&w2, &h2, src->w, src->h);
+ /* Pad the text to power-of-two. */
+
+ p = image_next2(src->pixels, src->w, src->h, b, &w2, &h2);
if (w) *w = src->w;
if (h) *h = src->h;
+ if (W) *W = w2;
+ if (H) *H = h2;
- /* 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;
+ /* Saturate the color channels. Modulate ONLY in alpha. */
- SDL_SetAlpha(src, 0, 0);
- SDL_BlitSurface(src, NULL, dst, &rect);
+ image_white(p, w2, h2, b);
- image_white(dst);
+ /* Create the OpenGL texture object. */
- o = make_image_from_surf(W, H, dst);
+ o = make_texture(p, w2, h2, b);
- SDL_FreeSurface(dst);
- }
+ 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;
+
+ 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(config_data(filename), &w, &h, &b)))
+ return SDL_CreateRGBSurfaceFrom(p, w, h, b * 8, w * b,
+ rmask, gmask, bmask, amask);
+ else
+ return NULL;
+}
+
+/*---------------------------------------------------------------------------*/