2 * Copyright (C) 2003 Robert Kooima
4 * NEVERBALL is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published
6 * by the Free Software Foundation; either version 2 of the License,
7 * or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
24 #include "base_image.h"
30 /*---------------------------------------------------------------------------*/
32 void image_snap(const char *filename)
35 png_structp writep = NULL;
36 png_infop infop = NULL;
37 png_bytep *bytep = NULL;
39 int w = config_get_d(CONFIG_WIDTH);
40 int h = config_get_d(CONFIG_HEIGHT);
43 unsigned char *p = NULL;
45 /* Initialize all PNG export data structures. */
47 if (!(filep = fs_open(filename, "w")))
49 if (!(writep = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0)))
51 if (!(infop = png_create_info_struct(writep)))
54 /* Enable the default PNG error handler. */
56 if (setjmp(png_jmpbuf(writep)) == 0)
58 /* Initialize the PNG header. */
60 png_set_write_fn(writep, filep, fs_png_write, fs_png_flush);
61 png_set_IHDR(writep, infop, w, h, 8,
62 PNG_COLOR_TYPE_RGB_ALPHA,
64 PNG_COMPRESSION_TYPE_DEFAULT,
65 PNG_FILTER_TYPE_DEFAULT);
67 /* Allocate the pixel buffer and copy pixels there. */
69 if ((p = (unsigned char *) malloc(w * h * 4)))
71 glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, p);
73 /* Allocate and initialize the row pointers. */
75 if ((bytep = (png_bytep *) png_malloc(writep, h * sizeof (png_bytep))))
77 for (i = 0; i < h; ++i)
78 bytep[h - i - 1] = (png_bytep) (p + i * w * 4);
80 png_set_rows (writep, infop, bytep);
82 /* Write the PNG image file. */
84 png_write_info(writep, infop);
85 png_write_png (writep, infop, 0, NULL);
93 /* Release all resources. */
95 png_destroy_write_struct(&writep, &infop);
99 /*---------------------------------------------------------------------------*/
102 * Create an OpenGL texture object using the given image buffer.
104 static GLuint make_texture(const void *p, int w, int h, int b)
106 static const GLenum format[] =
107 { 0, GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_RGB, GL_RGBA };
108 static const GLenum type[] =
109 { 0, GL_UNSIGNED_BYTE, GL_UNSIGNED_BYTE,
110 GL_UNSIGNED_SHORT_5_6_5, GL_UNSIGNED_SHORT_4_4_4_4 };
114 /* Scale the image as configured, or to fit the OpenGL limitations. */
116 #ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT
117 int a = config_get_d(CONFIG_ANISO);
119 #ifdef GL_GENERATE_MIPMAP_SGIS
120 int m = config_get_d(CONFIG_MIPMAP);
122 int k = config_get_d(CONFIG_TEXTURES);
126 GLint max = gli.max_texture_size;
130 while (w / k > (int) max || h / k > (int) max)
134 q = image_scale(p, w, h, b, &W, &H, k);
136 /* Generate and configure a new OpenGL texture. */
138 glGenTextures(1, &o);
139 glBindTexture(GL_TEXTURE_2D, o);
141 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
142 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
144 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
145 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
147 #ifdef GL_GENERATE_MIPMAP_SGIS
150 glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
151 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
152 GL_LINEAR_MIPMAP_LINEAR);
155 #ifdef GL_TEXTURE_MAX_ANISOTROPY_EXT
156 if (a) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, a);
159 /* Copy the image to an OpenGL texture. */
161 glTexImage2D(GL_TEXTURE_2D, 0,
163 format[b], type[b], q ? q : p);
171 static void *image_to_16bpp(unsigned char *data, int w, int h, int b)
173 unsigned char *p, *row;
176 if (b <= 2) return data;
178 if ((p = malloc(w * h * 2)))
180 for (i = 0; i < h; i++)
182 row = data + i * w * b;
183 for (j = 0; j < w; j++)
185 unsigned short packed, *pp;
188 (row[j * b] >> 4) << 12 |
189 (row[j * b + 1] >> 4) << 8 |
190 (row[j * b + 2] >> 4) << 4 |
194 (row[j * b] >> 3) << 11 |
195 (row[j * b + 1] >> 2) << 5 |
196 (row[j * b + 2] >> 3);
197 pp = (unsigned short *)&p[i * w * 2 + j * 2];
207 * Load an image from the named file. Return an OpenGL texture object.
209 GLuint make_image_from_file(const char *filename)
217 /* Load the image. */
219 if ((p = image_load(filename, &w, &h, &b)))
221 p = image_to_16bpp(p, w, h, b);
222 o = make_texture(p, w, h, b);
229 /*---------------------------------------------------------------------------*/
232 * Render the given string using the given font. Transfer the image
233 * to a surface of power-of-2 size large enough to fit the string.
234 * Return an OpenGL texture object.
236 GLuint make_image_from_font(int *W, int *H,
238 const char *text, TTF_Font *font)
242 /* Render the text. */
244 if (font && text && strlen(text) > 0)
246 SDL_Color col = { 0xFF, 0xFF, 0xFF, 0xFF };
249 if ((orig = TTF_RenderUTF8_Blended(font, text, col)))
254 int b = orig->format->BitsPerPixel / 8;
266 if ((src = SDL_ConvertSurface(orig, &fmt, orig->flags)) == NULL)
268 fprintf(stderr, _("Failed to convert SDL_ttf surface: %s\n"),
271 /* Pretend everything's just fine. */
276 SDL_FreeSurface(orig);
278 /* Pad the text to power-of-two. */
280 p = image_next2(src->pixels, src->w, src->h, b, &w2, &h2);
287 /* Saturate the color channels. Modulate ONLY in alpha. */
289 image_white(p, w2, h2, b);
291 /* Create the OpenGL texture object. */
293 p = image_to_16bpp(p, w2, h2, b);
294 o = make_texture(p, w2, h2, b);
297 SDL_FreeSurface(src);
313 /*---------------------------------------------------------------------------*/
316 * Load an image from the named file. Return an SDL surface.
318 SDL_Surface *load_surface(const char *filename)
325 SDL_Surface *srf = NULL;
327 if ((p = image_load(filename, &w, &h, &b)))
331 if ((q = image_flip(p, w, h, b, 0, 1)))
332 srf = SDL_CreateRGBSurfaceFrom(q, w, h, b * 8, w * b,
333 RMASK, GMASK, BMASK, AMASK);
339 /*---------------------------------------------------------------------------*/